Search code examples
c#unity-game-engineunity-networking

Attaching camera to rolling ball in multiplayer game


I'm working on a multiplayer game and it's kind of a mess, but I want to tackle each problem separately. For now, I want to attach the camera to the player. Problem is, the player rolls around, constantly changing its position and rotation. Additionally, since it's a multiplayer game, the player is a prefab, so I need to set the camera's parent to the player when it spawns in. So here are my problems:

  1. The camera needs to detect when the player spawns in (it doesn't spawn in when the game boots, but when a button is pressed), and set itself as its child.
  2. The camera should follow the player without rolling with it. Additionally, I should mention that the camera is rotatable using left-right keys (at least for now), and I want the player's movement to be relative to the camera, which is something I've done in a singleplayer tutorial project before, but if you have an efficient way of doing this, please tell me.

Here are the scripts for the player and camera respectively:

using System.Collections;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;

public class Player : NetworkBehaviour
{
    private Rigidbody playerRb;
    public float speed;

    void Start()
    {
        playerRb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        if (!IsOwner)
        {
            return;
        }

        float forwInput = Input.GetAxis("Vertical");
        float horzInput = Input.GetAxis("Horizontal");
        Vector3 direction = Vector3.forward * forwInput + Vector3.right * horzInput;
        if (direction.magnitude > 1) { direction.Normalize(); }

        MoveServerRpc(direction);
    }

    [ServerRpc]
    void MoveServerRpc(Vector3 direction)
    {
        playerRb.AddForce(direction * speed);
    }

}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RotateCamera : MonoBehaviour
{

    public float rotationSpeed;
  
    void Update()
    {
        float camInput = Input.GetAxis("MoveCam");
        transform.Rotate(Vector3.up, camInput * Time.deltaTime * rotationSpeed);
    }
}

I know this is a pretty basic thing, but I've searched for countless solutions and they were either too complex for me to understand and seemingly unnecessary (like the event system), or they simply didn't work (like the message system, because the camera wasn't receiving the message, even though the player sent it succesfully, since I debug logged it). I deleted any faulty code so I don't mess up my entire script, so there's no progress in this direction in the scripts I provided.


Solution

  • first take a look at cinemachine package for camera. its free and easy to use.

    BUT

    my usual advice is to never set the camera as the child of your player. do this instead and it will have the best outcome. add an object as the child of your player and position it based on how you want your camera positions. then in your camera script tell the camera to always follow that object but look at the player. if you dont have a super specific camera system, then just use "cinemachine". it is amazing for 90 percent of situations.

    using UnityEngine;
    
    public class CameraFollowAndLook : MonoBehaviour
    { 
    public Transform followTarget;   // The target object to follow
    public Transform lookTarget;     // The target object to look at
    public Vector3 offset;           // Offset from the follow target
    public float speed = 5.0f;       // Speed of following
    
    void Update()
    {
        // Check if follow target and look target are assigned
        if (followTarget != null && lookTarget != null)
        {
            // Calculate desired position for the camera
            Vector3 desiredPosition = followTarget.position + offset;
    
            // Smoothly move the camera towards the desired position
            transform.position = Vector3.Lerp(transform.position, desiredPosition, speed * Time.deltaTime);
    
            // Make the camera look at the look target
            transform.LookAt(lookTarget);
        }
      }
    }
    

    just be careful. if you move the camera and the player in the same loop, it can lead to jitter. i usualy recommend you to move the player in fixedUpdate and move camera in update. but if you have to move the player in the update, then move camera in late update. this matter should be handled in cinemachine too. in there you can choose which loop to use for camera movement.