Bolt 105 - オブジェクトと配列

Boltは、オブジェクト配列 という複雑なタイプの組み込み式レプリケーションをサポートしています。これは素のコードC#のそれに非常に近しいものですが、いくつかの点で異なります。オブジェクトBolt Assetsウィンドウで定義され、ステートまたはその他のオブジェクトにおける 配列 または オブジェクトのプロパティに対するタイプとして用いられます。

オブジェクトにより、一群のプロパティのカプセル化のための簡易なメカニズムが得られます。またこれにより、Bolt内の、様々なBoltのステートにまたがって再利用が可能な複雑な階層データを実装可能になります。Bolt内のオブジェクトの使い方について、シンプルなシューティングゲームのための武器スロットを導入するのを例として説明しましょう。(実際にゲームを作成するわけではありません。武器を複製するために、データ構造とステートを作成します)

右クリックメニューを使って、Bolt Assetsウィンドウで新しいオブジェクトを作成しましょう。

Create a new Object Asset
オブジェクトアセットの作成 

オブジェクトに WeaponSlotと名前をつけて、 WeaponIdWeaponAmmoの2つのプロパティを付与してください。 これはどちらも整数でなければなりません。 Bolt 内のオブジェクトは、イベントやステートのようなそれ自体のプロパティを有していません。 オブジェクトは、その他のアセットにも含まれることがあるデータのコンテナとして考えてください。

Configure the new Object Asset
新しいオブジェクトアセットの設定

'CubeState'上に、 WeaponsArrayという新たなプロパティを追加します。このプロパティにはタイプArrayを持ちます。Element TypeObjectに、 Object TypeWeaponSlot に設定されています。これを 3Element Countに付与します。もう1つ、WeaponActiveIndex という名前のプロパティを追加します。これのタイプは Integerです。これはアクティブにする武器のトラッキングに用いられます。

Add WeaponSlot to Cube State
CubeステートにWeaponSlotを追加

重要: Bolt Assets および'Bolt Editor'のウィンドウでの変更を完了したら、Boltをコンパイルするのを忘れないでください。

WeaponsArray プロパティは、これまで作成してきたものの中でも最も複雑です。Bolt は3つの'WeaponSlot'オブジェクトからなる配列を1つ作成し、それを調整し、その全てのデータをネットワーク上に複製することができます。

注意:ここでの 配列 とは、実際のC# WeaponSlot[] 配列のことではありません。Boltには、独自の配列に似たタイプがあり、これによりBoltはオブジェクトに対して行われた変更を容易にトラッキングすることができます。WeaponSlotsプロパティの実際のタイプはBolt.NetworkArray_Objects<WeaponSlot>です。一般には、通常のインデックス化オペレーションはこのクラスで動作し、同じLengthプロパティなどを持つことから、無視しても構いません。

ここで、Cubeプレハブに対するシンプルなプレースホルダーを設定しましょう。プレハブのコピーを何もないシーンにドラッグし、それがシーンの(0, 0, 0)に位置していることを確認してください。新たな spherecapsule および cylinder を(0, 0, 0)の位置に作成し、それらをCubeの子としてください。また、デフォルトのコライダーをそれらから除去し、必ずこれらの3つのオブジェクトを非有効化して、デフォルトでこれらすべてがオフになるようにしてください。これに用いた変換設定は以下の通りです:

Add Weapon representations to Cube Prefab
CubeプレハブにWeapon表示を追加

これにより、現在アクティブとなっている武器を簡単に見分けることができます。Cubeが選択されている状態でApplyを押すか、シーン内のCubeProjectウィンドウ内のCubeプレハブにドラッグし、変更をプレハブにも適用してください。

CubeBehaviourスクリプトの最上部に、WeaponObjectsという新たな変数を追加します。これはUnity GameObjectの配列です。

using UnityEngine;
using System.Collections;

public class CubeBehaviour : Bolt.EntityEventListener<ICubeState>
{
    public GameObject[] WeaponObjects;
    // ...
}

