I have this custom spawn function to spawn player prefabs when a new client connects, but as it currently is programmed, it spawns a new prefab for the player but it doesn't transfer ownership from the server to the newly connected client. I'm trying to use the player.GetComponent<NetworkObject>().SpawnWithOwnership(); function to spawn the new player prefab with the ownership set to the client, but to do so i need to pass the clientID as a parameter to the SpawnWithOwnership() function, the only problem is I'm not sure how to get the clientID as the OnNetworkSpawn() function that I'm using to spawn a prefab on client connect doesn't have any parameters such as clientID. I've tried looking through the API documentation for 'Netcode for GameObjects' but cannot find a function that would let me get the clientID i need.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
public class SpawnPlayer : NetworkBehaviour
{
public GameObject playerPrefab;
public float x, y, z;
public override void OnNetworkSpawn(){
if (!playerPrefab) return;
Debug.Log("Called");
Spawn();
}
void Spawn(){
Debug.Log("Called 2");
GameObject player = Instantiate(playerPrefab, new Vector3(x, y, z), Quaternion.identity);
player.GetComponent<NetworkObject>().SpawnWithOwnership();
}
}
Related
Below is the code for movement of player object and it works perfectly fine. But in the TellClientsToMoveClientRpc why are we doing transform.position as it refers to the the current gameobject but not every object moves, only the one which called the above Rpc moves which is desirable. But why all other gameobject do not move ?
using UnityEngine;
namespace HelloWorld
{
public class HelloWorldPlayer : NetworkBehaviour
{
private const float speed = 20f;
private void Update()
{
if (!IsOwner)
return;
PlayerMove();
}
void PlayerMove()
{
Vector3 velocity = new(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical"));
if(velocity.sqrMagnitude >= 1)
{
TellServerToMoveClientServerRpc(velocity, NetworkManager.Singleton.LocalClientId);
}
}
[ServerRpc]
void TellServerToMoveClientServerRpc(Vector3 velocity, ulong clientId)
{
TellClientsToMoveClientRpc(velocity, clientId);
}
[ClientRpc]
void TellClientsToMoveClientRpc(Vector3 velocity, ulong clientId)
{
transform.position += speed * Time.deltaTime * velocity;
}
}
}```
A multiplayer game like this means that there are multiple clients running the same program (the game), meaning that there is a copy of all of the same game objects on each client's instance of the game.
This means that the game object you attached your HelloWorldPlayer script on is present on each client.
When you call TellServerToMoveClientServerRpc from a client, it will execute that function on the same game object the client called the function from, but on the server. This is because you added a [ServerRPC].
Now that the server has control over what's going to happen next, it calls TellClientsToMoveClientRpc. Now this time, since you added a [ClientRpc], that function will be called on the same game object the original client called the function from, but now on every single client that's connected to your server.
Since it's always the same game object calling the function (just on different instances of the game, running on different computers), not all game objects move: only the one that initially called the TellServerToMoveClientServerRpc function.
I'm tryinng to change the camera position by a GameManager script, but having an error like this:
< MissingComponentException: There is no 'Camera' attached to the "Game Manager" game object, but a script is trying to access it.
You probably need to add a Camera to the game object "Game Manager". Or your script needs to check if the component is attached before using it. >
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager: MonoBehaviour
{
public GameObject maincamera;
public void Awake ()
{
maincamera = GameObject.Find("Camera");
maincamera.transform.position = new Vector3(1, 1, 1);
}
}
Can someone explain what i get wrong and how can i fix this?
Currently I am working on a networked 2d platformer game. I have a script that is supposed to instantiate the players jetpack called JetpackManager. However when the player is spawned into the scene the code only spawns a jetpack into the hosts scene and not into the clients' scenes. This results in only the hosts scene working properly while all the players in the clients' scenes have no jetpacks. This is my code for the JetpackManager:
using UnityEngine;
using UnityEngine.Networking;
public class JetpackManager : NetworkBehaviour {
[SerializeField]
private Jetpack[] jetpacks;
[SerializeField]
private Transform jetPackHold;
private PlayerController playerController;
private Jetpack currentJetpack;
void Start(){
playerController = GetComponent<PlayerController> ();
if (isLocalPlayer) {
CmdEquipJetpack (0);
}
}
[Command]
void CmdEquipJetpack(int jetpackNumber){
RpcEquipJetpack (jetpackNumber);
}
[ClientRpc]
void RpcEquipJetpack(int jetpackNumber){
if (currentJetpack != null) {
Destroy (currentJetpack.gameObject);
}
currentJetpack = Instantiate (jetpacks[jetpackNumber], jetPackHold.position, jetPackHold.rotation);
currentJetpack.transform.SetParent (jetPackHold);
playerController.InitialiseJetpackVariables (currentJetpack);
}
}
So essentially my problem is that the code within the RpcEquipJetpack Function is for some reason only being called on the host and not on any of the clients.
You should instantiate Network object with network class
Network.Instantiate
Network instantiate a prefab.
The given prefab will be instanted on all clients in the game.
Synchronization is automatically set up so there is no extra work
involved. The position, rotation and network group number are given as
parameters. Note that in the example below there must be something set
to the playerPrefab in the Editor. You can read more about
instantiations in the object reference Object.Instantiate.
camera transform
I am trying to move my camera based on the players' movements on Y axis in Unity.
However, it does not work...
What did I do wrong? I have attached image of my script (C#) here.
and, Yes, I did attach this script with Main Camera.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CameraController : MonoBehaviour {
GameObject player;
// Use this for initialization
void Start () {
this.player = GameObject.Find("cat");
}
// Update is called once per frame
void Update () {
Vector3 playerPos = this.player.transform.position;
transform.position = new Vector3(
transform.position.x, playerPos.y, transform.position.z);
}
}
Make the player GameObject public and just drag and drop your player in the inspector in unity see if that works? Are you getting any exceptions? Also add Debug.Log (player.transform.position.ToString ()) to see if it is showing the right values. Are you sure you player object name is cat and not Cat, it is case sensitive. Check on those things and let me know if you figured it out!
In short, I have a very simple multiplayer game. It's the Roll A Ball game (Unity3D tutorial). So right now I have the players etc spawning perfectly and everyone is able to control their own balls perfectly fine.
But here's the problem: I've got a default Main Camera. Since it's only the local player itself that needs to see it, I figured there's no point in trying to spawn a seperate camera for each player on the server.
However, to make the camera follow the player, I need to attach it the player gameobject. Obviously I can't attach it to the player prefab as it's a clone the camera needs to follow. But since the player is being spawned by the Network Manager component, I have no idea on how to refer to this clone.
What I've tried myself:
public class CameraController : NetworkManager
{
public GameObject playerPrefab;
public Transform target;
private Vector3 offset;
public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
GameObject player = (GameObject)Instantiate(playerPrefab, new Vector3(0, 0.5f, 0), Quaternion.identity);
target = player.transform;
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}
void Start()
{
offset = transform.position - target.position;
}
void LateUpdate()
{
transform.position = transform.position + offset;
}
}
But this resulted in:
Which I find extremely odd since as you can clearly see, there's no NetworkIdentity component on the NetworkManager object. I've been trying A LOT of things for the past 4 hours now and I just can't do it. So now I'm hoping you guys can help me out.
Edit: This is how the Network Manager normally spawns a player. As you can see, there's no code for it:
I had the same issue and figured out the followig solution. Seems like you already got a solution, but maybe it is interesting to share some possible ways for other people in the same situation.
This is a way to do it without a camera attached to the prefabs.
I'm using a NetworkManager to instantiate Player-prefabs. (Same as you)
I solved the problem of finding references to the clone objects by letting the clones tell the camera, who they are (or which transform belongs to them).
The Player has the following script:
using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
public class PlayerController : NetworkBehaviour {
public override void OnStartLocalPlayer()
{
GetComponent<MeshRenderer>().material.color = Color.blue;
Camera.main.GetComponent<CameraFollow>().target=transform; //Fix camera on "me"
}
void Update ()
{
if (!isLocalPlayer)
{
return;
}
var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
var z = Input.GetAxis ("Vertical") * Time.deltaTime * 3.0f;
transform.Rotate (0, x, 0);
transform.Translate (0,0,z);
}
}
On my default main Camera (there is no camera attached to the player prefab, just the default camera) I put the following script on. It takes a target which I initialised with the prefab using the inspector.
using UnityEngine;
using System.Collections;
public class CameraFollow : MonoBehaviour {
public Transform target; //what to follow
public float smoothing = 5f; //camera speed
Vector3 offset;
void Start()
{
offset = transform.position - target.position;
}
void FixedUpdate()
{
Vector3 targetCamPos = target.position + offset;
transform.position = Vector3.Lerp (transform.position, targetCamPos,smoothing * Time.deltaTime);
}
}
After starting the game, each clone tells the camera who he is, so the target changes to the individual clients clone with this line from the Player's Script:
Camera.main.GetComponent<CameraFollow>().target=transform; //Fix camera on "me"
This way you don't need to create one camera per instance of player-prefabs (I'm not sure if this makes big differences in performance) and you don't have to deactivate all cameras which don't belong to your client.
If you host the game in the editor you can see that there is just 1 camera instead of one camera per connected client (like when you attach it to the prefab).
I think this is a good use of this method, you can use it to put things in it, which should be applied to the Local Player only.
public override void OnStartLocalPlayer()
{
}
I tried by starting the game in the editor and in a build and it seems to work well.
I would add a camera to the prefab and then write a player script like this:
using UnityEngine.Networking;
public class Player : NetworkBehaviour
{
public Camera camera;
void Awake()
{
if(!isLocalPlayer)
{
camera.enabled = false;
}
}
}
I've not really worked with networking but what if you do this after you spawn the local player
Camera.main.transfor.SetParent(the transform of the local player here);
As I understand the problem each separate instance of the game has a main camera.
Thanks to Rafiwui's point into the right direction, I've finally managed to get it working. All I had to do was adept his code a bit. The end result was:
public Camera camera;
void Awake()
{
camera.enabled = false;
}
public override void OnStartLocalPlayer()
{
camera.enabled = true;
}
Thanks A LOT to you all for helping me out! This has been quite a day for me.