ご留意ください:Photon TrueSyncとThunderの開発は停止されており、今後はアップデートもパリリースされません。既存のアプリケーションへの影響はありませんが、現在開発中のアプリケーションについてはマイグレーションを推奨しています。

TrueSync チュートリアル セクション3

チュートリアルの内容

このチュートリアルのシリーズでは、Photon TrueSyncを使ってUnityでシンプルなマルチプレイヤーゲームを作る方法を説明します。セクション1と2では、Photonに接続するための基本的な設定とコード、および異なるゲームクライアント間で決定論的な動きをする物理ベースのプレーヤ制御ゲームオブジェクトを作成する方法について説明しました。

セクション3の内容:

発射物を動的にインスタンス化および破壊することができる、マルチプレイヤーゲームクライアント。プレイヤーはインターネット上で完全に同期したスコアを維持しながらボックスを動かし、お互いを撃つことができます。

同期プレハブインスタンシエーション/破棄

プレイヤープレハブは出発点としては良いですが、ゲーム内の挙動に基づいてリアルタイムでオブジェクトを作成する必要があるかもしれません。確定論的なロックステップシミュレーションでは、コードはすべての単一フレームの最後に同じ結果を出す必要があるため、TrueSyncはゲームオブジェクトのインスタンス化と破壊を制御する必要があります。

例として、プレイヤーがUnityからの "Fire1"デフォルト入力を押すたびにインスタンス化される発射体プレハブを作成します。

まず、新しいTrueSync sphere (Game Object/TrueSync/Sphere) をゲームシーンに作成し、それを「Tutorial」フォルダ内の新しいプレハブにドラッグします。

インスペクタでプレハブを編集し、TSRigidbodyコンポーネントを削除し、TSSphereColliderをトリガにするために適切なトグルにチェックを入れます(下図参照)。

Sphere inspector
インスペクタ上のsphereコンポーネント。

プレハブの名前を "ProjectilePrefab"に変えてください。必ずシーンからゲームオブジェクトを削除して保存してください(必要なのはプレハブのみです)。

新しいC#スクリプトを作成し、 "PlayerWeapon.cs"と名付けます。それを編集して、プレイヤーの動きを制御するものと同様、 "TrueSyncBehavior"から継承させます。新しいスクリプトで以前に作成した射影プレハブにも参照を追加しましょう。コードは以下のようになります。

C#

using UnityEngine;
using System.Collections;
using TrueSync;

public class PlayerWeapon : TrueSyncBehaviour {

    public GameObject projectilePrefab;

}

チュートリアルの最後に作成した "PlayerBox"プレイヤープレハブにこのスクリプトを添付します。これで、このプレハブに2つのカスタムスクリプト:移動用と、武器制御用が追加されました。

ProjectilePrefabをプロジェクトタブから "PlayerWeapon"スクリプトのスロットにドラッグします。プレーヤプレハブのインスペクタは、次の図のようになります。

Player weapon on inspector
Inspector上のプレイヤーの武器。

PlayerWeapon.csスクリプトは "PlayerMovement.cs"と似た構造になっているので、 "OnSyncedInput"メソッドで射撃入力を収集してキューに入れ、"OnSyncedUpdate"メソッドで武器を撃ち、cooldown変数を更新します。

入力には、プレイヤーが「Fire1」ボタンを押したこと(押していないときは0をキュー、押しているときは1)を示すbyteをキューに入れるだけです。 "PlayerWeapon.cs"に以下のコードを追加してください。

C#

public override void OnSyncedInput() {
    if (Input.GetButton("Fire1"))
        TrueSyncInput.SetByte (2, 1);
    else
        TrueSyncInput.SetByte (2, 0);
}

移動入力値(accellとsteer)にすでにキー0と1を使用しているので、この入力値はキー2の値で登録します。

プレイヤーが射撃ボタンを押して、cooldown変数で許可されている場合、TrueSyncは都度、投射プレハブのコピーをインスタンス化します。それを "PlayerWeapon.cs"スクリプトに追加します。

C#

private FP cooldown = 0;

public override void OnSyncedUpdate () {
    byte fire = TrueSyncInput.GetByte (2);
    if (fire == 1 && cooldown <= 0) {
        TrueSyncManager.SyncedInstantiate (projectilePrefab, tsTransform.position, TSQuaternion.identity);
        cooldown = 1;
    }
    cooldown -= TrueSyncManager.DeltaTime;
}

cooldown変数はFixedPoint数であり、"DeltaTime"のTrueSyncのバージョン によってデクリメントされるので、コード全体が確定論的になります。

弾丸を動かす

次に、発射体を順方向に移動させ、それが相手プレイヤーのボックスに当たったとき、またはしばらくしてから、破壊する必要があります。このために、新しいC#スクリプトを作成し、それを "Projectile.cs"と呼びます。他と同様、以下のように "TrueSyncBehaviour"から継承させます。

C#

using UnityEngine;
using System.Collections;
using TrueSync;

