如何在UNet / Unity5中同步非玩家GameObject属性?

我正在研究和学习Unity 5,UNET和网络的一些基础知识。 我制作了一个简单的3D游戏,你可以四处走动并改变物体的颜色。 但是我现在想让它成为多人游戏,并且我在如何通过网络发送更改方面遇到了很多麻烦,因此所有玩家都可以看到单个玩家的颜色变化。

部分问题是使用较新的UNET网络引擎很难找到答案。 有时我会遇到旧方式的答案。

所以主要的问题是,我如何联网非玩家GameObject属性的变化? 颜色,形状,大小等。

这是我现在的一些代码 – 我有很多不同的版本,所以我只发布当前版本:

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 objIdentity; void Update () { CheckIfPainting(); } void CheckIfPainting(){ if(Input.GetMouseButtonDown(0)) { if (Physics.Raycast (camTransform.TransformPoint (0, 0, 0.5f), camTransform.forward, out hit, range)) { string objName = hit.transform.name; CmdPaint(objName); } } } [ClientRpc] void RpcPaint(){ objIdentity.GetComponent().material.color = objectColor; } [Command] void CmdPaint(string name) { objIdentity = GameObject.Find (name); //tell us what was hit objectColor = new Color(Random.value, Random.value, Random.value, Random.value); RpcPaint (); } } 

我已经尝试了更多的解决方案,包括在我想要更改颜色的对象上编写单独的脚本,包括[SyncVar]和钩子函数。 我也尝试过每一个我期望更新客户端上的对象的函数的Debug.Log,并且它们正在使用预期的数据执行。

我真的不知道还能做什么。 我觉得这是一件非常简单的事情,但是我没有遇到任何问题,教程或其他资源中的非玩家GameObject的同步。 任何想法都会有所帮助,谢谢。

我找到了答案。 这是非常困难的,因为几乎每一个问题,post,例子等等……我能找到的是关于玩家对象,而不是非玩家对象。

所以,我需要使用AssignClientAuthority函数。 我曾尝试了几次,但没有正确使用它。 以下是适用于播放器的正常运行的C#脚本:

 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().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 (); // 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 } } 

!!!重要!!! 您想要影响的每个对象必须具有NetworkIdentity组件,并且必须将其设置为LocalPlayerAuthority

因此,此脚本只是为了更改随机颜色,但您应该能够更改实际内容以将其应用于材质中的任何更改或您要与非玩家对象联网的任何其他内容。 “应该”是最佳词 – 我还没有尝试过任何其他function。

编辑 – 为学习目的添加了更多评论。

Unity 5.3.2p3将客户端权限分配给非播放器对象

对于任何有兴趣设置这个的人来说,这是我的方法

客户端OnLocalPlayer组件 – >调用命令以通过传递对象NetworkInstanceId来分配和删除对象权限。 您可以添加任何UI以在此组件上调用这些方法

服务器端

  [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); } 

客户端3.对象组件 – >
OnStartAuthority() – 允许向服务器发送命令OnStopAuthority() – 不允许向服务器发送命令

这里的所有都是它的!

2018年:

而不是使用“分配对象权限”,

我真的建议只使用

.SpawnWithClientAuthority

这真的很容易。

事实上就是这么简单!

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

{在该代码中, 请注意“connectionToClient”可以毫不费力地神奇地使用 – 它意味着调用此命令的“客户端”。}

在客户端(你想要“拥有”的东西),只需调用CmdPleaseSpawnSomething()

我的意思是 – 这就是它的全部,谢天谢地。

这里有一个很清楚的解释:

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

我对这段代码进行了一些小的修改,并添加了脚本的可能性,如果我们放置玩家,他可以通过光线投射进行更改。

 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().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 (); // 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 } }