Union Platform(4) Reactorのイベント

Reactorの基本的なイベントを紹介します。UnionのバージョンはUnion alpha3を使用します。

ReactorのAPIドキュメントのすべてのクラスをみると、Eventの付く名前のクラスは7つあることが分かります。
順番はそれっぽい順にしてあります。

順番にみていきます。

ReactorEvent

Reactorインスタンスから送出されるイベントです。

ReactorEventの使いどころ

  • Union Serverとの接続が確立したことを知りたいとき
  • Union Serverとの接続が切断されたことを知りたいとき
var reactor:Reactor = new Reactor();
reactor.addEventListener(ReactorEvent.READY, reactor_readyHandler);
reactor.addEventListener(ReactorEvent.CLOSE, reactor_closeHandler);

// addEventListenerしてからconnectします。
reactor.connect("tryunion.com", 9100);

function reactor_readyHandler()
{
    // 接続が確立されたのでRoom作るなどします。

}

function reactor_closeHandler()
{
    // 接続が切断されたので、ポップアップでお知らせを出す等します。
}

ConnectionEvent

明記されていませんが、Conenctionインスタンスから送出されるイベントと思われます。 Connectionクラス自体が直接扱うクラスではないので、内部的に使われるイベントだと思います。

ServerEvent

Serverインスタンスから送出されるイベントです。

ServerEventの使いどころ

  • Serverに接続しているClient数を知りたいとき
  • Serverの時間を取得したいとき
