Unity によるクライアント実装例を紹介します。。
このチュートリアルでは、Unityについての基本的な知識を持つユーザーを前提条件としているため、Unityの説明は割愛します。
Unity 版クライアントの仕様
Unity 版クライアントの大まかな機能は、次のとおりです。
- ルーム一覧の取得
- ルームを選択して入室
- ルームの他の人の発言を見るビューワー(メッセージの購読)
- ルームに発言
- ルームから退室
開発環境の説明
MAGELLAN Client SDK for Unityを使用するには、以下の環境が必要となります。
Unity4のエディタ上で実行する場合のみUnity Proライセンスが必要となります。
サンプルアプリのダウンロード
Unityで簡単にお試しいただけるように、サンプルアプリのソースコードを用意しました。サンプルアプリでは、Unity4.6から搭載されているUIシステムを使用しています。
サンプルアプリソースコード一式
サンプルアプリのソースコード一式は、GitHub で公開しています。
MAGELLAN Client SDK for Unity の導入手順
MAGELLAN Client SDK for Unity の導入手順については以下のドキュメントを参照してください。
接続情報の確認
MAGELLAN にアクセスするためには、 consumer_key
と consumer_secret
が必要となります。これらの情報は、magellan-cli
の project list で確認できます。
$ magellan-cli project list
+---+----+--------------+-----------+----------+-----------------+----------------------------------+
| * | id | organization | name | icon_url | consumer_key | consumer_secret |
+---+----+--------------+-----------+----------+-----------------+----------------------------------+
| * | 3 | MyOrg | MyProject | | MyOrg.MyProject | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+---+----+--------------+-----------+----------+-----------------+----------------------------------+
Total: 1
ビルド設定
サンプルアプリでは、Sceneの移動を行うため、Build Settings
にSceneを追加します。
Unityメニューの File
> Build Settings...
を選択すると、ビルド設定のウィンドウが開きます。
ビルドの際に含めるScene の編集リストがポップアップ表示されます。
プロジェクトビューからRooms.unity
、RoomChat.unity
、Users.unity
をドラッグしてきて Scene In Build
に入れます。
接続情報の設定
MAGELLAN にアクセスするための情報を定義します。
サンプルアプリでは、Assets/Scripts/MagellanSettings.cs
に定数として定義しています。
using Magellan;
public class MagellanSettings
{
// 接続先
public const string HTTP_SERVER_HOST = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
// 接続先ポート
public const int HTTP_SERVER_PORT = XXX;
// MAGELLANのConsumer Key
public const string CONSUMER_KEY = "XXXXXXXXX";
// MAGELLANのConsumer Secret
public const string CONSUMER_SECRET = "XXXXXXXXXX";
// MQTT接続先
public const string MQTT_SERVER_HOST = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
// MQTT接続先ポート
public const int MQTT_SERVER_PORT = XXXX;
// PubSub KeepAlive設定時間
public const int PUBSUB_KEEP_ALIVE = 30;
// WorkerのURIスキーム
public const BaseRequest.SchemeType SCHEME_TYPE = BaseRequest.SchemeType.HTTPS;
// クライアントバージョン
public const string CLIENT_VERSION = "0.0.1";
}
MAGELLAN にアクセスするときのサーバー情報(ホスト・ポート)については、「サーバー情報」を参照して設定してください。また、Consumer key、Consumer Secret については、「接続情報の確認」で確認した接続先を設定してください。
ルーム一覧の取得
Worker で実装したルーム一覧取得 API /rooms
を呼び出してルーム一覧を取得します。
ルームの一覧を表示するSceneは Assets/Scenes/Rooms.unity
となります。
Rooms.unity
を開くと、Hierarchyビューにゲームオブジェクトが展開されます。
この中のScriptオブジェクトにアタッチされているRoomList.cs
を開きます。
Magellan システムを構成する各種クラスは Magellan名前空間
に定義されています。usingでMagellanを指定します。
using Magellan;
MagellanSettings.csで定義した接続先のホスト
、ポート
、Consumer Key
、Consumer Secret
を指定して、MAGELLANのクライアントハンドルを生成します。
クライアントハンドル生成は、Managerクラスの CreateClient メソッドで行われます。
ここでは、Start()
でクライアントハンドル生成を行っています。
クライアントハンドルが生成されると、返り値としてクライアントハンドルが得られます。クライアントハンドルは、後の処理で使うので、メンバ変数に格納しておきます。
// クライアントの作成
workerHandle = Manager.Instance.CreateClient(MagellanSettings.HTTP_SERVER_HOST, MagellanSettings.HTTP_SERVER_PORT, MagellanSettings.CONSUMER_KEY, MagellanSettings.CONSUMER_SECRET, false);
Workerへアクセスする場合は初めに、Managerクラス
の InitializeWorker メソッドから初期化を実行する必要があります。
引数には、クライアントハンドルとアクセスするWorkerのクライアントバージョンを指定します。
// Workerの初期化
Manager.Instance.InitializeWorker (workerHandle, MagellanSettings.CLIENT_VERSION);
それでは、Workerからルームの一覧を取得します。
SetRoomList メソッドで、Workerからデータを取得し、画面に表示するという一連の処理を行っています。
void SetRoomList ()
{
// GET /rooms/ (ルームの一覧)へのリクエスト用インスタンスの生成
Worker worker = new Worker("rooms/", BaseRequest.MethodType.Get, BaseRequest.ProtocolType.General, MagellanSettings.scheme);
// レスポンスコールバック
worker.ResponseCallback = (_worker) =>
{
// 結果の取得
string responseData = System.Text.Encoding.UTF8.GetString(_worker.Response);
if (! String.IsNullOrEmpty(responseData)) {
IList roomList = (IList)Json.Deserialize (responseData);
Dictionary<int, string> rooms = new Dictionary<int, string>();
foreach(IDictionary room in roomList)
{
rooms.Add(int.Parse(room["id"].ToString()), (string)room["name"]);
}
if (rooms.Count > 0)
SetContent(rooms);
}
}
// エラーコールバック
worker.ErrorCallback = (req) =>
{
Debug.Log(String.Format("Request Error. Error Code: {0}.", req.ErrorCode.ToString()));
}
// Worker リクエスト送信
Manager.Instance.SendWorkerRequest (workerHandle, worker);
}
SetRoomList メソッドで行っている、Workerへアクセスする際の手順を解説していきます。
Workerへアクセスするには、Workerクラス
を使用します。
APIのURLディレクトリ部
、リクエストメソッド
、プロトコル
、スキーム
を指定して、リクエスト用の Workerインスタンス を作成します。
Worker worker = new Worker("rooms/", BaseRequest.MethodType.Get, BaseRequest.ProtocolType.General, MagellanSettings.scheme);
Workerインスタンス
には、レスポンス受信時に実行されるコールバックをデリゲートとして設定出来ます。
サンプルアプリでは、ResponseCallback
が受け取る引数_worker
から、結果を取得し、データを画面へ表示するSetContent関数へ渡すというコールバック処理をデリゲートとして設定しています。
worker.ResponseCallback = (_worker) =>
{
// 結果の取得
string responseData = System.Text.Encoding.UTF8.GetString(_worker.Response);
.
.
.
}
また、エラーが発生した際のコールバックもデリゲートして設定出来ます。
Workerインスタンスの ErrorCallback
が受け取る引数req
から、エラーコードが取得出来ます。
worker.ErrorCallback = (req) =>
{
Debug.Log(String.Format("Request Error. Error Code: {0}.", req.ErrorCode.ToString()));
}
リクエストの送信は、Manegerクラスを通じて行われます。Managerクラスの SendWorkerRequest メソッドに、引数としてWorkerインスタンスを指定します。
Manager.Instance.SendWorkerRequest (workerHandle, worker);
これで、MAGELLANにアクセスしてルームの一覧が取得できました。
ルーム選択と入室
入室 API /rooms/:room_id/users
はルーム ID と入室ユーザの名前を指定して、POST でリクエストを送信します。
入室処理は JoinRoom メソッドで行っています。
void JoinRoom()
{
// POST: /rooms/:room_id/users (ルームへの入室)へのリクエスト用インスタンスの生成
Worker worker = new Worker(String.Format("rooms/{0}/users", PlayerPrefs.GetInt("SelectRoomId")), BaseRequest.MethodType.Post, BaseRequest.ProtocolType.General, MagellanSettings.SCHEME_TYPE);
// ユーザー名をPostデータに指定
worker.AddPostData ("name", PlayerPrefs.GetString("Username"));
// レスポンスコールバック
worker.ResponseCallback = (_worker) =>
{
string responseDate = System.Text.Encoding.UTF8.GetString(_worker.Response);
if (! String.IsNullOrEmpty(responseDate)) {
Dictionary<string, object> result = Json.Deserialize (responseDate) as Dictionary<string, object>;
if ((bool)result["result"]) {
Application.LoadLevel("RoomChat");
} else {
Debug.Log(String.Format("Could not Join Room. error: {0}", result["error"].ToString()));
}
}
};
// エラーコールバック
worker.ErrorCallback = (req) =>
{
Debug.Log(String.Format("Request Error. Error Code: {0}.", req.ErrorCode.ToString()));
};
// Worker リクエスト送信
Manager.Instance.SendWorkerRequest (workerHandle, worker);
}
簡易なバリデーションチェックを行なった後、必要なパラメータ(name
)を POST で送信します。
POSTデータは、Workerインスタンス
へ付加することが出来ます。
worker.AddPostData ("name", PlayerPrefs.GetString("Username"));
レスポンスをチェックして、reuslt
が true
の場合は正常に入室できているので、チャット画面(RoomChat.unity
)へ遷移します。
result
が false
のときは、入室に失敗しているのでその旨を表示します。
Subscribe の開始
入室に成功すると、チャット画面に遷移できました。
チャット画面のSceneは、Assets/Scenes/RoomChat.unity
となります。
RoomChat.unity
を開いてみましょう。
ヒエラルキーに表示される内容は、Rooms.unityと同じ構成となっているため、説明は割愛します。
入室したという情報だけでは、実際にそのルームのメッセージを受け取ることはできません。
入室に成功したら、PubSubへの接続処理とメッセージの購読(Subscribe)を開始するようにします。
ScriptオブジェクトにアタッチされているChat.cs
を見てみましょう。
PubSubへの接続開始は BeginPubSubConnect メソッドで行っています。
void BeginPubSubConnect()
{
// PubSub用のクライアントの作成
pubsubHandle = Manager.Instance.CreateClient(MagellanSettings.MQTT_SERVER_HOST, MagellanSettings.MQTT_SERVER_PORT, MagellanSettings.CONSUMER_KEY, MagellanSettings.CONSUMER_SECRET, false);
// PubSubを初期化
Manager.Instance.InitializePubSub(pubsubHandle, MagellanSettings.CLIENT_VERSION);
// PubSub接続
Manager.Instance.ConnectPubSub(pubsubHandle, MagellanSettings.PUBSUB_KEEP_ALIVE, OnPubSubConnect, OnPubSubDisconnect);
topic = String.Format (topic, PlayerPrefs.GetString("RoomName"));
}
BeginPubSubConnect メソッドで行っている、Subscribeを開始する手順を解説していきます。
PubSub用のクライアントハンドル生成は、Managerクラスの CreateClient メソッドで行われます。
引数には、MagellanSettings.csで定義したMQTT_SERVER_HOST
、MQTT_SERVER_PORT
を指定します。
返り値として得たクライアントハンドルをメンバ変数に格納しておきます。
pubsubHandle = Manager.Instance.CreateClient(MagellanSettings.MQTT_SERVER_HOST, MagellanSettings.MQTT_SERVER_PORT, MagellanSettings.CONSUMER_KEY, MagellanSettings.CONSUMER_SECRET, false);
PubSubを使用する場合は初めに、Managerクラスの InitializePubSub メソッドで初期化を実行する必要があります。 引数には、クライアントハンドル、MagellanSettings.csで定義したCLIENT_VERSIONを指定します。
Manager.Instance.InitializePubSub(pubsubHandle, MagellanSettings.CLIENT_VERSION);
初期化処理を実行し、Managerクラスの ConnectPubSub メソッドでサーバーへ接続します。 引数には、クライアントハンドル、MagellanSettings.csで定義したPUBSUB_KEEP_ALIVEを指定します。サンプルアプリでは、続く引数に接続時、切断時に実行されるコールバックを指定しています。
Manager.Instance.ConnectPubSub(pubsubHandle, MagellanSettings.PUBSUB_KEEP_ALIVE, OnPubSubConnect, OnPubSubDisconnect);
ConnectPubSub で指定されているコールバックを見てみましょう。
PubSub接続時のコールバック OnPubSubConnect
では、クライアントハンドルと接続ステータスを引数に取ります。
接続が成功した場合、Subscriberを登録する RegisterSubscriber メソッドをコールします。
// PubSub接続コールバック
void OnPubSubConnect(ClientHandle clientHandle, Manager.PubSubConnectStatus status)
{
if (Manager.PubSubConnectStatus.Success == status) {
RegisterSubscriber();
}
}
PubSub切断時のコールバックOnPubSubDisconnect
も、接続時のコールバックと同様に、クライアントハンドルと切断ステータスを引数に取ります。
// PubSub切断コールバック
void OnPubSubDisconnect(ClientHandle clientHandle, Manager.PubSubDisconnectStatus status)
{
if (Manager.PubSubDisconnectStatus.Expected == status) {
if (transition.ContainsKey(pushObject.name)){
Application.LoadLevel (transition[pushObject.name]);
}
}
}
次に、メッセージの購読(Subscribe)を開始します。 Subscriberを登録している RegisterSubscriber メソッドを見てみましょう。
// Subscriber登録要求
void RegisterSubscriber()
{
// インスタンス生成
PubSub_Subscriber sub = new PubSub_Subscriber(topic, PubSubQos.FireAndForget);
// メッセージ受信時のコールバック
sub.SubscribeCallback = (_sub, _topic, _message) =>
{
SetContent(System.Text.Encoding.UTF8.GetString(_message));
};
// 登録解除完了時に実行
sub.UnRegisterCallback = (_sub) =>
{
// PubSub切断
Manager.Instance.DisconnectPubSub(pubsubHandle);
};
// 登録完了時に実行
sub.RegisterCallback = (_sub) =>
{
Debug.Log("Register Success Subscribe");
};
// 登録
subscribeHandle = Manager.Instance.RegisterPubSub_Subscriber(pubsubHandle, sub);
}
メッセージをSubscribeするには、PubSub_Subscriberクラス
を使用します。
Subscribeする Topic
と QoS
を指定して PubSub_Subscriberインスタンス を生成します。
PubSub_Subscriber sub = new PubSub_Subscriber(topic, PubSubQos.FireAndForget);
PubSub_Subscriberインスタンス
には、以下のコールバックをデリゲートとして設定出来ます。
- RegisterCallback() Subscriberの登録完了時のコールバック
- SubscribeCallback() メッセージ受信時のコールバック
- UnRegisterCallback() Subscriber登録解除時のコールバック
サンプルアプリでは、SubscribeCallback
で、引数に取ってきた_message
を、SetContent メソッドに渡し、メッセージを画面に表示します。
sub.SubscribeCallback = (_sub, _topic, _message) =>
{
SetContent(System.Text.Encoding.UTF8.GetString(_message));
}
PubSub_Subscriberの登録は、Manegerクラスを通じて行われます。 RegisterPubSub_Subscriber メソッドに、生成したPubSub_Subscriberインスタンスを渡すことで、Subscriberが登録されます。
subscribeHandle = Manager.Instance.RegisterPubSub_Subscriber(pubsubHandle, sub);
これで、Subscriberの登録が行われ、メッセージが受信出来るようになりました。
ルームに発言する
Subscribeが開始されたので、次はルームに発言(publish)してみましょう。
ルームへの発言はChat.cs
内の PublishMessage で行っています。
// Publishリクエスト
void PublishMessage()
{
var data = BuildMessageData();
if (String.IsNullOrEmpty(data)) {
return;
}
//インスタンス生成
PubSub_Publish req = new PubSub_Publish(topic, PubSubQos.FireAndForget, System.Text.Encoding.UTF8.GetBytes(data));
//リクエスト送信
Manager.Instance.SendPubSub_PublishRequest(pubsubHandle, req);
}
string BuildMessageData()
{
InputField inputField = inputMessage.GetComponent<InputField> ();
string Message = String.Empty;
if (! String.IsNullOrEmpty (inputField.text)) {
Dictionary<string, string> dict = new Dictionary<string, string>();
dict["user"] = PlayerPrefs.GetString("Username");
dict["message"] = inputField.text;
dict["date"] = DateTime.Now.ToString("MM/dd HH:mm");
Message = Json.Serialize(dict);
}
inputField.text = String.Empty;
return Message;
}
BuildMessageData から、画面のテキストフォームに入力されたメッセージを取得します。 サンプルアプリでは、ユーザ名、発言時刻も表示するため、JSONデータに変換しています。
メッセージをPublishするには、PubSub_Publishクラス
を使用します。
Publish 対象の Topic
、QoS
、Publish するメッセージ
を指定して PubSub_Publishインスタンス を生成します。
PubSub_Publish req = new PubSub_Publish(topic, PubSubQos.FireAndForget, System.Text.Encoding.UTF8.GetBytes(data));
Publishの送信は、Manager クラスを通じて行われます。 SendPubSub_PublishRequest メソッドに、PubSub_Publishインスタンスを指定し、リクエストを送信します。
Manager.Instance.SendPubSub_PublishRequest(req);
テキストフォームにメッセージを入力して、送信してみましょう。
ルームから退出する
次にルームから退出する処理を見てみましょう。 ルームの退出処理は、Chat.cs内の LeaveRoom メソッドで行っています。
// ルーム退出
void LeaveRoom()
{
// クライアントの作成
ClientHandle workerHandle = Manager.Instance.CreateClient(MagellanSettings.HTTP_SERVER_HOST, MagellanSettings.HTTP_SERVER_PORT, MagellanSettings.CONSUMER_KEY, MagellanSettings.CONSUMER_SECRET, false);
// Workerの初期化
Manager.Instance.InitializeWorker (workerHandle, MagellanSettings.CLIENT_VERSION);
// Worker リクエスト用のインスタンスの生成
Worker worker = new Worker(String.Format("rooms/{0}/users/{1}", PlayerPrefs.GetInt("SelectRoomId"), PlayerPrefs.GetString("Username")),
BaseRequest.MethodType.Delete,
BaseRequest.ProtocolType.General,
MagellanSettings.SCHEME_TYPE);
// POSTデータのセット
worker.AddPostData ("name", PlayerPrefs.GetString("Username"));
// レスポンスコールバック
worker.ResponseCallback = (_worker) =>
{
string responseData = System.Text.Encoding.UTF8.GetString(_worker.Response);
if (! String.IsNullOrEmpty(responseData)){
Dictionary<string, object> result = Json.Deserialize (responseData) as Dictionary<string, object>;
if ((bool)result["result"]) {
// Subscriberの登録解除
Manager.Instance.UnregisterPubSub_Subscriber(pubsubHandle, sub);
} else {
Debug.Log(String.Format("Could not Exit. error: {0}", result["error"].ToString()));
}
}
};
// エラーコールバック
worker.ErrorCallback = (req) =>
{
Debug.Log(String.Format("Request Error. Error Code: {0}.", req.ErrorCode.ToString()));
};
// Worker リクエスト送信
Manager.Instance.SendWorkerRequest (workerHandle, worker);
}
退出処理では、必要なパラメータ(name
)をDELETEで送信します。
レスポンスをチェックし、resultがtrueの場合は、PubSubの切断処理を行い、ルーム一覧(Rooms.unity)へ遷移します。
PubSubの切断処理は以下のように行っています。
まずSubscriberの登録を解除を行います。 Subscriberの登録解除は、Managerクラスの UnregisterPubSub_Subscriber メソッドを使用します。 引数に、PubSub接続時に指定したクライアントハンドルとPubSub_Subscriberインスタンスを渡します。
Manager.Instance.UnregisterPubSub_Subscriber(pubsubHandle, sub);
PubSubの切断は、Subscriberの登録時に指定したコールバックUnRegisterCallback
内で行っています。
ManagerクラスのDisconnectPubSub
メソッドで、サーバーとの接続を切断します。
接続時に指定したクライアントハンドルを引数として渡します。
// Subscriber 登録解除完了時に実行
sub.UnRegisterCallback = (_sub) =>
{
// PubSub切断
Manager.Instance.DisconnectPubSub(pubsubHandle);
};
PubSubの切断が終了すると、PubSub切断後のコールバックでルームの一覧に遷移します。
これで、メッセージの購読の解除とルームから退室出来るようになりました。
以上で、Unity 版クライアントの完成です。