I have this code that spawns a ball and throws it in the direction where the player is looking, later I want to make a system for throwing items from the inventory, but I have a problem with multiplayer because the gameobject can only spawn the server so I use RPC but it causes quite a big delay (like .5 seconds) before the throwing object
Does anyone know of a way to reduce this delay??
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
public class PlayerFunctions : NetworkBehaviour
{
public GameObject itemPrefab;
public float throwForce;
public Transform cameraPos;
public Transform itemSpawnPos;
private KeyCode throwKey = KeyCode.Q;
bool network = false;
public override void OnNetworkSpawn()
{
base.OnNetworkSpawn();
network = true;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(throwKey) && IsOwner)
{
ThrowServerRpc(itemSpawnPos.position, cameraPos.rotation);
}
else if(!network)
{
Throw();
}
}
[ServerRpc]
void ThrowServerRpc(Vector3 position, Quaternion rotation)
{
GameObject objectToThrow = Instantiate(itemPrefab, position, rotation);
var objectToThrowNetworkObject = objectToThrow.GetComponent<NetworkObject>();
objectToThrowNetworkObject.Spawn();
ThrowClientRpc(objectToThrowNetworkObject.NetworkObjectId);
}
[ClientRpc]
void ThrowClientRpc(ulong networkObjectId)
{
NetworkObject networkObject = NetworkManager.Singleton.SpawnManager.SpawnedObjects[networkObjectId];
if(networkObject != null)
{
Rigidbody itemRb = networkObject.GetComponent<Rigidbody>();
itemRb.AddForce(cameraPos.forward * throwForce, ForceMode.Force);
itemRb.AddForce(transform.up * 100, ForceMode.Force);
}
}
void Throw()
{
GameObject objectToThrow = Instantiate(itemPrefab, itemSpawnPos.position, cameraPos.rotation);
Rigidbody itemRb = objectToThrow.GetComponent<Rigidbody>();
itemRb.AddForce(cameraPos.forward * throwForce, ForceMode.Force);
itemRb.AddForce(transform.up * 100, ForceMode.Force);
}
}
In case you haven't already solved this, I see Instantiate being used in your code. That's a slow path. What you want is object pools.
Basically you preinstantiate a pool of instances of a given prefab and you have a Free and Used list, so when you need an instance, you get a reference to an already instantiated object by "reserving" it, you modify it to set it up for your use and it goes from the Free list to the Used list. When you don't need it anymore, instead of Destroy, you clear up any of the modifications (or to phrase it better, you reset the instance to its defaults) and "release" it and it moves back to the Free list. This obviously implies that you need to find a good configuration for the number of instances you preinstantiate since you basically pay the cost of Instantiate upfront. That also means a worst case scenario of how many of this object's instances you expect to have "reserved" at a single frame, to avoid instantiating more when you don't want to incur the cost. Additionally, you don't want to overdo it and make it an overhead, so this is a bit of an iterative process to find that sweet spot count.
You can roll your own easily, but Unity has its own API for it now, ObjectPool, where T is the type you want to pool.
And here's documentation for the Netcode stuff that deals with pooling.