public class Projectile : TrueSyncBehaviour {

}

このスクリプトを発射体プレハブに添付します。次に、いくつかの属性を追加する必要があります:

  • speed:発射体の移動速度を設定するため(これはFixedPoint数でなければなりません)。
  • direction:現在の順方向を格納するTSVector。これにより、発射体はその方向に動きます。
  • destroyTime (private):この発射体がまだ動いている時間を記録するもう1つのFP。ある程度の時間が経過したらが破壊するため。

これらの属性と移動コードを備えた "Projectile.cs"スクリプトは、次のようになります:

C#

using UnityEngine;
using System.Collections;
using TrueSync;

public class Projectile : TrueSyncBehaviour {

    public FP speed = 15;
    public TSVector direction;
    private FP destroyTime = 3;

    public override void OnSyncedUpdate () {
        if (destroyTime <= 0) {
            TrueSyncManager.SyncedDestroy (this.gameObject);
        }
        tsTransform.Translate (direction * speed * TrueSyncManager.DeltaTime);
        destroyTime -= TrueSyncManager.DeltaTime;
    }

}

また、「PlayerWeapon.cs」で発射体をインスタンス化するコードを次のように更新する必要があります。

C#

public override void OnSyncedUpdate () {
    byte fire = TrueSyncInput.GetByte (2);
    if (fire == 1 && cooldown <= 0) {
        GameObject projectileObject = TrueSyncManager.SyncedInstantiate (projectilePrefab, tsTransform.position, TSQuaternion.identity);

        Projectile projectile = projectileObject.GetComponent<Projectile> ();
        projectile.direction = tsTransform.forward;
        projectile.owner; = owner;

        cooldown = 1;
    }
    cooldown -= TrueSyncManager.DeltaTime;
}

次に、発射体が移動する方向を設定し、この発射体が所属するプレイヤー(TrueSyncのカスタムownerID)をマークします(これは、次のセクションで発射体のターゲットを識別するために使用されます)。

物理コールバックとスコア

発射体がプレイヤーのボックスに当たったことを識別し、それに応じて反応をさせるコードが必要です。 TrueSyncの物理エンジンには、「OnSyncedCollision [Enter / Stay / Exit]」や「OnTrigger [Enter / Stay / Exit]」などの、Unityのコールバックと同じようなコールバックがあります。

発射されたプレハブコライダーをトリガーとしてマークしたため、OnSyncedTriggerEnterを使用します。"Projectile.cs"に次のコードを追加します。

C#

public void OnSyncedTriggerEnter(TSCollision other) {
    if (other.gameObject.tag == "Player") {
        PlayerMovement hitPlayer = other.gameObject.GetComponent<PlayerMovement> ();
        if (hitPlayer.owner != owner) {
            TrueSyncManager.SyncedDestroy (this.gameObject);
            hitPlayer.Respawn ();
        }
    }
}

上記のコードは、 "Player"タグが設定されている他のTrueSync物理オブジェクトと、異なるオーナーにのみ影響します。つまり、敵プレイヤーのボックスにのみ当たります。

発射体を破壊するだけでなく、ヒットしたボックスの "PlayerMovement.cs"スクリプトへの参照を取得し、そこに新しいメソッド( "Respawn")を呼び出します。

このメソッドは、ヒットしたプレイヤーボックスをどこかでランダムにrespawnし、得た死亡数を増やします。これを「PlayerMovement.cs」に追加します。

C#

public int deaths = 0;

public override void OnSyncedStart () {
    tsTransform.position = new TSVector (TSRandom.Range(-5,5), 0, TSRandom.Range(-5,5));
}

public void Respawn() {
    tsTransform.position = new TSVector (TSRandom.Range(-5,5), 0, TSRandom.Range(-5,5));
    deaths++;
}

また、 "OnSyncedStart"コールバックに同じランダムなspawnコードを追加したので、すべてのプレイヤーは開始時に別の場所に配置されます。

プレイヤーからの入力値を除き、ネットワーク自体で何も同期されていないので、TrueSyncゲームはすべてのコンピュータで全く同じように実行されているすべての計算に依存します。

ゲームのスコアを確認できるようにするには、次のGUIコードを「PlayerMovement.cs」に追加します。

C#

void OnGUI() {
    GUI.Label (new Rect(10, 100 + 30 * owner.Id, 300, 30), "player: " + owner.Id + ", deaths: " + deaths);
}

テストの実行

両方のシーン (Tutorial/Menu とTutorial/Game) がビルド設定に含まれていること、また、Tutorial/Menuが最初のシーン(起動時にUnityが読み込むもの)であることを確認してください。

任意のビルドを作成し、1つ、または2つのコピーを実行して、Unityエディタ内からMenuシーンを実行します。

これで、両方のクライアントがPhotonに接続して、各クライアントが独自のボックスを制御し、互いに射撃し合うゲームシーンが読み込まれます。

それではセクション4に移動して、ロールバックを持つプレイヤーからレイテンシーを隠す方法を学びましょう。

Back to top