Search Unity

Set Camera to follow local player

Discussion in 'Netcode for GameObjects' started by MelonMan96, Feb 28, 2023.

  1. MelonMan96

    MelonMan96

    Joined:
    May 4, 2014
    Posts:
    10
    Hi! This was propably asked before but I have been searching youtube and forums for over an hour now and I cant seem to find a solution for my problem, hope someone can help me here :)
    Currently im spawning players using the network manager. They move around, everyone controls their own local player, all is nicely working.

    Now I want to have each player have their own camera that follows them around. For that I created a cinemashine camera and wrote a little code that sets the local player as the follow target (or atleast it should do that) The code works fine, but just for the host! The clients cameras just stay static while the host walks around and the camera follows just fine. (as seen on the screenshot, the clients camera code is not finding a player) What am I missing?



    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Cinemachine;
    5. using Unity.Netcode;
    6.  
    7. public class AssignCamera : NetworkBehaviour
    8. {
    9.     public Transform Player;
    10.     public GameObject Camera;
    11.  
    12.     // Start is called before the first frame update
    13.     void Start()
    14.     {
    15.         //Player = GameObject.FindGameObjectWithTag("Player").transform;
    16.         Player = NetworkManager.LocalClient.PlayerObject.transform;
    17.     }
    18.  
    19.     // Update is called once per frame
    20.     void Update()
    21.     {
    22.         if(Player != null)
    23.         {
    24.             Assign();
    25.         }
    26.     }
    27.  
    28.     void Assign()
    29.     {
    30.         var vcam = Camera.GetComponent<CinemachineVirtualCamera>();
    31.         vcam.LookAt = Player;
    32.         vcam.Follow = Player;
    33.     }
    34. }
     

    Attached Files:

  2. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,989
    Code (CSharp):
    1. void Start()
    2.     {
    3.         //Player = GameObject.FindGameObjectWithTag("Player").transform;
    4.         Player = NetworkManager.LocalClient.PlayerObject.transform;
    5.     }
    Try to move this to OnNetworkSpawn. In Start() there will not be a player object spawned yet.
     
    RikuTheFuffs-U and RikuTheFuffs like this.
  3. MelonMan96

    MelonMan96

    Joined:
    May 4, 2014
    Posts:
    10
    Thanks for the reply! Sadly this broke everything.. Now one player is completly unable to move for some reason and the camera is still doing nothing. You mentioned in void Start there will not be a object spawned, still the code works for the host? How is that possible? (sorry im very very new to networking and I cant figure out what im doing wrong)
     
  4. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,989
    It may work for the host because the host is not affected by networking roundtrip time since everything the host does happens instantly on the local machine, like in singleplayer. Whereas for the clients to receive that spawn message and execute it, a network packet has to be sent across the network which takes tens or hundreds of milliseconds to arrive on the client side.

    It is best to assume that in Start(), Awake() and OnEnable() the NetworkManager methods are off-limits and anything that uses NetworkManager should rather be in OnNetworkSpawn. There may be exceptions of course, such as StartHost/Client obviously but maybe some other methods.
     
  5. MelonMan96

    MelonMan96

    Joined:
    May 4, 2014
    Posts:
    10
    Oh I see! Thats explains alot. Still, Do you know a way to reference the local player? This would be very useful not only for cameras but for lot of gameplay related things as well! I found out that you can use "NetworkManager.Singleton.ConnectedClients[clientId].PlayerObject;" so I thought I just write a code which stores the local player as a gameobject and throw it into the scene but I just cant get it to work. This is all very frustrating Im really not made for networking...
     
  6. CodeSmile

    CodeSmile

    Joined:
    Apr 10, 2014
    Posts:
    5,989
    Maybe just start following the Netcode manual and demo projects? That way you pick up many best practices.

    Networking requires a shift in mindset. Mainly: the server/host is the one running the game, and anything the server isn't instructed to do (or does by itself) doesn't happen to clients either. And any such thing takes time for a client to execute due to network latency.

    You cannot just "throw a gameobject into the scene" for a local player. The server (host) tells the client to spawn a gameobject as its PlayerObject and until that happens, you have no such object. The client simply is not allowed to spawn networked objects. Any object you do spawn manually on the client is not synchronized over the network, and if that object happens to have a network script attached it will most likely raise errors when spawned manually on the client.
     
  7. MelonMan96

    MelonMan96

    Joined:
    May 4, 2014
    Posts:
    10
    Thanks alot for the replies and your right I should work myself through a demo project BUT I managed to solve my issue in the simplest way possible (and it only took a few hours to figure out)
    So for anyone stumbling across this in the future facing the same problem:
    Instead of having a cinemashine virtual camera in my scene and assigning it to the local player, I added a cinemashine virtual camera to the spawned player prefab and then I added a simple code which disables the camera for all players that are not you.
    Code (CSharp):
    1.         if(!IsOwner)
    2.         {
    3.             Cam.SetActive(false); //The cam itself
    4.             CamController.SetActive(false); //the cinemashine virtual camera
    5.         }
    This is propably not the best way to do this but for me it works for now and I have not encountered any issues with this solution so far :)
     
  8. diogodubiella

    diogodubiella

    Joined:
    Aug 1, 2018
    Posts:
    1
    Here is my code:


    Code (CSharp):
    1. using UnityEngine;
    2. using Unity.Netcode;
    3.  
    4.  
    5. public class CameraMotion : NetworkBehaviour {
    6.  
    7.     public Transform Player;
    8.     public GameObject Camera;
    9.  
    10.     public float followDelay = 0.5f;
    11.     // public Transform _target;
    12.     private Vector3 velocity = Vector3.zero;
    13.  
    14.     private void Start() {
    15.         transform.position = Player.position;
    16.     }
    17.  
    18.     private void Move() {
    19.         Player = NetworkManager.LocalClient.PlayerObject.transform;
    20.         transform.position = Vector3.SmoothDamp(transform.position, Player.position, ref velocity, followDelay);
    21.     }
    22.  
    23.     private void Update() {
    24.         Move();
    25.     }
    26.  
    27.     private void OnDrawGizmos() {
    28.         Gizmos.color = Color.red;
    29.         Gizmos.DrawSphere(transform.position, 1f);
    30.     }
    31. }
    32.