My client won’t move despite having a ClientNetworkTransform attached to it.
And I can’t move my camera at all from client.
Though all animations like firing, moving, aiming, etc work fine on both host and client.
I am using the package Low Poly Shooter Pack - Free Sample | Systems | Unity Asset Store and I am trying to make a multiplayer shooter game using the fps package above that I modified a little bit and NGO.
We can’t advise without seeing any code and/or prefab setup. 
@CodeSmile Sorry I forgot to attach any related items.
that’s the player movement script from the pack that I modified to fit my needs
// Copyright 2021, Infima Games. All Rights Reserved.
using System.Linq;
using UnityEngine;
using UnityEngine.InputSystem;
namespace InfimaGames.LowPolyShooterPack
{
[RequireComponent(typeof(Rigidbody), typeof(CapsuleCollider))]
public class Movement : MovementBehaviour
{
#region FIELDS SERIALIZED
[Header("Audio Clips")]
[Tooltip("The audio clip that is played while walking.")]
[SerializeField]
private AudioClip audioClipWalking;
[Tooltip("The audio clip that is played while running.")]
[SerializeField]
private AudioClip audioClipRunning;
[Header("Speeds")]
[SerializeField]
private float speedWalking = 5.0f;
float speedRunningOriginal;
[Tooltip("How fast the player moves while running."), SerializeField]
private float speedRunning = 9.0f;
[SerializeField] float speedSprinting = 12f;
[SerializeField] float slideForce;
[SerializeField] PlayerInput input;
[SerializeField] GameObject cam;
[SerializeField] GameObject minimapCam;
[SerializeField] GameObject depthCam;
#endregion
#region PROPERTIES
//Velocity.
private Vector3 Velocity
{
//Getter.
get => rigidBody.velocity;
//Setter.
set => rigidBody.velocity = value;
}
#endregion
#region FIELDS
/// <summary>
/// Attached Rigidbody.
/// </summary>
private Rigidbody rigidBody;
/// <summary>
/// Attached CapsuleCollider.
/// </summary>
private CapsuleCollider capsule;
/// <summary>
/// Attached AudioSource.
/// </summary>
private AudioSource audioSource;
/// <summary>
/// True if the character is currently grounded.
/// </summary>
private bool grounded;
/// <summary>
/// Player Character.
/// </summary>
private CharacterBehaviour playerCharacter;
/// <summary>
/// The player character's equipped weapon.
/// </summary>
private WeaponBehaviour equippedWeapon;
/// <summary>
/// Array of RaycastHits used for ground checking.
/// </summary>
private readonly RaycastHit[] groundHits = new RaycastHit[8];
#endregion
#region UNITY FUNCTIONS
public override void OnNetworkSpawn() {
base.OnNetworkSpawn();
if(!IsOwner) {
cam.SetActive(false);
minimapCam.SetActive(false);
depthCam.SetActive(false);
enabled = false;
}
else {
input.enabled = true;
playerCharacter = ServiceLocator.Current.Get<IGameModeService>().GetPlayerCharacter();
}
}
/// <summary>
/// Awake.
/// </summary>
protected override void Awake()
{
//Get Player Character.
}
/// Initializes the FpsController on start.
protected override void Start() {//Rigidbody Setup.
SetupFPSController();
}
void SetupFPSController() {
rigidBody = GetComponent<Rigidbody>();
rigidBody.constraints = RigidbodyConstraints.FreezeRotation;
//Cache the CapsuleCollider.
capsule = GetComponent<CapsuleCollider>();
//Audio Source Setup.
audioSource = GetComponent<AudioSource>();
audioSource.clip = audioClipWalking;
audioSource.loop = true;
speedRunningOriginal = speedRunning;
}
/// Checks if the character is on the ground.
private void OnCollisionStay()
{
if(capsule == null) {
SetupFPSController();
return;
}
//Bounds.
Bounds bounds = capsule.bounds;
//Extents.
Vector3 extents = bounds.extents;
//Radius.
float radius = extents.x - 0.01f;
//Cast. This checks whether there is indeed ground, or not.
Physics.SphereCastNonAlloc(bounds.center, radius, Vector3.down,
groundHits, extents.y - radius * 0.5f, ~0, QueryTriggerInteraction.Ignore);
//We can ignore the rest if we don't have any proper hits.
if (!groundHits.Any(hit => hit.collider != null && hit.collider != capsule))
return;
//Store RaycastHits.
for (var i = 0; i < groundHits.Length; i++)
groundHits[i] = new RaycastHit();
//Set grounded. Now we know for sure that we're grounded.
grounded = true;
}
protected override void FixedUpdate()
{
//Move.
MoveCharacter();
//Unground.
grounded = false;
}
/// Moves the camera to the character, processes jumping and plays sounds every frame.
protected override void Update()
{
//Get the equipped weapon!
equippedWeapon = playerCharacter.GetInventory().GetEquipped();
//Play Sounds!
PlayFootstepSounds();
if (Input.GetKeyDown(KeyCode.Space)) {
Jump();
}
if (Input.GetKeyDown(KeyCode.Z)) {
Slide();
}
if (speedRunning > speedRunningOriginal) {
speedRunning -= Time.deltaTime * slideForce * slideForce * (slideForce / 1.2f);
transform.GetChild(0).GetComponent<Animator>().SetBool("Running", false);
}
else {
sliding = false;
}
if (speedRunning < speedRunningOriginal) {
speedRunning = speedRunningOriginal;
}
}
#endregion
#region METHODS
private void MoveCharacter()
{
#region Calculate Movement Velocity
//Get Movement Input!
Vector2 frameInput = playerCharacter.GetInputMovement();
//Calculate local-space direction by using the player's input.
var movement = new Vector3(frameInput.x, 0.0f, frameInput.y);
//Running speed calculation.
if(playerCharacter.IsRunning())
movement *= speedRunning;
else if (playerCharacter.IsSprinting()) {
movement *= speedSprinting;
}
else
{
//Multiply by the normal walking speed.
movement *= speedWalking;
}
//World space velocity calculation. This allows us to add it to the rigidbody's velocity properly.
movement = transform.TransformDirection(movement);
#endregion
//Update Velocity.
Velocity = new Vector3(movement.x, Velocity.y, movement.z);
}
/// <summary>
/// Plays Footstep Sounds. This code is slightly old, so may not be great, but it functions alright-y!
/// </summary>
private void PlayFootstepSounds()
{
//Check if we're moving on the ground. We don't need footsteps in the air.
if (grounded && rigidBody.velocity.sqrMagnitude > 0.1f)
{
//Select the correct audio clip to play.
audioSource.clip = playerCharacter.IsRunning() ? audioClipRunning : audioClipWalking;
//Play it!
if (!audioSource.isPlaying)
audioSource.Play();
}
//Pause it if we're doing something like flying, or not moving!
else if (audioSource.isPlaying)
audioSource.Pause();
}
bool sliding = false;
void Slide() {
if (sliding) return;
speedRunning *= slideForce;
transform.GetChild(0).GetComponent<Animator>().SetBool("Running", false);
transform.GetChild(0).GetComponent<Animator>().SetBool("Sprinting", false);
sliding = true;
}
[SerializeField] float jumpForce;
void Jump() {
if (!grounded) return;
rigidBody.AddForce(transform.up * jumpForce);
}
#endregion
}
}
@CodeSmile
these are the components on my network player
I enable the Player Input class when the player spawns and if is the owner as you can see in above code in line 108
this is the prefab

and i have the animator and some other scripts here

I suppose the camera is somewhere inside the player prefab? If not then that might be a problem.
Client is updating the Velocity value when it tries to move? Debug.Log or, well, debug (attach debugger, set breakpoint, step through code, see all values as the code runs, mind-blowing revelation if you haven’t done that before).
Since this code relies on a Rigidbody, you may need to add the NetworkRigidbody component too.
@CodeSmile Yes, the camera is inside the player prefab
And I also have the NetworkRigidbody
Though I will try to debug the code and find any issues in there!
@CodeSmile I did some debugging and found out that on the client side, the velocity is logged as 0 on all axes
On host side, the velocity log is as usual
Ok, I figured it out!
Actually, on the client side, the player character on the Movement script was set to the host.
As the host wasn’t moving when I tested the client, the movement input was zero.
Now I fixed it and everything works fine!
Thanks!
1 Like