死と再生成

確認済のバージョン: 5.3

-

難易度: 中級

現時点では、プレイヤーの「現在の体力」がゼロになった際、サーバーのゲーム機にメッセージが出る以外は何も起こりません。もう少しゲームらしい挙動にするために、「現在の体力」がゼロになった時にプレイヤーが開始位置に戻されて体力が満タンに戻るようにしてみましょう。

ここで、もうひとつのステート同期(State Synchronization)用ツールである [ClientRpc] 属性をご紹介します。

ClientRpc コールは、サーバー上にある、NetworkIdentity を持つ全ての生成(spawn)オブジェクトから送ることができます。この関数はサーバー上で呼び出されますが、クライアント上で実行されます。つまりコマンドとは逆になります。コマンドはクライアント上で呼び出され、サーバー上で実行されますが、ClientRpc はサーバー上で呼び出され、クライアント上で実行されます。

関数を ClientRpc コールにするには、[ClientRpc] 属性を使用し、 関数の名前にプレフィックス “Rpc” を追加します。こうすることで、この関数がサーバー上で呼び出された場合にクライアント上で実行されるようになります。全ての引数は自動的に ClientRpc コールの一部としてクライアントに渡されます。[ClientRpc] 属性についての詳細は、リモートアクションに関するページをご覧ください。

オブジェクトの再生成(respawn)を有効にするには、Health スクリプト内に Respawn 関数を作成し、プレイヤーの体力が 0 になった際の Respawn 関数への呼び出しを、サーバー上で TakeDamage 内に作成する必要があります。

  • 編集用に Health スクリプトを開いてください。
  • Respawn という名前の新しい関数を、[ClientRpc] 属性および Rpc プレフィックスを付けて作成してください。
[ClientRpc]
void RpcRespawn()
{
    if (isLocalPlayer)
    {
        // ゼロ地点に戻る
        transform.position = Vector3.zero;
    }
}

ここで、TakeDamage 内で、プレイヤーの currentHealth0 になった場合に、そのプレイヤーが再生成されるようにコードを更新する必要があります。

  • TakeDamage 内のコードを、プレイヤーの currentHealth が maximum にリセットされるように変更してください。
currentHealth = maxHealth;

  • Debug.Log ラインを RpcRespawn の呼び出しに置き換えてください。
// サーバーで呼び出されるが、クライアントで実行される
RpcRespawn();

最終的なスクリプトは以下のようになります。

Health (体力)

Code snippet

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

public class Health : NetworkBehaviour {

    public const int maxHealth = 100;

    [SyncVar(hook = "OnChangeHealth")]
    public int currentHealth = maxHealth;

    public RectTransform healthBar;

    public void TakeDamage(int amount)
    {
        if (!isServer)
            return;
        
        currentHealth -= amount;
        if (currentHealth <= 0)
        {
            currentHealth = maxHealth;

            // サーバーで呼び出されるが、クライアントで実行される
            RpcRespawn();
        }
    }

    void OnChangeHealth (int currentHealth )
    {
        healthBar.sizeDelta = new Vector2(currentHealth , healthBar.sizeDelta.y);
    }

    [ClientRpc]
    void RpcRespawn()
    {
        if (isLocalPlayer)
        {
            // ゼロ地点に戻る
            transform.position = Vector3.zero;
        }
    }
}

このサンプルでは、ローカルの Player ゲームオブジェクトの位置をクライアントが制御しています。これは、この Player ゲームオブジェクトがこのクライアントにおける ローカル権限 を持っているからです。

プレイヤーの currentHealth0 になった際、もし単純にサーバーが直接その Player ゲームオブジェクトを元の位置に戻したとしたら、このクライアントはサーバーをオーバーライドします。なぜなら、このクライアントが権限を持っているからです。

これを回避するため、ClientRpc コールという形で、サーバーから該当クライアントに対して、このプレイヤーのゲームオブジェクトを再スタート位置に戻すよう命令を出します。その後、このプレイヤーゲームオブジェクトの NetworkTransform の働きにより、全てのクライアント上でこの位置に同期が行われます。

  • スクリプトを保存してください。
  • Unity に戻ってください。
  • スタンドアロンのアプリケーションとして該当シーンの Build and Run(ビルドおよび実行)を行ってください。
  • ゲーム内 UI から Host ボタンをクリックすると、このゲームがホストとして開始されます。
  • プレイヤーゲームオブジェクトを動かしてください。
  • Unity に戻ってください。
  • Play モードを開始します。
  • ゲーム内 UI から LAN Client ボタンをクリックすると、クライアントとしてホストに接続されます。
  • プレイヤーゲームオブジェクトを動かし、どちらのプレイヤーゲームオブジェクトも元々の位置にない状態にしてください。

一方のプレイヤーがもう一方を撃って「現在の体力」が 0 になるまでダメージを与えると、ダメージを受けた方のプレイヤーゲームオブジェクトが元々の位置に転送され、「現在の体力」は最高値に戻っているはずです。

  • スタンドアロン・プレイヤーを終了してください。
  • Unity に戻ってください。
  • Play モードを終了してください。

関連ドキュメント