Bolt 105 - オブジェクトと配列
Bolt
は、オブジェクト と 配列 という複雑なタイプの組み込み式レプリケーションをサポートしています。これは素のコードC#のそれに非常に近しいものですが、いくつかの点で異なります。オブジェクト
はBolt Assets
ウィンドウで定義され、ステートまたはその他のオブジェクトにおける配列
またはオブジェクト
のプロパティに対するタイプとして用いられます。
オブジェクトにより、一群のプロパティのカプセル化のための簡易なメカニズムが得られます。またこれにより、Bolt
内の、様々なBoltのステートで再利用できる複雑な階層データを実装できます。Bolt
内のオブジェクトの使い方について、シンプルなシューティングゲームへの武器スロットの導入を例として説明しましょう。ここでは、実際にゲームを作成するわけではありません。武器を複製するために、データ構造とステートを作成します。
右クリックメニューを使って、Bolt Assets
ウィンドウで新しいオブジェクト
を作成しましょう。
オブジェクトにWeaponSlot
と名前をつけて、WeaponId
とWeaponAmmo
の2つのプロパティを付与してください。これらはどちらも整数でなければなりません。Bolt
内のオブジェクトは、イベントやステートのようなそれ自体のプロパティを有していません。 オブジェクトは、その他のアセットにも含まれることがあるデータのコンテナとして考えてください。
CubeState
上に、WeaponsArray
という新たなプロパティを追加します。このプロパティのタイプはArray
に、Element Type
はObject
に、Object Type
はWeaponSlot
に設定します。また、Element Count
は3
に設定します。もう1つ、WeaponActiveIndex
という名前のプロパティを追加し、これのタイプはInteger
に設定します。このプロパティはどの武器がアクティブであるかのトラッキングに用いられます。
重要: Bolt Assets
およびBolt Editor
のウィンドウでの変更を完了したら、Boltをコンパイルするのを忘れないでください。
WeaponsArray
プロパティは、これまで作成してきたものの中でも最も複雑です。Bolt
は3つの'WeaponSlot'オブジェクトからなる配列を1つ作成します。この配列を調整することで、その3つのオブジェクト内のすべてのデータをネットワーク上に自動的に複製することができます。
ここでの 配列 とは、実際のC# WeaponSlot[]
配列のことではありません。Bolt
には、独自の配列に似たタイプがあり、これによりBolt
はオブジェクトに対して行われた変更を容易にトラッキングすることができます。WeaponSlots
プロパティの実際のタイプはBolt.NetworkArray_Objects<WeaponSlot>
です。一般的には通常のインデックス化オペレーションはこのクラスでも動作し、同じLength
プロパティを持つことなどから、多くの場合に無視しても問題ありません。
それでは、Cube
プレハブに簡単なプレースホルダー武器を設定しましょう。プレハブのコピーを何もないシーンにドラッグし、それがシーンの(0, 0, 0)
に位置していることを確認してください。新たな sphere 、 capsule および cylinder を(0, 0, 0)の位置に作成し、それらをCube
の子に設定してください。また、デフォルトのコライダーを削除し、必ず3つのオブジェクトを非有効化して、デフォルトでこれらすべてがオフになるようにしてください。これに用いた変換設定は以下の通りです:
これにより、現在アクティブとなっている武器を簡単に見分けることができます。Cube
が選択されている状態でApply
を押すか、シーン内のCube
をProject
ウィンドウ内のCube
プレハブにドラッグし、変更をプレハブにも適用してください。
スクリプトの修正を開始します。CubeBehaviour
スクリプトの最上部に、UnityGameObject
の配列であるWeaponObjects
という名前の新しい変数を追加します。
C#
using UnityEngine;
using System.Collections;
using Bolt;
public class CubeBehaviour : Bolt.EntityEventListener<ICubeState>
{
public GameObject[] WeaponObjects;
// ...
}
Cube
プレハブのインスペクターに進み、3つの子オブジェクトをWeaponObjects
配列インスペクター欄にドラッグしてください。
これから、 CubeBehaviour
スクリプトに多くの新規コードを追加します。武器のセットアップを適切に行うため Attached
内で、それぞれのプレイヤーへの武器をオーナー上で設定する必要があります。また、コールバックに接続し、アクティブな武器スロットが変更になった際に通知を受けられるようにする必要があります。
C#
// ...
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
メソッドは以下のようになります。
C#
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インプットをポーリングします。以下を参照してください:
C#
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
スクリプトは、以下のとおりです。
C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Bolt;
public class CubeBehaviour : Bolt.EntityEventListener<ICubeState>
{
public GameObject[] WeaponObjects;
private float _resetColorTime;
private 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);
}
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();
}
}
public override void OnEvent(FlashColorEvent evnt)
{
_resetColorTime = Time.time + 0.2f;
_renderer.material.color = evnt.FlashColor;
}
void Update()
{
if (_resetColorTime < Time.time)
{
_renderer.material.color = state.CubeColor;
}
}
void OnGUI()
{
if (entity.IsOwner)
{
GUI.color = state.CubeColor;
GUILayout.Label("@@@");
GUI.color = Color.white;
}
}
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);
}
}
}
ゲームをビルドしサーバーとクライアントを起動すると、キーボード上の1
、2
および3
のキーを用いることで武器を選択できます。以下のようになります。
現時点では、何に対してもWeaponAmmo
プロパティを使用していませんが、有用であることがおわかりいただけたと思います。
次章 >>に続きます。
Back to top