Cubeプレハブのインスペクターに進み、3つ子オブジェクトをWeaponObjects配列インスペクター欄にドラッグしてください。

Drag Weapon object to Cube Behavior Script
WeaponオブジェクトをCube Behavior Scriptにドラッグ

ここで、CubeBehaviour スクリプトに多くの新規コードを追加します。武器のセットアップを適切に行うためAttached内で、それぞれのプレイヤーへの武器をオーナー上で設定する必要があります。また、コールバックに接続し、アクティブな武器スロットが変更になった際に通知を受けられるようにする必要があります。

// ...

public override void Attached()
{
    renderer = GetComponent<Renderer>();

    state.SetTransforms(state.CubeTransform, transform);

    if (entity.isOwner)
    {
        state.CubeColor = new Color(Random.value, Random.value, Random.value);

        // NEW: On the owner, we want to setup the weapons, the Id is set just as the index
        // and the Ammo is randomized between 50 to 100
        for (int i = 0; i < state.WeaponArray.Length; ++i)
        {
            state.WeaponArray[i].WeaponId = i;
            state.WeaponArray[i].WeaponAmmo = Random.Range(50, 100);
        }

        //NEW: by default we don't have any weapon up, so set index to -1
        state.WeaponActiveIndex = -1;
    }

    state.AddCallback("CubeColor", ColorChanged);

    // NEW: we also setup a callback for whenever the index changes
    state.AddCallback("WeaponActiveIndex", WeaponActiveIndexChanged);
}

// ...

if(entity.isOwner)のブロック内には新たなforループが存在します。これにより、3つの武器スロットを初期化することができます。ここでは、Bolt Assetsウィンドウ内の状態上で定義したWeaponArrayプロパティを用います。ランダムに武器オブジェクトのモデルの内の1つを.WeaponIdに割り当て、それから銃弾カウントを50から100の間でランダムに選び、それを.WeaponAmmoに割り当てます。

また .WeaponActiveIndex プロパティを-1に設定します。これは、デフォルトでは武器を持って いない ことを示します。最後に、コールバックを"WeaponActiveIndex"プロパティに追加し、アクティブな武器が変更されたら通知が行われるようにします。

WeaponActiveIndexChangedメソッドは以下のようになります。

void WeaponActiveIndexChanged()
{
    for (int i = 0; i < WeaponObjects.Length; ++i)
    {
        WeaponObjects[i].SetActive(false);
    }

    if (state.WeaponActiveIndex >= 0)
    {
        int objectId = state.WeaponArray[state.WeaponActiveIndex].WeaponId;
        WeaponObjects[objectId].SetActive(true);
    }
}

最初に、全ての武器オブジェクトを無効にしましょう。それから、インデックスが>= 0になっていることを確認します。0以上になっていたら、.WeaponIdをつかみ、それを用いて正しいオブジェクトを表示させます。最後に、SimulateOwner内の標準のUnityインプットをポーリングします。以下を確認してください:

public override void SimulateOwner()
{
    var speed = 4f;
    var movement = Vector3.zero;

    if (Input.GetKey(KeyCode.W)) { movement.z += 1; }
    if (Input.GetKey(KeyCode.S)) { movement.z -= 1; }
    if (Input.GetKey(KeyCode.A)) { movement.x -= 1; }
    if (Input.GetKey(KeyCode.D)) { movement.x += 1; }

    // NEW: Input polling for weapon selection
    if (Input.GetKeyDown(KeyCode.Alpha1)) state.WeaponActiveIndex = 0;
    if (Input.GetKeyDown(KeyCode.Alpha2)) state.WeaponActiveIndex = 1;
    if (Input.GetKeyDown(KeyCode.Alpha3)) state.WeaponActiveIndex = 2;
    if (Input.GetKeyDown(KeyCode.Alpha0)) state.WeaponActiveIndex = -1;

    if (movement != Vector3.zero)
    {
        transform.position = transform.position + (movement.normalized * speed * BoltNetwork.frameDeltaTime);
    }

    if (Input.GetKeyDown(KeyCode.F))
    {
        var flash = FlashColorEvent.Create(entity);
        flash.FlashColor = Color.red;
        flash.Send();
    }
}

