C#スクリプトAPIについて¶
Strix Unity SDKには一式のC#スクリプトAPIがあります。このページでは、スクリプトを使用する上での共通概念とヒントを説明します。
StrixBehaviourクラス¶
Unityでは、スクリプトコンポーネントを作成する場合、クラスをMonoBehaviour
クラスから派生させます。Strix Unity SDKでは、Strixの機能を利用するスクリプトコンポーネントを作成する場合、クラスをStrixBehaviour
クラスから派生させます。
StrixBehaviour
はMonoBehaviour
の派生クラスなので、StrixBehaviour
から派生したクラスはMonoBehaviour
が提供する全ての機能(例えばGameObjectにアタッチできるようになること)に加えてStrixBehaviour
に特有の機能が利用できます。
StrixBehaviour
から派生したスクリプトをGameObjectにアタッチするときには、StrixReplicator
コンポーネントもアタッチする必要があります。StrixBehaviour
にはstrixReplicator
プロパティがあり、これを使ってGameObjectにアタッチされているStrixReplicator
コンポーネントを参照できます。これはちょうど、transform
プロパティを使ってTransform
コンポーネントにアクセスできるのと同様です。StrixBehaviour
には同様な簡略プロパティがもう2つあります。isLocal
とisSync
です。両者はStrixReplicator
の同じ名前のプロパティを参照します。
StrixNetworkシングルトンクラス¶
StrixNetwork
シングルトンクラスは、StrixのスクリプトAPIへの主要なエントリポイントを提供します。通常通り、instance
プロパティを使用してこのクラスのシングルトンインスタンスを取得し、それを用いてクラスの他のメンバーにアクセスします。
このクラスはSoftGear.Strix.Unity.Runtime
名前空間に属しています。
例えば:
using SoftGear.Strix.Unity.Runtime;
// 何らかのメソッドの内部、例えば Start()
StrixNetwork.instance.applicationId = "00000000-0000-0000-0000-000000000000";
StrixNetwork.instance.ConnectMasterServer(
"000000000000000000000000.game.strixcloud.net",
OnConnectMasterCallback,
OnConnectMasterFailedCallback
);
非同期処理¶
StrixのスクリプトAPIには非同期に実行されるメソッドが多数あります。それらのメソッドはネットワーク操作を伴うため長い時間がかかることがありますが、その間Unityのメインスレッドをブロックするわけにはいかないからです。
このような非同期操作をStrix Unity SDKはコールバックハンドラーによって実現します。
注釈
Strix Unity SDKでは、これらのコールバックをしばしばイベントと呼びますが、これらは実際には単に普通のデリゲートです。C#の文法用語の「イベント」や、UnityのUnityEvent
と混同しないように注意してください。
なお、Strixのクラスの中には、C#の文法用語の意味でのイベントをメンバーとして持っているものもあります。
ネットワーク操作を行う一般的なStrixのメソッドは、引数リスト内にデリゲートを2つ持っています。これらのデリゲートを一般に「成功コールバックハンドラー」と「失敗コールバックハンドラー」と呼びます。そのようなメソッドを呼び出すと、メソッドはネットワーク操作の完了前に戻ります。後になって、操作が完了したときに、いずれか一方のデリゲートが起動されます。操作が成功した場合には成功コールバックが起動され、それ以外の場合には失敗コールバックが起動されます。
コールバックハンドラーのデリゲートの型はさまざまですが、それらは大抵パラメーターを1つ受け取り、その型の名前は最後がEventArgs
になっています。また結果は返しません(void
)。コールバックハンドラーがパラメーターとして受け取るオブジェクトには、普通(必ず、というわけではありませんが)、ネットワーク操作の結果を示す(単なる成功か失敗以上の)情報が含まれています。
例えば、ConnectMasterServer
メソッドの失敗コールバックハンドラーの型はStrixNetworkConnectFailedEventHandler
ですが、これは次のように定義されています。
public delegate void StrixNetworkConnectFailedEventHandler(
StrixNetworkConnectFailedEventArgs args
);
ここに、StrixNetworkConnectFailedEventArgs
は、cause
(型はException
)とsession
(型はAbstractSession
)という2つのプロパティを持つクラスです。
ダウンキャスト¶
Strixサーバーの特長の一つは柔軟にカスタマイズできることです。(残念ながら、Strix Cloudで動作するStrixサーバーはカスタマイズできません。カスタマイズしたStrixサーバーを利用するためにはSTRIX ENGINE製品が必要です。)カスタマイズしたサーバーを活用するためには、クライアント側にも同レベルの柔軟性が必要になります。
スクリプトAPIの多くの部分は一般的な定義になっており、しばしばジェネリックスを使用していますが、その一つの目的は柔軟性を得ることです。それらが使用する型はしばしばインターフェイス型か抽象クラスとして定義されています。ただし、そのようなオブジェクトを具象クラスにダウンキャストすることで、宣言上の型よりも多くのメンバーにアクセスすることができます。ときには、オブジェクトが具象クラスとして宣言されている場合にも同じようにダウンキャストが可能なことがあります。
例えば、失敗コールバックに渡される引数には大抵cause
という名前のプロパティがあり、Exception
型として定義されています。定義上はException
ですが、これは大抵ErrorCodeException
型(SoftGear.Strix.Unity.Runtime.Error
名前空間に定義されています)にダウンキャストできて、こちらのクラスにはエラーの原因を示すerrorCode
プロパティがあります。
例えば:
void OnConnectMasterFailedCallback(StrixNetworkConnectFailedEventArgs args)
{
if (args.cause is ErrorCodeException
&& ((ErrorCodeException)args.cause).errorCode == StandardErrorCode.ConnectionError)
{
// この特定のエラーに関する特別な処理
}
else
{
// 通常のエラー処理
}
}
エラーコードの詳細についてはエラーコードを参照してください。
インターフェイス¶
Strix Unity SDKはStrix自身のインターフェイスを多数使用しますが、その中には名前が「 I 」から始まらないものがある点に注意してください。その一例はSoftGear.Strix.Client.Core.UID
インターフェイスです。これはさまざまなオブジェクトの一意識別子を表します。(RoomInfo.nodeUid
プロパティの型や、IRoomMember.GetUid()
メソッドの戻り値など、いくつかの場面で使われています。)これらの、名前が「 I 」以外の文字で始まるインターフェイスを意識してください。
ところで、なぜインターフェイスだと意識する必要があるのでしょうか?…それは、よく間違える落とし穴があるからです。
何らかの比較可能な値を表すクラスでは、==
と!=
の演算子をオーバーライドして、プログラマーがそれらのオブジェクトを直観的な書き方で比較できるようにしていることがよくあります。しかし、C#言語の制約により(先頭の文字とは無関係に)、インターフェイスでは「等しい」「等しくない」の演算子をオーバーライドすることができません。
そのため、例えば2つのUID
オブジェクトを比較する際には、==
演算子を使うことができません。なぜなら、この演算子は2つのオブジェクトのリファレンスが等しいかどうかを比較するので、同一のIDを表していてもUID
オブジェクトが異なるとfalse
になってしまうからです。その代わりに、次の例の2番目のif
文のようにEquals
メソッドを使用する必要があります。
private UID uid;
// StrixNetwork::GetRoomMembersのハンドラー。
void OnRoomMembersGot(RoomMemberGetEventArgs args)
{
foreach (var member in args.roomMemberCollection)
{
UID memberUid = member.GetUid();
// この比較は期待したようには動作しません。
// リファレンスが等しいかどうかを比較してしまうからです。
if (memberUid == uid)
{
// 何らかの処理を行う。
}
// 代わりにこうしてください。
if (memberUid.Equals(uid))
{
// 何らかの処理を行う。
}
}
}