How do I sync non-player GameObject properties in UNet/Unity5?

前端 未结 4 864
遇见更好的自我
遇见更好的自我 2020-12-09 22:32

I\'m working on and learning some basics of Unity 5, UNET, and networking. I made a simple 3D game where you go around and change the colors of objects. But I want to make i

相关标签:
4条回答
  • 2020-12-09 22:53

    i make a small modification to this code and add the possibility the script if we place the player he can make the change through the raycasting.

    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    
    public class Raycasting_Object : NetworkBehaviour {
    
        private int range = 200;
    //  [SerializeField] private Transform camTransform;
        private RaycastHit hit;
        [SyncVar] private Color objectColor;
        [SyncVar] private GameObject objectID;
        private NetworkIdentity objNetId;
    
        void Update () {
            if (isLocalPlayer) {    
                CheckIfPainting ();
            }
        }
    
        void CheckIfPainting(){
    
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            Debug.DrawRay (ray.origin, ray.direction * 100, Color.cyan);
    
            if(isLocalPlayer && Input.GetMouseButtonDown(0)) {
                if (Physics.Raycast (ray.origin, ray.direction, out hit, range)) {
                    objectID = GameObject.Find (hit.transform.name);                                    // this gets the object that is hit
                    Debug.Log(hit.transform.name);
                    objectColor = new Color(Random.value, Random.value, Random.value, Random.value);    // I select the color here before doing anything else
                    CmdPaint(objectID, objectColor);
                }
            }
    
        }
    
        [ClientRpc]
        void RpcPaint(GameObject obj, Color col){
            obj.GetComponent<Renderer>().material.color = col;      // this is the line that actually makes the change in color happen
        }
    
        [Command]
        void CmdPaint(GameObject obj, Color col) {
            objNetId = obj.GetComponent<NetworkIdentity> ();        // get the object's network ID
            objNetId.AssignClientAuthority (connectionToClient);    // assign authority to the player who is changing the color
            RpcPaint (obj, col);                                    // usse a Client RPC function to "paint" the object on all clients
            objNetId.RemoveClientAuthority (connectionToClient);    // remove the authority from the player who changed the color
        }
    }
    
    0 讨论(0)
  • 2020-12-09 22:58

    Unity 5.3.2p3 Assign Client Authority to Non Player Objects

    For anyone interested in setting this up this is my approach

    Client Side OnLocalPlayer component -> Call commands to assign and remove object authority by passing through the objects NetworkInstanceId. You can add any UI to call these methods on this component

    Server Side

        [Command]
        void CmdAssignObjectAuthority(NetworkInstanceId netInstanceId)
        {
            // Assign authority of this objects network instance id to the client
            NetworkServer.objects[netInstanceId].AssignClientAuthority(connectionToClient);
        }
    
        [Command]
        void CmdRemoveObjectAuthority(NetworkInstanceId netInstanceId)
        {
            // Removes the  authority of this object network instance id to the client
            NetworkServer.objects[netInstanceId].RemoveClientAuthority(connectionToClient);
        }  
    

    Client Side 3. Object component ->
    OnStartAuthority() - allowed to send commands to server OnStopAuthority() - not allowed to send commands to server

    That's all there is to it!

    0 讨论(0)
  • 2020-12-09 23:02

    I found my answer. And it was very difficult, as almost every single question, post, example, etc... I could find was about player objects, and not non-player objects.

    So, I needed to use the AssignClientAuthority function. Which I had tried a couple of times, but wasn't using it correctly. Here is the functioning C# script to apply to the player:

    using UnityEngine;
    using System.Collections;
    using UnityEngine.Networking;
    
    public class Player_Paint : NetworkBehaviour {
    
        private int range = 200;
        [SerializeField] private Transform camTransform;
        private RaycastHit hit;
        [SyncVar] private Color objectColor;
        [SyncVar] private GameObject objectID;
        private NetworkIdentity objNetId;
    
        void Update () {
            // only do something if it is the local player doing it
            // so if player 1 does something, it will only be done on player 1's computer
            // but the networking scripts will make sure everyone else sees it
            if (isLocalPlayer) {
                CheckIfPainting ();
            }
        }
    
        void CheckIfPainting(){
            // yes, isLocalPlayer is redundant here, because that is already checked before this function is called
            // if it's the local player and their mouse is down, then they are "painting"
            if(isLocalPlayer && Input.GetMouseButtonDown(0)) {
                // here is the actual "painting" code
                // "paint" if the Raycast hits something in it's range
                if (Physics.Raycast (camTransform.TransformPoint (0, 0, 0.5f), camTransform.forward, out hit, range)) {
                    objectID = GameObject.Find (hit.transform.name);                                    // this gets the object that is hit
                    objectColor = new Color(Random.value, Random.value, Random.value, Random.value);    // I select the color here before doing anything else
                    CmdPaint(objectID, objectColor);    // carry out the "painting" command
                }
            }
        }
    
        [ClientRpc]
        void RpcPaint(GameObject obj, Color col){
            obj.GetComponent<Renderer>().material.color = col;      // this is the line that actually makes the change in color happen
        }
    
        [Command]
        void CmdPaint(GameObject obj, Color col) {
            objNetId = obj.GetComponent<NetworkIdentity> ();        // get the object's network ID
            objNetId.AssignClientAuthority (connectionToClient);    // assign authority to the player who is changing the color
            RpcPaint (obj, col);                                    // usse a Client RPC function to "paint" the object on all clients
            objNetId.RemoveClientAuthority (connectionToClient);    // remove the authority from the player who changed the color
        }
    }
    

    !!!Important!!! Each object that you want to affect must have a NetworkIdentity component, and it must be set to LocalPlayerAuthority

    So this script is just to change a random color, but you should be able to change the actual stuff to apply this to any change in the materials or anything else you want to network with a non-player object. "Should" being the optimal word - I haven't tried with any other functionality yet.

    EDIT - added more comments for learning purposes.

    0 讨论(0)
  • 2020-12-09 23:03

    For 2018:

    Rather than using "Assign Object Authority",

    I really recommend simply using

    .SpawnWithClientAuthority

    It's really very easy.

    In fact it's this simple!

      [Command]
      void CmdPleaseSpawnSomething() {
     
            GameObject p = Instantiate(some_Prefab);
            NetworkServer.SpawnWithClientAuthority(p, connectionToClient);
        }
    

    {In that code, note that "connectionToClient" is magically available with no effort - it means "the client" who called this command.}

    On the client (the one you want to "own" the thing), just call CmdPleaseSpawnSomething().

    I mean - that's all there is to it, thank goodness.

    There's a long clear explanation here:

    https://forum.unity.com/threads/assign-authority-to-local-client-gameobject.371113/#post-3592541

    0 讨论(0)
提交回复
热议问题