首页 > 解决方案 > 在 Unity 中使用 Unet 更改 GameObjects 上的材质

问题描述

当我在任何客户端中单击它时,我想在所有客户端上更改游戏对象的材质。我是 UNET 的新手,我认为我有一个概念缺陷。所以基本上我想做的是:

  1. 在 NetworkPlayer 上向场景中的对象发射光线
  2. [Command]从播放器发送一个
  3. 在这个[Command]调用[ClientRpc]对象上
  4. [ClientRpc]改变这个物体的材质

我的播放器:

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

}

发生的情况是:对象上的文本更改为适当的颜色,但材质从未更改。如何更改材料?

额外问题:如果有人知道如何构思 UNET 游戏的好教程,请告诉我。

标签: unity3dgameobjectunity3d-unet

解决方案


您的问题是您curColOfThisObject在客户端计算值,但同时使用[SyncVar]它。

来自[SyncVar]文档

这些变量的值将从服务器同步到客户端

-> 不要更改客户端上的值,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改为:hook[SyncVar]

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

请注意,您可能会击中孩子或父母,而不是您想要击中的实际对象.. 所以 evtl。您必须使用or查找RPC_ColorChange子级或父级中的组件。GetComponentInChildrenGetComponentInParent


推荐阅读