Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在UNet/Unity5中同步非玩家游戏对象属性?_C#_Unity3d_Multiplayer_Unity5_Unity Networking - Fatal编程技术网

C# 如何在UNet/Unity5中同步非玩家游戏对象属性?

C# 如何在UNet/Unity5中同步非玩家游戏对象属性?,c#,unity3d,multiplayer,unity5,unity-networking,C#,Unity3d,Multiplayer,Unity5,Unity Networking,我正在学习Unity 5、UNET和网络的一些基础知识。我做了一个简单的3D游戏,你可以在游戏中改变物体的颜色。但是我现在想让它成为多人游戏,而且我很难弄清楚如何通过网络发送更改,以便所有玩家都能看到单个玩家的颜色更改 问题的一部分在于,使用较新的UNET网络引擎很难找到答案。有时我会遇到一些老一套的答案 所以,主要的问题是,我如何改变网络非玩家游戏对象的属性?颜色、形状、大小等 下面是我现在拥有的一些代码——我有很多不同的版本,所以我只发布当前版本: using UnityEngine;

我正在学习Unity 5、UNET和网络的一些基础知识。我做了一个简单的3D游戏,你可以在游戏中改变物体的颜色。但是我现在想让它成为多人游戏,而且我很难弄清楚如何通过网络发送更改,以便所有玩家都能看到单个玩家的颜色更改

问题的一部分在于,使用较新的UNET网络引擎很难找到答案。有时我会遇到一些老一套的答案

所以,主要的问题是,我如何改变网络非玩家游戏对象的属性?颜色、形状、大小等

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

 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<Renderer>().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 ();
     }
 }
使用UnityEngine;
使用系统集合;
使用UnityEngine。联网;
公共类玩家:网络行为{
私有整数范围=200;
[SerializeField]私有转换camTransform;
二等兵雷卡斯特命中;
[SyncVar]专用颜色objectColor;
[SyncVar]私有游戏对象对象身份;
无效更新(){
CheckIfPainting();
}
void CheckIfPainting(){
if(Input.GetMouseButtonDown(0)){
if(Physics.Raycast(camTransform.TransformPoint(0,0,0.5f)、camTransform.forward、out hit、range)){
字符串objName=hit.transform.name;
CmdPaint(objName);
}
}
}
[客户端RPC]
void RpcPaint(){
objIdentity.GetComponent().material.color=objectColor;
}
[命令]
void CmdPaint(字符串名称){
objIdentity=GameObject.Find(name);//告诉我们命中了什么
objectColor=新颜色(Random.value、Random.value、Random.value、Random.value);
RpcPaint();
}
}
我尝试了更多的解决方案,包括在我想要更改颜色的对象上编写单独的脚本,并包括[SyncVar]和hook函数。我还尝试了Debug.Log,登录我希望更新客户机上对象的每个函数,这些函数正在使用预期的数据执行


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

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

因此,我需要使用
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<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
    }
}
使用UnityEngine;
使用系统集合;
使用UnityEngine。联网;
公共类玩家:网络行为{
私有整数范围=200;
[SerializeField]私有转换camTransform;
二等兵雷卡斯特命中;
[SyncVar]专用颜色objectColor;
[SyncVar]私有游戏对象objectID;
专用网络标识objNetId;
无效更新(){
//只有本地玩家在做某件事时才去做
//所以如果玩家1做了什么,它将只在玩家1的计算机上完成
//但是网络脚本将确保其他人都能看到它
if(IsLocalLayer){
CheckIfPainting();
}
}
void CheckIfPainting(){
//是的,IsLocalLayer在这里是冗余的,因为在调用此函数之前已经检查了它
//如果是本地玩家,他们的鼠标按下了,那么他们在“画画”
if(isLocalPlayer&&Input.GetMouseButtonDown(0)){
//这是实际的“绘画”代码
//如果光线投射击中其范围内的某物,“绘制”
if(Physics.Raycast(camTransform.TransformPoint(0,0,0.5f)、camTransform.forward、out hit、range)){
objectID=GameObject.Find(hit.transform.name);//这将获取命中的对象
objectColor=新颜色(Random.value、Random.value、Random.value、Random.value);//在执行其他操作之前,我在此处选择颜色
CmdPaint(objectID,objectColor);//执行“绘制”命令
}
}
}
[客户端RPC]
void RpcPaint(游戏对象对象对象,颜色列){
obj.GetComponent().material.color=col;//这是实际更改颜色的行
}
[命令]
void CmdPaint(游戏对象对象对象,颜色列){
objNetId=obj.GetComponent();//获取对象的网络ID
objNetId.AssignClientAuthority(ConnectionClient);//将权限分配给正在更改颜色的玩家
RpcPaint(obj,col);//使用客户端RPC函数在所有客户端上“绘制”对象
objNetId.RemoveClientAuthority(ConnectionClient);//从更改颜色的播放器中删除权限
}
}
!!!重要的!!! 要影响的每个对象都必须具有NetworkIdentity组件,并且必须将其设置为LocalPlayerAuthority

所以这个脚本只是为了改变一个随机的颜色,但是你应该能够改变实际的东西,把它应用到材料的任何变化,或者你想要与非玩家对象联网的任何东西。“应该”是最好的词-我还没有尝试过任何其他功能


编辑-为学习目的添加更多注释。

Unity 5.3.2p3将客户端权限分配给非玩家对象

对于任何有兴趣建立这个系统的人,这是我的方法

客户端 OnLocalPlayer组件->调用命令,通过传递对象网络实例ID来分配和删除对象权限。您可以添加任何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);
    }  
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
    }
}
  [Command]
  void CmdPleaseSpawnSomething() {
 
        GameObject p = Instantiate(some_Prefab);
        NetworkServer.SpawnWithClientAuthority(p, connectionToClient);
    }