Unity版本:5.5

场景示例:


灯光[带有灯光组件的GameObject]
LightSwitch-[包含:BoxCollider | NetworkIdentity |从NetworkBehaviour继承的脚本,当有人单击BoxCollider时,该脚本可打开/关闭灯光]


LightSwitch.cs

public class LightSwitch : NetworkBehaviour
{
    public GameObject roomLight;

    void OnMouseDown () {
        CmdToggleLight(!roomLight.activeSelf);
    }

    [Command]
    void CmdToggleLight (bool status) {
        RpcToggleLight(status);
    }

    [ClientRpc]
    void RpcToggleLight (bool status) {
        roomLight.SetActive(status);
    }
}


¿我如何让任何玩家单击该LightSwitch并打开/关闭灯光?

编辑:
在示例之后,这是我必须构建的代码:

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;

public class LightSwitch : NetworkBehaviour
{
    public GameObject roomLight;

    [SyncVar(hook="setLight")]
    private bool status;


    void OnMouseDown()
    {
        // my player's singleton
        Player.singleton.CmdToggleSwitch(this.gameObject);
    }

    public void toggleLight()
    {
        status = !status;
    }

    void setLight(bool newStatus)
    {
        roomLight.SetActive(newStatus);
    }

    [ClientRpc]
    public void RpcToggleSwitch(GameObject switchObject)
    {
        switchObject.GetComponent<LightSwitch>().toggleLight();
    }
}


Player.cs代码:

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
using System.Collections.Generic;
using System;

public class Player : NetworkBehaviour {

    public static Player singleton;

    void Start () {
        singleton = this;
    }

    //... my player class code ....//

    [Command]
    public void CmdToggleSwitch(GameObject gObject)
    {
        gObject.GetComponent<LightSwitch>().RpcToggleSwitch(gObject);
    }
}


多亏了Unity,很多东西只是用来切换灯光。

最佳答案

不幸的是,命令只能从客户端播放器对象发送。
从文档:


  在与连接关联的玩家GameObject上调用[Command]函数。


您可以做的是在播放器对象上放置一个切换功能,该功能传递您要切换的对象的网络标识。例如:

[Command]
void CmdToggleSwitch (GameObject switch) //switch must have network identity component
{
  //Set the switch state on the server
  switch.GetComponent<LightSwitch>().ToggleMethod();
}


然后在服务器上,您可以调用RPC或将电灯开关状态作为SyncVar。后一种方法可能更简单,更可靠(即新玩家将自动设置正确的灯光开关状态)。

这是一个(未经测试的)示例:

using UnityEngine;
using UnityEngine.Networking;

public class RaycastExample : NetworkBehaviour

    void ToggleSwitch()
        {
            RaycastHit hit;
            //Use raycasting to find switch
            if (Physics.Raycast(transform.position, transform.forwards, out hit, 5.0f))
            {
                if (hit.GetComponent<LightSwitch>())
                {
                    //Send the command to toggle the switch of the server, passing in the LightSwitch gameobject as the parameter
                    CmdToggleSwitch (hit.transform.gameObject);
                }
            }
    }

    //This will be run on the server version of our player
    [Command]
    void CmdToggleSwitch (GameObject switch) //switch must have network identity component
    {
      //Set the switch state on the server
      //Server light switch will need some way to notify the clients of the change. RPC or SyncVar.
      switch.GetComponent<LightSwitch>().ToggleMethod();
    }


编辑:

这是我的一个项目的代码片段。该代码片段来自附加到网络播放器对象的脚本,该脚本用于控制播放器的运行状况。

    [SyncVar(hook="OnHealth")]
    public float currentHealth = 100f;


首先,我声明一个变量来保持玩家的健康状况,并为其分配SyncVar属性。通过分配此属性,只要服务器上的此变量发生更改,服务器就会在客户端之间更新此变量。我还添加了hook参数,以使在更新此变量时在所有客户端上调用OnHealth()函数。

void OnHealth (float newHealth) {
    currentHealth = newHealth;
}


这是OnHealth功能。每当服务器通知客户端currentHealth已更改时,都会调用此函数。它还将currentHealth的新值作为参数传递,我们只需要手动将此传递的值分配为新的currentHealth。

    public void TakeDamage (float damage) {
        if (!isServer)
            return;

        currentHealth -= damage;
        if (currentHealth < 0)
            currentHealth = 0;
    }


我还有一个公共功能,可以让玩家受到伤害。请注意此功能第一行中的检查,我只关心服务器是否损坏。 SyncVar属性将导致currentHealth的更改在客户端之间进行同步。在这个特殊的游戏中,玩家只有在被弹丸击中时才会受到伤害。通过这种方式调用损伤函数,服务器将成为真实的来源(如果客户端滞后,弹丸应该在命中时丢失,反之亦然-在这种情况下,使用[Command]属性可能导致结果冲突)。

    [Command]
    public void CmdHeal(float heal) {
            currentHealth += heal;
    }


在该游戏中,当玩家按下某个键时,还会发生修复功能。由于服务器不知道何时按下此键,因此无法像使用损坏功能那样更新运行状况。因此,我使用[Command]属性。流程如下:播放器按下键->客户端通知服务器CmdHeal被称为-> CmdHeal在服务器上执行->服务器通知所有客户端currentHealth已更改。

08-17 18:44