UNET - 让任何玩家向同一个 NetworkIdentity 发送命令
Posted
技术标签:
【中文标题】UNET - 让任何玩家向同一个 NetworkIdentity 发送命令【英文标题】:UNET - Let any player send Commands to the same NetworkIdentity 【发布时间】:2017-04-28 05:02:12 【问题描述】:Unity 版本:5.5
场景示例:
Light [带有 Light 组件的游戏对象] 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,只是为了切换灯而已。
【问题讨论】:
【参考方案1】:不幸的是,命令只能从客户端播放器对象发送。 来自文档:
[Command] 函数在与连接关联的玩家 GameObject 上调用。
您可以做的是在播放器对象上放置一个切换函数,该函数传递您要切换的对象的网络身份。例如:
[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();
编辑:
这是我的一个项目中的代码 sn-p。这个 sn-p 来自一个附加到网络播放器对象的脚本,我用它来控制播放器的健康状况。
[SyncVar(hook="OnHealth")]
public float currentHealth = 100f;
首先,我声明一个变量来保存玩家的健康状况,并为其分配一个 SyncVar 属性。通过分配此属性,服务器将在服务器上更改此变量时跨客户端更新此变量。我还添加了钩子参数,导致在更新此变量时在所有客户端上调用 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 的更改通过客户端同步。在这个特定的游戏中,玩家只有在被弹丸击中时才会受到伤害。通过以这种方式调用伤害函数,服务器成为 true 的来源(如果客户端滞后,射弹可能会在应该击中时看起来未命中,反之亦然 - 在这种情况下,使用 [Command] 属性可能会导致结果冲突)。
[Command]
public void CmdHeal(float heal)
currentHealth += heal;
在这个游戏中,当玩家按下某个键时,还有一个治疗功能。由于服务器不知道何时按下此键,因此我无法像使用损坏功能那样更新健康状况。因此,我使用 [Command] 属性。所以流程如下:玩家按下键 -> 客户端通知服务器 CmdHeal 被调用 -> CmdHeal 在服务器上执行 -> 服务器通知所有客户端 currentHealth 已更改。
【讨论】:
(对不起,未格式化的评论,我不能让它看起来很棒,Unity Answers markdown SUCKS:imgur.com/rQi496t)。对不起,但我不明白你的解决方案。拥有示例场景: - 我将您在 LightSwitch.cs 中制作的CmdToggleSwitch
放置在 LightSwitch.cs 中,因为该脚本附加在存在 NetworkIdentity 的同一个 GameObject 中。 - 我如何从任何播放器调用该函数?正如您所说,[Command] 方法只能由 NetworkIdentity 所有者调用:s
对不起,我不清楚。 CmdToggleSwitch 将位于附加到播放器对象的脚本中,而不是灯开关上。然后该命令将在您的播放器的服务器版本上执行,然后播放器调用服务器灯开关上的 ToggleMethod()。然后通过 RPC 或 SyncVar 将灯开关的变化发送给客户端。
要记住的主要一点是,无论何时您在脚本中使用 [Commad],它都必须附加到您的网络播放器。
问题更新发布结束代码。我讨厌我必须编写多少代码才能切换一个灯。使用 Photon Network,这只是 2 种方法并完成...
@Chairs 我想知道您是否可以提供一个完整的示例,其中包含单独的脚本以及哪个对象也包含 SyncVar,因为我对它的位置缺乏了解。提前致谢以上是关于UNET - 让任何玩家向同一个 NetworkIdentity 发送命令的主要内容,如果未能解决你的问题,请参考以下文章
Unity UNET - 在播放器对象之外调用 [Command]
Unity 5 - UNET - 将拖动的游戏对象同步为客户端(HL2 重力枪风格)