1

I've got a player controller that should work over UNET. I must not understand something though as any remote players joining a game can't control their character.

The hosting local player can control his/her character just fine.

Basically the way I think this is working is that in Update the local player can press keys. Those keypresses issue Commands to the server where synced bools are set.

In FixedUpdate the server moves the Rigidbody around based on the set bools. On the player object I have a NetworkTransform so any movement the server does should be sent back to the client.

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

[RequireComponent(typeof(NetworkIdentity))]
public class PlayerController : NetworkBehaviour {
    public GameObject NormalBullet;

    public Vector3 size = new Vector3(0.25f, 0.25f, 0.25f);
    private float speed = 8;
    private float angularSpeed = 35;
    private float jumpForce = 10;

    private Rigidbody _rigidbody;
    private Map _map;
    private NHNetworkedPool _pool;

    private bool _active = false;
    private Vector3 _lastPosition;

    [SyncVar]
    private bool _moveForward;
    [SyncVar]
    private bool _moveBackward;
    [SyncVar]
    private bool _turnLeft;
    [SyncVar]
    private bool _turnRight;
    [SyncVar]
    private bool _jump;
    [SyncVar]
    private bool _isgrounded;
    [SyncVar]
    private bool _isFireing;

    void Awake () {
        Messenger.AddListener ("MAP_LOADED", OnMapLoaded);

        _rigidbody = gameObject.GetComponent<Rigidbody> ();
        _map = GameObject.Find ("Map").GetComponent<Map> ();

        Physics.IgnoreLayerCollision(LayerMask.NameToLayer("Players"), LayerMask.NameToLayer("Players"), true);
    }

    override public void OnStartClient () {
        _rigidbody.position = new Vector3 (-100, -100, -100);

        if (NetworkServer.active) {
            _pool = FindObjectOfType<NHNetworkedPool> ();
        }
    }

    /// <summary>
    /// Once the board is built, hookup the camera if this is the local player
    /// and set the player as active.
    /// </summary>
    void OnMapLoaded () {
        if (isLocalPlayer) {
            // Hook up the camera
            PlayerCamera cam = Camera.main.GetComponent<PlayerCamera>();
            cam.target = transform;

            // Move the player to the it's spawn location
            CmdSpawn();
        }

        // Set the player as active
        _active = true;
    }

    /// <summary>
    /// Only and active local player should be able to
    /// issue commands for the player
    /// </summary>
    void Update () {
        if (!isLocalPlayer || !_active) {
            return;
        }

        if (Input.GetKeyDown ("up")) {
            CmdSetMoveForward (true);
        }
        if (Input.GetKeyUp ("up")) {
            CmdSetMoveForward (false);
        }
        if (Input.GetKeyDown ("down")) {
            CmdSetMoveBackward (true);
        }
        if (Input.GetKeyUp ("down")) {
            CmdSetMoveBackward (false);
        }
        if (Input.GetKeyDown ("left")) {
            CmdSetTurnLeft (true);
        }
        if (Input.GetKeyUp ("left")) {
            CmdSetTurnLeft (false);
        }
        if (Input.GetKeyDown ("right")) {
            CmdSetTurnRight (true);
        }
        if (Input.GetKeyUp ("right")) {
            CmdSetTurnRight (false);
        }
        if (Input.GetKeyDown (KeyCode.Space)) {
            CmdSetJump (true);
        }
        if (Input.GetKeyUp (KeyCode.Space)) {
            CmdSetJump (false);
        }
        if (Input.GetKeyDown (KeyCode.LeftShift)) {
            CmdSetShooting(true);
        }
        if (Input.GetKeyUp (KeyCode.LeftShift)) {
            CmdSetShooting(false);
        }
    }

    /// <summary>
    /// Only the server should update the player's location
    /// the transform is synced to the clients
    /// </summary>
    void FixedUpdate () {
        if (!isServer) {
            return;
        }

        if (_moveForward) {
            float moveAmount = speed * Time.deltaTime;
            _rigidbody.MovePosition(_rigidbody.position + _rigidbody.transform.forward * moveAmount);
        }

        if (_moveBackward) {
            float moveAmount = (-speed * 0.6f) * Time.deltaTime;
            _rigidbody.MovePosition(_rigidbody.position + _rigidbody.transform.forward * moveAmount);
        }

        if (_turnLeft) {
            Quaternion rotateAmount = Quaternion.Euler(new Vector3(0f, -angularSpeed, 0f) * Time.deltaTime);
            _rigidbody.MoveRotation(_rigidbody.rotation * rotateAmount);
        }

        if (_turnRight) {
            Quaternion rotateAmount = Quaternion.Euler(new Vector3(0f, angularSpeed, 0f) * Time.deltaTime);
            _rigidbody.MoveRotation(_rigidbody.rotation * rotateAmount);
        }

        if (_jump && _isgrounded) {
            _rigidbody.AddForce(Vector3.up * 250);
        }
    }

    void OnCollisionStay (Collision collision) {
        if(collision.gameObject.tag.ToUpper() == "GROUND") {
            _isgrounded = true;
        }
    }

    void OnCollisionExit (Collision collision) {
        if(collision.gameObject.tag.ToUpper() == "GROUND") {
            _isgrounded = false;
        }
    }

    /// <summary>
    /// Client -> Server
    /// Move the player to a spawn location
    /// </summary>
    void CmdSpawn() {
        _rigidbody.position = _map.GetPlayerSpawn();
        _rigidbody.velocity = Vector3.zero;
    }

    /// <summary>
    /// Client -> Server
    /// Set the forward move of the player on/off
    /// </summary>
    [Command]
    void CmdSetMoveForward (bool active) {
        _moveForward = active;
    }

    /// <summary>
    /// Client -> Server
    /// Set the backward of the player on/off
    /// </summary>
    [Command]
    void CmdSetMoveBackward (bool active) {
        _moveBackward = active;
    }

    /// <summary>
    /// Client -> Server
    /// Set the left turn of the player on/off
    /// </summary>
    [Command]
    void CmdSetTurnLeft (bool active) {
        _turnLeft = active;
    }

    /// <summary>
    /// Client -> Server
    /// Set the right turn of the player on/off
    /// </summary>
    [Command]
    void CmdSetTurnRight (bool active) {
        _turnRight = active;
    }

    /// <summary>
    /// Client -> Server
    /// Set the jumpping of the player on/off
    /// </summary>
    [Command]
    void CmdSetJump (bool active) {
        _jump = active;
    }

    /// <summary>
    /// Client -> Server
    /// Set shooting weapon on/off
    /// </summary>
    [Command]
    void CmdSetShooting (bool active) {
        _isFireing = true;
    }
}
Justin808
  • 20,859
  • 46
  • 160
  • 265

1 Answers1

0

You should not do the movement on the server. Rewrite it so that the movement is calculated and executed on the client. Then add an NetworkTransform component to the player and it should work.

Only the Fire method has to be a Command. But because I don't know what actually happens when _isFireing = true I can't tell you what you should write exactly ;)

EDIT: You also need a NetworkIdentity component on the player if you don't have one

Rafiwui
  • 544
  • 6
  • 19
  • I have NetworkIdentity and I have NetworkTransform. I _want_ the server to be in control. You're not supposed to trust the client. – Justin808 Mar 11 '16 at 21:26
  • Another problem is that `[SyncVar]` is synchronized from server to client not from client to server (at least i think so and thats what the Scripting API is saying) – Rafiwui Mar 11 '16 at 21:41