4

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 のおかげで、ライトを切り替えるだけでも大したことはありません。

4

1 に答える 1

3

残念ながら、コマンドはクライアント プレイヤー オブジェクトからしか送信できません。ドキュメントから:

[Command] 関数は、接続に関連付けられたプレーヤー ゲームオブジェクトで呼び出されます。

それらを行うことができるのは、トグルするオブジェクトのネットワーク ID を渡すトグル関数をプレーヤー オブジェクトに配置することです。例えば:

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

編集:

これは、私のプロジェクトの 1 つからのコード スニペットです。このスニペットは、ネットワーク化されたプレイヤー オブジェクトにアタッチされたスクリプトから取得したもので、プレイヤーのヘルスを制御するために使用しています。

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

このゲームには、プレイヤーが特定のキーを押すと発生するヒール機能もあります。サーバーはこのキーが押されたタイミングを認識しないため、ダメージ関数のようにヘルスを更新することはできません。したがって、[コマンド] 属性を使用します。フローは次のとおりです。プレーヤーがキーを押す -> クライアントがサーバーに CmdHeal が呼び出されたことを通知する -> CmdHeal がサーバー上で実行される -> サーバーがすべてのクライアントに currentHealth が変更されたことを通知する。

于 2016-12-13T16:36:01.020 に答える