var server:Server = reactor.getServer();
server.addEventListener(ServerEvent.CLIENT_COUNT, server_clientCountHandler
server.addEventListener(ServerEvent.TIME_SYNC, server_timeSyncHandler);

// 既にreactorからReactorEvent.READYが送出されているとします。

// Union Serverの応答があればServerEvent.CLIENT_COUNTを送出します
server.getNumClientsOnServer();

// Union Serverの応答があればServerEvent.TIME_SYNCを送出します
server.syncTime();

function server_clientCountHandler(event:ServerEvent):void
{
    trace("Server clients:" + event.getNumClients());
}

function server_timeSyncHandler()
{
    // 1970年1月1日を基点としたミリ秒フォーマット
    // ServerEventインスタンスのプロパティから取れないあたりは
    // バージョンアップで変わりそうな予感がしますね。
    trace("Time is: " + Server(event.target).getServerTime());
}

チャットの発言の横に出す時間とかクライアント時間なんて当てに出来ないのでこれは便利ですね。

RoomManagerEvent

RoomManagerインスタンスから送出されるイベントです。

RoomManagerEventの使いどころ

  • 指定したRoomのClient数を知りたいとき
  • 自身のClientが作成しようとした部屋が作成できたか知りたいとき
  • 特定のIDのRoomが生成されたことを知りたいとき
  • 自身のClientが存在しないRoomへjoin, observe, leaveしたことを知りたいとき
var roomManager:RoomManager = reactor.getRoomManager();
roomManager.addEventListener(RoomManagerEvent.CLIENT_COUNT, roomManager_clientCountHandler);
roomManager.addEventListener(RoomManagerEvent.CREATE_ROOM_RESULTS, roomManager_createRoomResultHandler);

// 既にreactorからReactorEvent.READYが送出されているとします。
// la.fla.chat, la.fla.gameというRoomが存在しているとします。

// la.fla.*というIDのRoomをwatchします
roomManager.watchForRooms("la.fla.*");

// la.fla.*内のclient数を取得します。
// UnionServerからの応答があれば、RoomManagerEvent.CLIENT_COUNTを送出します。
roomManager.getNumClientsInRooms("la.fla.*");

// la.fla.lobbyを作成します。
// UnionServerからの応答があれば、RoomManagerEvent.CREATE_ROOM_RESULTS
roomManager.createRoom("la.fla.lobby");

function roomManager_clientCountHandler(event:RoomManagerEvent):void
{
    // la.fla.*内のクライアント数を取得します。
    trace("RoomManager clients:" + event.getNumClientsTotal());
}

function roomManager_createRoomResultHandler(event:RoomManagerEvent):void
{
    // 自身が作成しようとした部屋の作成結果を取得します。
    trace("RoomManager create room result:" + event.getStatus());
}

la.fla.*のような指定をすることで、特定のグループのRoomの人数を知ることが出来ます。 チャットの部屋とロビーの関係をla.fla.chat, la.fla.chat.room01, la.fla.chat.room02などとすると管理しやすそうですね。

RoomEvent

Roomインスタンスから送出されるイベントです。

RoomEventの使いどころ

以下のRoomとはRoomEventを送出したRoomインスタンスを示します。

  • 自分自身のClientがRoomに無事join, leave, observe完了したことを知りたいとき
  • 別のClientがRoomにがjoin, leave, observeしたことを知りたいとき
  • Roomに入室、観察しているClient数の変化を知りたいとき
  • Room内のClientがClient Attributeを更新、削除したことを知りたいとき
  • 誰かがRoom Attributeが更新、削除したことを知りたいとき
  • Room入室時に現在の状況を知りたいとき
var room:Room = roomManager.createRoom("la.fla.lobby");

room.addEevntListener(RoomEvent.JOIN, room_joinHandler);
room.addEventListener(RoomEvent.ADD_CLIENT, room_addClientHandler);
room.addEventListener(RoomEvent.REMOVE_CLIENT, room_removeClientHandler);
room.addEventListener(RoomEvent.UPDATE_CLIENT_ATTRIBUTE, room_updateClientAttributeHandler);
room.addEventListener(RoomEvent.UPDATE_ROOM_ATTRIBUTE, room_updateRoomAttributeHandler);
room.addEventListener(RoomEvent.SYNCHRONIZE, room_synchronizeHandler);


// 既にroomManagerからRoomManagerEvent.CREATE_ROOM_RESULTSが送出されているとします。

// UnionServerからの応答があれば、RoomEvent.JOINを送出します。
room.join();

function room_joinHandler(event:RoomEvent):void
{
    trace("ルームに無事入室できました。");
}

function room_addClientHandler(event:RoomEvent):void
{
    trace("ルームに別のClientが入室しました。");
}

function room_removeClientHandler(event:RoomEvent):void
{
    trace("ルームから別のClientが退室しました。");
}

function room_updateClientAttributeHandler(event:RoomEvent):void
{
    var attribute:Attribute = event.getChangedAttr();
    if (attribute.name == "_PING") return;

    // Client Attributeを更新したClientを表します。
    var client:IClient = event.getClient();
    var clientID:String = event.getClientID();

    trace(
          clientID
        + "'s (" + attribute.scope + ")"
        + attribute.name + " was changed " + attribute.oldValue
        + " to " + attribute.value
    );
}

function room_updateRoomAttributeHandler(event:RoomEvent):void
{
    var attribute:Attribute = event.getChangedAttr();
    trace(
          attribute.name + " was changed " + attribute.oldValue
        + " to " + attribute.value
    );
}

function room_synchronizeHandler(event:RoomEvent):void
{
    var client:IClient;
    for each (client in _room.getClients())
    {
        // 既に入室しているClientのClient Attributeなどを取得する
    }
}

Union Platformでアプリケーションを作る際の核となるのは、このRoomEventとMessagesのイベントだと思います。 これらのイベント発生するイベントがユーザの視覚的な体験となるんですね。

ClientEvent

Clientインスタンスから送出されるイベントです。

ClientEventの使いどころ

  • 特定ClientのRoomへのjoin、leaveを知りたいとき
  • 特定ClientのClient Attributeの更新を知りたいとき

LogEvent

Loggerインスタンスから送出されるイベントです。

Messageのイベント

Messageのイベントはイベント用のインスタンスは生成されず、リスナー登録の引数やハンドラの引数が独自のものとなっています。 情報の共有化でもみたようにMessageは以下のAPIから送信されます。

  • Server APIによるMessage
  • RoomManager APIによるMessage
  • Room APIによるMessage
  • ClientManager APIによるMessage
  • Client APIによるMessage
  • Union ServerからのMessage

Messageイベントの使いどころ

情報の共有化でみてきた様なMessageの受信時に使います。

Server APIによるMessage

Serverに接続している全ClientへMessageを送信したい場合に使用します。

// 既にroomからRoomEvent.JOINが送出されているとします。

reactor.getMessageManager().addMessageListener("MESSAGE_ID", messageHandler);


// MESSAGE_IDというMessageを送信します。
// Union Serverから応答があれば、先にひもづけたmessageHandlerが呼ばれます。
server.sendMessage("MESSAGE_ID", true, null, "param1", "param2");


function messageHandler(fromClient:IClient, param1, param2):void
{
    trace(fromClient.getClientID() + "から"
        + param1 +"と" +param2 + "を受け取りました。");
}
RoomManager APIによるMessage

指定したRoomに入室しているClientへMessageを送信したい場合に使用します。

// 既にroomからRoomEvent.JOINが送出されているとします。

reactor.getMessageManager().addMessageListener("MESSAGE_ID", messageHandler);


// Room ID chat, game へ MESSAGE_IDというMessageを送信します。
// Union Serverから応答があれば、先にひもづけたmessageHandlerが呼ばれます。
roomManager.sendMessage("MESSAGE_ID", ["chat", "game"], true, null, "param1", "param2");


function messageHandler(fromClient:IClient, toRoom:Room, param1, param2):void
{
    trace(fromClient.getClientID() + "から"
        + param1 +"と" +param2 + "を受け取りました。");
}
Room APIによるMessage

現在Roomに入室しているClientへMessageを送信したい場合に使用します。

// 既にroomからRoomEvent.JOINが送出されているとします。

room.addMessageListener("MESSAGE_ID", messageHandler);


// MESSAGE_IDというMessageを送信します。
// Union Serverから応答があれば、先にひもづけたmessageHandlerが呼ばれます。
room.sendMessage("MESSAGE_ID", true, null, "param1", "param2");


function messageHandler(fromClient:IClient, param1, param2):void
{
    trace(fromClient.getClientID() + "から"
        + param1 +"と" +param2 + "を受け取りました。");
}
ClientManager APIによるMessage

指定したClientへMessageを送信したい場合に使用します。

// 既にroomからRoomEvent.JOINが送出されているとします。

reactor.getMessageManager().addMessageListener("MESSAGE_ID", messageHandler);


// Client ID 123, 124へMESSAGE_IDというMessageを送信します。
// Union Serverから応答があれば、先にひもづけたmessageHandlerが呼ばれます。
clientManager.sendMessage("MESSAGE_ID", ["123", "124"], null, "param1", "param2");


function messageHandler(fromClient:IClient, param1, param2):void
{
    trace(fromClient.getClientID() + "から"
        + param1 +"と" +param2 + "を受け取りました。");
}
Client APIによるMessage

特定のClientへMessageを送信したい場合に使用します。

// 既にroomからRoomEvent.JOINが送出されているとします。

var self:IClient = reactor.getClientManager().self();
self.addMessageListener("MESSAGE_ID", messageHandler);

var client:IClient = _room.getClients("123");

// MESSAGE_IDというMessageを送信します。
// Union Serverから応答があれば、先にひもづけたmessageHandlerが呼ばれます。
client.sendMessage("MESSAGE_ID", "param1", "param2");

// 自身のClient IDが123であれば実行されます
function messageHandler(fromClient:IClient, param1, param2):void
{
    trace(fromClient.getClientID() + "から"
        + param1 +"と" +param2 + "を受け取りました。");
}


まとめ

基本的なイベントの使いどころをみてきたので、もうアプリを作ることが出来そうです。 簡単なアプリの流れを見てみましょう。

基本的なアプリの流れ

  1. Reactorのインスタンス作成
  2. ReactorEventのlisten
    • ReactorEvent.READY
    • ReactorEvent.CLOSE</li
  3. ReactorインスタンスからUnion Serverへ接続
  4. ReactorインスタンスがReactorEvent.READYを送出
  5. 自身のClientを取得
  6. 自身のClient Attributeを初期化
  7. RoomManagerEventのlisten
    • RoomManagerEvent.CLIENT_COUNT
    • RoomManagerEvent.CREATE_ROOM_RESULTS
  8. Roomインスタンスの作成
  9. RoomインスタンスがRoomManagerEvent.CREATE_ROOM_RESULTSを送出
  10. RoomEventのlisten
    • RoomEvent.JOIN
    • RoomEvent.OBSERVE
    • RoomEvent.LEAVE
    • RoomEvent.STOP_OBSERVING
    • RoomEvent.CLIENT_COUNT
    • RoomEvent.UPDATE_CLIENT_ATTRIBUTE
    • RoomEvent.DELETE_CLIENT_ATTRIBUTE
    • RoomEvent.UPDATE_ROOM_ATTRIBUTE
    • RoomEvent.DELETE_CLIENT_ATTRIBUTE
    • RoomEvent.SYNCHRONIZE
  11. Roomインスタンスの接続(join or observe)
  12. RoomインスタンスがRoomEvent.JOIN or RoomEvent.OBSERVEを送出
  13. RoomインスタンスがRoomEvent.SYNCHRONIZEを送出

もちろん、他にも今回見てきたイベントのリッスンを挟み込むことで色々なアプリケーションが作れます。 次回は、マルチアプリケーションの定番であるチャットアプリケーションを作ってみます。

関連記事

  1. UnionPlatform (1) 概要
  2. UnionPlatform (2) 概念
  3. Union Platform(3) 情報の共有化
  4. Union Platform(4) Reactorのイベント
  5. Union Platform(5) チャットを作る
  6. Union Platform(6) Union Server入門
  7. Union Platform(7) Union Server Module作成準備
  8. Union Platform(8) Moduleサンプル