如何同步UNet/Unity5中的非玩家GameObject属性
本文关键字:玩家 属性 GameObject Unity5 何同步 同步 UNet | 更新日期: 2023-09-27 18:20:19
我正在学习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<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 ();
}
}
我尝试了更多的解决方案,包括为我想要更改颜色的对象编写一个单独的脚本,并包括[SyncVar]和钩子函数。我还尝试了Debug.Log来更新客户端上的对象的每个函数,它们正在使用预期的数据执行。
我真的不知道还能做什么。我觉得这是我想做的一件非常简单的事情,但我没有在任何问题、教程或其他资源中遇到同步非玩家GameObject的问题。任何想法都会有帮助,谢谢。
所以,我需要使用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
}
}
!!!重要的要影响的每个对象都必须具有NetworkIdentity组件,并且必须将其设置为LocalPlayerAuthority
所以这个脚本只是改变一个随机的颜色,但你应该能够改变实际的东西,将其应用于材料的任何变化或你想与非玩家对象联网的任何其他东西。"应该"是最合适的词——我还没有尝试过任何其他功能。
编辑-添加了更多用于学习目的的评论。
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<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
}
}