完成したCubeBehaviourスクリプトは以下のようになります。

using UnityEngine;
using System.Collections;

public class CubeBehaviour : Bolt.EntityEventListener<ICubeState>
{
    public GameObject[] WeaponObjects;

    float resetColorTime;
    Renderer renderer;

    public override void Attached()
    {
        renderer = GetComponent<Renderer>();

        state.SetTransforms(state.CubeTransform, transform);

        if (entity.isOwner)
        {
            state.CubeColor = new Color(Random.value, Random.value, Random.value);

            // NEW: On the owner, we want to setup the weapons, the Id is set just as the index
            // and the Ammo is randomized between 50 to 100
            for (int i = 0; i < state.WeaponArray.Length; ++i)
            {
                state.WeaponArray[i].WeaponId = i;
                state.WeaponArray[i].WeaponAmmo = Random.Range(50, 100);
            }

            //NEW: by default we don't have any weapon up, so set index to -1
            state.WeaponActiveIndex = -1;
        }

        state.AddCallback("CubeColor", ColorChanged);

        // NEW: we also setup a callback for whenever the index changes
        state.AddCallback("WeaponActiveIndex", WeaponActiveIndexChanged);
    }

    void OnGUI()
    {
        if (entity.isOwner)
        {
            GUI.color = state.CubeColor;
            GUILayout.Label("@@@");
            GUI.color = Color.white;
        }
    }

    void Update()
    {
        if (resetColorTime < Time.time)
        {
            renderer.material.color = state.CubeColor;
        }
    }

    public override void SimulateOwner()
    {
        var speed = 4f;
        var movement = Vector3.zero;

        if (Input.GetKey(KeyCode.W)) { movement.z += 1; }
        if (Input.GetKey(KeyCode.S)) { movement.z -= 1; }
        if (Input.GetKey(KeyCode.A)) { movement.x -= 1; }
        if (Input.GetKey(KeyCode.D)) { movement.x += 1; }

        // NEW: Input polling for weapon selection
        if (Input.GetKeyDown(KeyCode.Alpha1)) state.WeaponActiveIndex = 0;
        if (Input.GetKeyDown(KeyCode.Alpha2)) state.WeaponActiveIndex = 1;
        if (Input.GetKeyDown(KeyCode.Alpha3)) state.WeaponActiveIndex = 2;
        if (Input.GetKeyDown(KeyCode.Alpha0)) state.WeaponActiveIndex = -1;

        if (movement != Vector3.zero)
        {
            transform.position = transform.position + (movement.normalized * speed * BoltNetwork.frameDeltaTime);
        }

        if (Input.GetKeyDown(KeyCode.F))
        {
            var flash = FlashColorEvent.Create(entity);
            flash.FlashColor = Color.red;
            flash.Send();
        }
    }

    void ColorChanged()
    {
        GetComponent<Renderer>().material.color = state.CubeColor;
    }

    void WeaponActiveIndexChanged()
    {
        for (int i = 0; i < WeaponObjects.Length; ++i)
        {
            WeaponObjects[i].SetActive(false);
        }

        if (state.WeaponActiveIndex >= 0)
        {
            int objectId = state.WeaponArray[state.WeaponActiveIndex].WeaponId;
            WeaponObjects[objectId].SetActive(true);
        }
    }

    public override void OnEvent(FlashColorEvent evnt)
    {
        resetColorTime = Time.time + 0.25f;
        renderer.material.color = evnt.FlashColor;
    }
}

ゲームをビルドしサーバーとクライアントを起動すると、キーボード上の12および 3のキーを用いることで武器を選択できます。以下のようになります。

Change Weapons Gameplay
ゲームプレイで武器を変更

現時点では、何に対してもWeaponAmmoを使用していませんが、有用であることがおわかりいただけたと思います。

次章 >>に続きます。

ドキュメントのトップへ戻る