在 Unity 中使用 Unet 更改 GameObjects material
Change material on GameObjects with Unet in Unity
当我在任何客户端中单击某个游戏对象时,我想在所有客户端上更改该游戏对象的 material。我是 UNET 的新手,我认为我有一个概念上的缺陷。所以基本上我想做的是:
- 将 NetworkPlayer 上的光线射向场景中的对象
- 从播放器发送一个
[Command]
- 在此
[Command]
中调用对象[ClientRpc]
- 在
[ClientRpc]
更改此对象的material
我的播放器:
using UnityEngine;
using UnityEngine.Networking;
// This script is on my Game Player Prefab
// (removed the cam movement part)
public class CamMovement : NetworkBehaviour
{
void Update()
{
if (!isLocalPlayer)
{
return;
}
if (Input.GetMouseButtonDown(0))
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
CmdNextColor(hit.transform.gameObject);
}
}
[Command]
public void CmdNextColor(GameObject hitObject)
{
RPC_ColorChange colorChange = hitObject.GetComponent<RPC_ColorChange>();
if (colorChange != null)
{
colorChange.RpcNextColor();
}
}
}
我的对象:
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class RPC_ColorChange : NetworkBehaviour {
public Material[] material;
[SyncVar]
int curColOfThisObject;
Text text;
private void Start()
{
text = GetComponentInChildren<Text>();
}
[ClientRpc]
public void RpcNextColor()
{
if (!isClient)
return;
if (material.Length > 0)
{
Material curMaterial = this.GetComponent<MeshRenderer>().material;
curColOfThisObject++;
if (curColOfThisObject >= material.Length)
curColOfThisObject = 0;
curMaterial = material[curColOfThisObject];
}
}
private void Update()
{
if (isClient)
{
text.text = "new color of this object: " + curColOfThisObject.ToString();
}
}
}
发生的事情是:
对象上的文本更改为适当的颜色,但 material 永远不会更改。如何更改 material?
奖金问题:
如果有人知道关于如何构思 UNET 游戏的好教程,请告诉我。
您的问题是您在客户端计算 curColOfThisObject
的值,但同时为它使用 [SyncVar]
。
These variables will have their values sychronized from the server to clients
-> 不要更改 RpcNextColor
中客户端 上的值 ,而是已经 服务器 中的值CmdNextColor
。否则 curColOfThisObject
将立即被服务器上从未更改过的默认值覆盖。我会将该值作为 [ClientRpc]
中的参数传递给客户,因此从技术上讲,您甚至根本不需要 [SyncVar]
。
在CamMovement
[Command]
public void CmdNextColor(GameObject hitObject)
{
RPC_ColorChange colorChange = hitObject.GetComponent<RPC_ColorChange>();
if (colorChange != null)
{
colorChange.NextColor();
// after calculating a new curColOfThisObject send it to clients (doesn't require [SyncVar] anymore)
colorChange.RpcNextColor(curColOfThisObject);
}
}
在RPC_ColorChange
// Make the calculation of the value on the server side
[Server]
private void NextColor()
{
if (material.Length > 0)
{
Material curMaterial = this.GetComponent<MeshRenderer>().material;
curColOfThisObject++;
if (curColOfThisObject >= material.Length)
curColOfThisObject = 0;
// set the material also on the server
curMaterial = material[curColOfThisObject];
}
}
[ClientRpc]
public void RpcNextColor(int newValue)
{
if (!isClient) return;
// easier to debug if you keep the curColOfThisObject variable
curColOfThisObject = newValue;
if(newValue=> material.Length)
{
Debug.LogError("index not found in material");
return;
}
// instead of curColOfThisObject you could also just use the newValue
// but this is easier to debug
curMaterial = material[curColOfThisObject];
}
如果您想坚持使用 [SyncVar]
,您也可以完全跳过 ClientRpc
并将其设为 [SyncVar]
的 hook
:
在CamMovement
[Command]
public void CmdNextColor(GameObject hitObject)
{
RPC_ColorChange colorChange = hitObject.GetComponent<RPC_ColorChange>();
if (colorChange != null)
{
colorChange.NextColor();
}
}
在RPC_ColorChange
[SyncVar(hook = "OnNextColor")]
private int curColOfThisObject;
// Make the calculation of the value on the server side
[Server]
private void NextColor()
{
if (material.Length > 0)
{
Material curMaterial = this.GetComponent<MeshRenderer>().material;
curColOfThisObject++;
if (curColOfThisObject >= material.Length)
curColOfThisObject = 0;
// set the material also on the server
curMaterial = material[curColOfThisObject];
}
}
// This method automatically gets called when the value of
// curColOfObject is changed to newValue on the server
private void OnNextColor(int newValue)
{
if (!isClient) return;
// easier to debug if you keep the curColOfThisObject variable
curColOfThisObject = newValue;
if(newValue=> material.Length)
{
Debug.LogError("index not found in material");
return;
}
// instead of curColOfThisObject you could also just use the newValue
// but this is easier to debug
curMaterial = material[curColOfThisObject];
}
额外的一点:我会在通过网络发送东西之前检查RPC_ColorChange
组件是否存在。
if (Input.GetMouseButtonDown(0))
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if(hit.GetComponent<RPC_ColorChange>()!=null)
{
CmdNextColor(hit.transform.gameObject);
}
}
}
请注意,您可能会点击 child 或 parent 而不是您想要点击的实际 object .. 所以 evtl。您必须使用 GetComponentInChildren
或 GetComponentInParent
.
在 child 或 parent 中查找 RPC_ColorChange
组件
RpcFunctions 在 Command 函数被处理后被调用有点违反直觉:
在播放器预制件上:
[Command]
public void CmdNextColor(GameObject hitObject)
{
RPC_ColorChange colorChange = hitObject.GetComponent<RPC_ColorChange>();
if (colorChange != null)
{
int curColor = colorChange.GetCurColor();
// change color +1 on the clients
colorChange.RpcNextColor(curColor);
// assign a SyncVar with the current color
colorChange.SyncColorVar();
}
}
现在按以下顺序调用函数:
1) 同步颜色变量()
2) RpcNextColor()
当我在任何客户端中单击某个游戏对象时,我想在所有客户端上更改该游戏对象的 material。我是 UNET 的新手,我认为我有一个概念上的缺陷。所以基本上我想做的是:
- 将 NetworkPlayer 上的光线射向场景中的对象
- 从播放器发送一个
[Command]
- 在此
[Command]
中调用对象[ClientRpc]
- 在
[ClientRpc]
更改此对象的material
我的播放器:
using UnityEngine;
using UnityEngine.Networking;
// This script is on my Game Player Prefab
// (removed the cam movement part)
public class CamMovement : NetworkBehaviour
{
void Update()
{
if (!isLocalPlayer)
{
return;
}
if (Input.GetMouseButtonDown(0))
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
CmdNextColor(hit.transform.gameObject);
}
}
[Command]
public void CmdNextColor(GameObject hitObject)
{
RPC_ColorChange colorChange = hitObject.GetComponent<RPC_ColorChange>();
if (colorChange != null)
{
colorChange.RpcNextColor();
}
}
}
我的对象:
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class RPC_ColorChange : NetworkBehaviour {
public Material[] material;
[SyncVar]
int curColOfThisObject;
Text text;
private void Start()
{
text = GetComponentInChildren<Text>();
}
[ClientRpc]
public void RpcNextColor()
{
if (!isClient)
return;
if (material.Length > 0)
{
Material curMaterial = this.GetComponent<MeshRenderer>().material;
curColOfThisObject++;
if (curColOfThisObject >= material.Length)
curColOfThisObject = 0;
curMaterial = material[curColOfThisObject];
}
}
private void Update()
{
if (isClient)
{
text.text = "new color of this object: " + curColOfThisObject.ToString();
}
}
}
发生的事情是: 对象上的文本更改为适当的颜色,但 material 永远不会更改。如何更改 material?
奖金问题: 如果有人知道关于如何构思 UNET 游戏的好教程,请告诉我。
您的问题是您在客户端计算 curColOfThisObject
的值,但同时为它使用 [SyncVar]
。
These variables will have their values sychronized from the server to clients
-> 不要更改 RpcNextColor
中客户端 上的值 ,而是已经 服务器 中的值CmdNextColor
。否则 curColOfThisObject
将立即被服务器上从未更改过的默认值覆盖。我会将该值作为 [ClientRpc]
中的参数传递给客户,因此从技术上讲,您甚至根本不需要 [SyncVar]
。
在CamMovement
[Command]
public void CmdNextColor(GameObject hitObject)
{
RPC_ColorChange colorChange = hitObject.GetComponent<RPC_ColorChange>();
if (colorChange != null)
{
colorChange.NextColor();
// after calculating a new curColOfThisObject send it to clients (doesn't require [SyncVar] anymore)
colorChange.RpcNextColor(curColOfThisObject);
}
}
在RPC_ColorChange
// Make the calculation of the value on the server side
[Server]
private void NextColor()
{
if (material.Length > 0)
{
Material curMaterial = this.GetComponent<MeshRenderer>().material;
curColOfThisObject++;
if (curColOfThisObject >= material.Length)
curColOfThisObject = 0;
// set the material also on the server
curMaterial = material[curColOfThisObject];
}
}
[ClientRpc]
public void RpcNextColor(int newValue)
{
if (!isClient) return;
// easier to debug if you keep the curColOfThisObject variable
curColOfThisObject = newValue;
if(newValue=> material.Length)
{
Debug.LogError("index not found in material");
return;
}
// instead of curColOfThisObject you could also just use the newValue
// but this is easier to debug
curMaterial = material[curColOfThisObject];
}
如果您想坚持使用 [SyncVar]
,您也可以完全跳过 ClientRpc
并将其设为 [SyncVar]
的 hook
:
在CamMovement
[Command]
public void CmdNextColor(GameObject hitObject)
{
RPC_ColorChange colorChange = hitObject.GetComponent<RPC_ColorChange>();
if (colorChange != null)
{
colorChange.NextColor();
}
}
在RPC_ColorChange
[SyncVar(hook = "OnNextColor")]
private int curColOfThisObject;
// Make the calculation of the value on the server side
[Server]
private void NextColor()
{
if (material.Length > 0)
{
Material curMaterial = this.GetComponent<MeshRenderer>().material;
curColOfThisObject++;
if (curColOfThisObject >= material.Length)
curColOfThisObject = 0;
// set the material also on the server
curMaterial = material[curColOfThisObject];
}
}
// This method automatically gets called when the value of
// curColOfObject is changed to newValue on the server
private void OnNextColor(int newValue)
{
if (!isClient) return;
// easier to debug if you keep the curColOfThisObject variable
curColOfThisObject = newValue;
if(newValue=> material.Length)
{
Debug.LogError("index not found in material");
return;
}
// instead of curColOfThisObject you could also just use the newValue
// but this is easier to debug
curMaterial = material[curColOfThisObject];
}
额外的一点:我会在通过网络发送东西之前检查RPC_ColorChange
组件是否存在。
if (Input.GetMouseButtonDown(0))
{
Ray ray = cam.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if(hit.GetComponent<RPC_ColorChange>()!=null)
{
CmdNextColor(hit.transform.gameObject);
}
}
}
请注意,您可能会点击 child 或 parent 而不是您想要点击的实际 object .. 所以 evtl。您必须使用 GetComponentInChildren
或 GetComponentInParent
.
RPC_ColorChange
组件
RpcFunctions 在 Command 函数被处理后被调用有点违反直觉:
在播放器预制件上:
[Command]
public void CmdNextColor(GameObject hitObject)
{
RPC_ColorChange colorChange = hitObject.GetComponent<RPC_ColorChange>();
if (colorChange != null)
{
int curColor = colorChange.GetCurColor();
// change color +1 on the clients
colorChange.RpcNextColor(curColor);
// assign a SyncVar with the current color
colorChange.SyncColorVar();
}
}
现在按以下顺序调用函数:
1) 同步颜色变量()
2) RpcNextColor()