マルチプレイヤーシューティングを追加する

確認済のバージョン: 5.3

-

難易度: 中級

この項では、サンプルプロジェクトの弾にネットワーキングを追加していきます。Bullet プレハブとシューティングコードの両方が更新される必要があります。

まず、Bullet プレハブはネットワーク上で一意的に特定可能であるためには NetworkIdentity を 1 つ持っている必要があり、また弾の位置と角度の同期のために NetworkTransform も 1 つ必要です。そしてプレハブ自体は、 Spawnable Prefab(生成可能プレハブ) として NetworkManager に登録されている必要があります。

  • Project ウィンドウで Bullet プレハブを選択してください。
  • Bullet プレハブが選択された状態で、
  • ... Network > NetworkIdentity コンポーネントを追加してください。
  • ... Network > NetworkTransform コンポーネントを追加してください。
  • NetworkTransform コンポーネントの Network Send Rate0 に設定してください。

弾は発射された後には速度や方向が変わることがないので、弾から動きの更新を送る必要はありません。各クライアントは弾の位置を正確に算出することができます。Send Rate(送信頻度)を 0 に設定することで位置がネットワークを介して同期されないようにし、各クライアントが弾の位置を計算できるようにすることで、ネットワーク全体の転送量が削減され、ゲームのパフォーマンス向上に繋がります。

description

  • Hierarchy ウィンドウで NetworkManager を選択してください。
  • NetworkManager が選択された状態で、
  • ... Spawn Info のドロップダウンメニューを開いてください。
  • Registered Spawnable Prefabs のリストに、「+」 ボタンで新しい行を追加してください。
  • NetworkManager が選択された状態で、
  • ... Registered Spawnable Prefabs リストの新しい行に Bullet プレハブを追加します。

description

次に、シューティングのコードをネットワークと連携させるために PlayerController スクリプトを更新します。

  • 編集用に PlayerController スクリプトを開きます。

先にプレイヤーの動きをネットワーク化する の項で、マルチプレイヤー ネットワーキング HLAPI を使用したプロジェクトの構造についてご説明しました。その基本的な原理は、サーバーとクライアントの全てが、同じゲームオブジェクトの同じスクリプトの同じコードを同時に実行するというものです。サーバーと複数のクライアントによって共有されるスクリプト内でロジックの流れを制御する手段のひとつとして、isLocalPlayer に対するチェックによって、どのオブジェクトがどのコードを実行できるか設定するという方法をご紹介しました。

もうひとつの制御方法は [Command] 属性です。[Command] 属性は、それに続く関数が、クライアントによって呼び出されてサーバーで実行されることを示します。この関数内の引数はすべて自動的にこの Command と共にサーバーに渡されます。Command はローカルプレイヤーオブジェクトによってのみ送信されます。ネットワークに接続されたコマンドを作成する際は、関数名が“Cmd” から始まる必要があります。[Command] 属性に関する詳細はリモートアクション をご覧ください。

  • Fire 関数に [Command] 属性を追加すると、ネットワークコマンドになります。
  • 関数名にプレフィックス “Cmd” を追加して “CmdFire” に変更してください。
[Command]
void CmdFire()

  • Update 内で呼び出される関数の名前を CmdFire に変更してください。
CmdFire();

次にご紹介する概念は ネットワーク Spawning(生成) です。これは概ねマルチプレイヤーネットワーキング特有の概念です。マルチプレイヤーネットワーキング HLAPI における “Spawn(生成)” とは、単なる “インスタンス化” を意味するものではなく、サーバーおよびそれに接続されたクライアントの全てにゲームオブジェクトを生成することを意味します。生成されたゲームオブジェクトは、Spawn(生成)のシステムによって管理されます。サーバー上でオブジェクトに変更があるとクライアントにステート(状態)の更新が送られ、ゲームオブジェクトがサーバー上で破壊されるとクライアント上でも破壊されます。また、生成されたゲームオブジェクトは、サーバーが管理するネットワーク ゲームオブジェクト一式の中に加えられるので、後に参加した新しいクライアント上にも正しい状態で生成されます。ネットワークにおける Spawn(生成)に関する詳細はオブジェクトの Spawn(生成)をご覧ください。

  • 弾を生成させるために NetworkServer.Spawn 関数を追加してください。
NetworkServer.Spawn(bullet);

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

PlayerController

Code snippet

using UnityEngine;
using UnityEngine.Networking;

public class PlayerController : NetworkBehaviour
{
    public GameObject bulletPrefab;
    public Transform bulletSpawn;

    void Update()
    {
        if (!isLocalPlayer)
        {
            return;
        }

        var x = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
        var z = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;

        transform.Rotate(0, x, 0);
        transform.Translate(0, 0, z);

        if (Input.GetKeyDown(KeyCode.Space))
        {
            CmdFire();
        }
    }

    // この [Command] コードはクライアントに呼び出されますが …
    // … サーバーで実行されます!
    [Command]
    void CmdFire()
    {
        // Bullet Prefab から Bullet を生成する
        var bullet = (GameObject)Instantiate(
            bulletPrefab,
            bulletSpawn.position,
            bulletSpawn.rotation);

        // 弾の速度を増加させる
        bullet.GetComponent<Rigidbody>().velocity = bullet.transform.forward * 6;

        // Client 上に弾を生成する
        NetworkServer.Spawn(bullet);

        // 2 秒後に弾を破壊する
        Destroy(bullet, 2.0f);
    }

    public override void OnStartLocalPlayer ()
    {
        GetComponent<MeshRenderer>().material.color = Color.blue;
    }
}
  • PlayerController スクリプトを保存してください。
  • Unity に戻ってください。

プロジェクトの現在の状態をテストします。

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

スペースキーを押すと、新しい弾のゲームオブジェクトが、全てのクライアント上で正しいプレイヤーに作成されます。各プレイヤーがお互いに射撃することができるはずです。

ただし、弾のゲームオブジェクトは相手プレイヤーに当たると単純に跳ね返るだけで、相手プレイヤー自体に対しては目に見えて分かる影響は与えません。

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

関連ドキュメント