简体   繁体   English

UNET - 让任何玩家将命令发送到同一个NetworkIdentity

[英]UNET - Let any player send Commands to the same NetworkIdentity

Unity version : 5.5 Unity版本 :5.5

Scene example : 场景示例

  • Light [GameObject with a Light component] Light [带有Light组件的GameObject]
  • LightSwitch - [Contains: BoxCollider|NetworkIdentity|Script inherited from NetworkBehaviour that toggles light on/off when someone clicks over it's BoxCollider] LightSwitch - [包含:BoxCollider | NetworkIdentity |从NetworkBehaviour继承的脚本,当有人点击它的BoxCollider时打开/关闭灯光]

LightSwitch.cs 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);
    }
}

¿How can i let any player click that LightSwitch and toggle the lights on/off? ¿我怎样才能让任何玩家点击LightSwitch并打开/关闭灯光?

Edit: Following the example, this is the code that i had to build: 编辑:在示例之后,这是我必须构建的代码:

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

A big piece of shit just to toggle a light, thanks to Unity. 这要归功于Unity,这只是为了切换灯光。

Unfortunately commands can only be sent from the client player object. 不幸的是,命令只能从客户端播放器对象发送。 From the docs: 来自文档:

[Command] functions are invoked on the player GameObject associated with a connection. 在与连接关联的播放器GameObject上调用[Command]函数。

What you can do those is place a toggle function on the player object that passes the network identity of the object you want to toggle. 您可以做的是在播放器对象上放置一个切换功能,该功能传递您要切换的对象的网络标识。 For instance: 例如:

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

And then on the server you can either call an RPC or have the light switch state as a SyncVar. 然后在服务器上,您可以调用RPC或将灯开关状态设置为SyncVar。 The later method is probably easier and more reliable (ie a new player will have the correct light switch state set automatically). 后一种方法可能更容易,更可靠(即新玩家将自动设置正确的灯开关状态)。

Here is an (untested) example: 这是一个(未经测试的)示例:

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

Edit: 编辑:

This is a code snippet from one of my projects. 这是我的一个项目的代码片段。 This snippet comes from a script attached to the networked player object that I use to control the player's health. 此片段来自附加到网络播放器对象的脚本,用于控制播放器的运行状况。

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

Firstly, I declare a variable to hold the players health and assign it a SyncVar attribute. 首先,我声明一个变量来保持玩家健康并为其分配一个SyncVar属性。 By assigning this attribute, the server will update this variable across the clients whenever this variable is changed on the server. 通过分配此属性,无论何时在服务器上更改此变量,服务器都将在客户端上更新此变量。 I also add the hook parameter causing the OnHealth() function to be called on all clients when this variable in updated. 我还添加了hook参数,当更新此变量时,导致在所有客户端上调用OnHealth()函数。

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

Here is the OnHealth function. 这是OnHealth功能。 This function is called every time the server notifies the client that currentHealth has changed. 每次服务器通知客户端currentHealth已更改时,都会调用此函数。 It also passes the new value of currentHealth as an argument, we just need to manually assign this passed value as the new currentHealth. 它还将currentHealth的新值作为参数传递,我们只需要将此传递的值手动分配为新的currentHealth。

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

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

I also have a public function that allows the player to take damage. 我还有一个公共功能,允许玩家受到伤害。 Notice the check in the first line of this function, I only care if the damage occurs on the server. 注意检查这个函数的第一行,我只关心服务器上是否有损坏。 The SyncVar attribute will cause the change in currentHealth to by synced across the clients. SyncVar属性将导致currentHealth中的更改通过客户端同步。 In this particular game, the player is only damaged when they get hit by a projectile. 在这个特定的游戏中,玩家只有在被射弹击中时才会受损。 By calling the damage function this way, the server becomes the source of true (if the client is lagging the projectile may appear to miss when it should hit or vice versa - in that case, using a [Command] attribute may lead to conflicting results). 通过这种方式调用损坏函数,服务器成为真的来源(如果客户端滞后,射弹可能会在它应该命中时错过,反之亦然 - 在这种情况下,使用[Command]属性可能会导致冲突的结果)。

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

In this game there is also a heal function that occurs when the player presses a certain key. 在该游戏中,还存在当玩家按下某个键时发生的治疗功能。 Since the server doesn't know when this key is pressed, I can't update the health the way I do with the damage function. 由于服务器不知道何时按下该键,我无法像使用损坏功能那样更新健康状况。 Therefore, I use a [Command] attribute. 因此,我使用[Command]属性。 So this is the flow: player presses key -> Client notifies server that CmdHeal was called -> CmdHeal executes on the server -> server notifies all clients that currentHealth has changed. 所以这就是流程:玩家按键 - >客户端通知服务器CmdHeal被调用 - > CmdHeal在服务器上执行 - >服务器通知所有客户端currentHealth已更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM