9ballsyndrome

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  1. --/--/--(--) --:--:--|
  2. スポンサー広告

AS3SX 入門3 EventManagerについて

logo

 

AS3SX入門3。

やること

 

 


 

 

EventManager

 

ServerAS3SX.eventでEventManagerオブジェクトを取得できる。

Eventとつくのだが、特にEventクラスとそのサブクラスとは関係がない。

EventDispatcherとも関係がない。

何をするクラスなのかというと、公式のSimple Sample Appでの使われ方を見ると、どうやら多数に送信する命令のようだ。

 

EventManager

 

addUserEventHandlerをリクエストハンドラ内で実行すると、現在のセッションがselectorに関連付けられる。これをしておくと、dispatchServerEventで第二引数にそのselectorを指定したときに第一引数のレスポンスオブジェクトが送られる。

例えばクライアント1のリクエストハンドラで"group1"に、
クライアント2のリクエストハンドラで"group1"に、
クライアント3のリクエストハンドラで"group2"に、
クライアント4のリクエストハンドラで"group2"に、
それぞれaddUserEventHandlerしておくと、

クライアント1のリクエストハンドラでdispatchServerEvent("hello","group1")とすることでクライアント1とクライアント2に"hello"がレスポンスとして送られる。クライアント3と4には送信されない。

クライアント1のリクエストハンドラでdispatchServerEvent("hello","group2")とすると、今度はクライアント3と4に"hello"が送られるが、クライアント2にも、リクエストを送ったクライアント1にも送信されない。

 

このことから、selectorはグループ名のようなもので、グループ名を選択してdispatchServerEventすることでそのグループにあらかじめ登録してあるセッションにオブジェクトが一斉に送信されるようだ。

 

内部ではおそらくループで全員に送っているだけだろうが、送るグループを簡単に管理することができる。

 

 

(*注)と思っているのだが、このremoveUserEventHandlerも働いていない気がする。

現在のセッションを一度登録したグループから抜けださせるメソッドだと思うのだが、試してみると期待の動きをしない(登録が解除されず、一度登録してあったselectorにdispatchServerEventすると相変わらず送られる)ようだ。

使い方の解釈が間違ってるかもしれないので、とりあえずこれも保留。

なぜEventという名前がついているのかもちょっと謎なので他の使い方があるのかもしれない。リファレンス待ちだ。

 

 

 

簡易チャット

 

EventManagerを利用してこんな簡易チャットを作ってみる。

demo

名前を入力して部屋を選び、ボタンを押すとその部屋に入室する。そこで発言すると、同じ部屋に入った全員にメッセージが伝わるものだ。

友達のいない人はウィンドウを2つ開いて一人チャットをやってみよう。

また、もう1つ別のウィンドウで別の部屋にも入ってみると、他の部屋のメッセージは受信しないし、この部屋の発言も他の部屋には伝わらない。

部屋は4つあるが、起動しているサーバーサイドswfは1つだけだ。

 

本当は部屋を変えられるようにしたかったが、removeUserEventHandlerが働かないため、この方法では無理だった。

 

 

Entryクラス

省略。

があるだけ。最初の接続時に自分の名前と入った部屋をサーバーに教えておくためのもの。

実は今回、部屋も名前もクライアントサイドに情報は残さず、サーバーサイドのSessionに保存させてみた。これでいちいち部屋も名前もメッセージに付加して送らずに済む。

 

今回もカスタムクラスを送信するが、実はこのソケット通信ではデータをAMFにしてやりとりしている。

カスタムクラスをAMF化するときは復元する時のためにregisterClassAliasでクラスを登録しなくてはならないが、AS3SXでは送信するカスタムクラスは自分で登録しなくても内部でregisterClassAliasしてくれているので何も考えずに使える。

しかし、カスタムクラスにさらにカスタムクラスを持たせる時は、そこまではやってくれないので自分でサーバーサイドとクライアントサイド両方でそのカスタムカラスをregisterClassAliasしなくてはならない。

 

 

クライアントサイド

package {
    import com.as3sx.connection.SocketConnection;
    import com.bit101.components.ComboBox;
    import com.bit101.components.InputText;
    import com.bit101.components.Label;
    import com.bit101.components.Panel;
    import com.bit101.components.PushButton;
    import com.bit101.components.Style;
    import com.bit101.components.TextArea;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    import flash.ui.Keyboard;
 
    /**
     * ...
     * @author
     */
    public class ClientMain extends Sprite {
 
        /// change endpoint
        private static const END_POINT:String = "http://as3sx.com/Apps/ふんぐるいむぐるうなふ/";
        //
        private var enterPanel:Panel;
        private var nameInput:InputText;
        private var roomChoose:ComboBox;
        private var enterButoon:PushButton;
        //
        private var roomLabel:Label;
        private var log:TextArea;
        private var messageInput:InputText;
        private var sendButton:PushButton;
 
        public function ClientMain():void {
            if (stage)
                init();
            else
                addEventListener(Event.ADDED_TO_STAGE, init);
        }
 
        private function init(e:Event = null):void {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            // entry point
            ClientAS3SX.setEndPoint(END_POINT);
            addEventListener(Event.ENTER_FRAME, connectionCheck);
        }
 
        private function connectionCheck(e:Event):void {
            if (SocketConnection.instance.connected){
                removeEventListener(Event.ENTER_FRAME, connectionCheck);
                // connected
                initUI();
                ClientAS3SX.setResponseHandler(String, onString);
            }
        }
 
        private function initUI():void {
            Style.embedFonts = false;
            Style.fontName = "PF Ronda Seven";
            Style.fontSize = 12;
            //
            log = new TextArea(this, 100, 100);
            log.setSize(600, 400);
            log.html = true;
            log.editable = false;
            messageInput = new InputText(this, 100, 500, "");
            messageInput.setSize(600, 20);
            messageInput.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
            messageInput.enabled = false;
            sendButton = new PushButton(this, 600, 520, "SEND", onPush);
            sendButton.enabled = false;
            roomLabel = new Label(this, 100, 40);
            //
            enterPanel = new Panel(this, 250, 250);
            enterPanel.setSize(300, 100);
            roomChoose = new ComboBox(enterPanel.content, 40, 60, "", ["room0", "room1", "room2", "room3"]);
            roomChoose.selectedIndex = 0;
            roomChoose.numVisibleItems = 4;
            nameInput = new InputText(enterPanel.content, 40, 20, "");
            nameInput.setSize(220, 20);
            enterButoon = new PushButton(enterPanel.content, 160, 60, "Enter", onEnter);
        }
 
        private function onEnter(e:MouseEvent):void {
            var name:String = nameInput.text;
            if (name != ""){
                var entry:Entry = new Entry();
                entry.room = roomChoose.selectedIndex;
                entry.name = name;
                ClientAS3SX.sendRequest(entry);
                //
                roomLabel.text = "room" + entry.room;
                enterButoon.removeEventListener(MouseEvent.CLICK, onEnter);
                removeChild(enterPanel);
                messageInput.enabled = true;
                sendButton.enabled = true;
            }
        }
 
        private function onPush(e:MouseEvent):void {
            sendMessage();
        }
 
        private function onKeyDown(e:KeyboardEvent):void {
            if (e.keyCode == Keyboard.ENTER){
                sendMessage();
            }
        }
 
        private function sendMessage():void {
            var message:String = messageInput.text;
            if (message != ""){
                ClientAS3SX.sendRequest(message);
                messageInput.text = "";
            }
        }
 
        private function onString(str:String):void {
            log.text = str + "\n" + log.text;
        }
 
    }
 
}

 

ちょっとUI部分大目。

受けるレスポンスはStringにしよう。StringでsetResponseHandlerする。ハンドラメソッドではStringが来たらテキストの上に送られてきたStringを追加して表示する。

名前と部屋を選び、Enterボタンを押したらEntryオブジェクトを作ってnameとroomをそれぞれのコンポーネントから取得し、sendRequestする。

あとはmessageInputに文字列を入力してSENDボタンを押すかキーボードのEnterを押すとmessageInputのテキスト文字列をsendRequestしている。

 

 

サーバーサイド

package {
    import com.as3sx.server.EventManager;
    import com.as3sx.server.SessionManager;
    import com.as3sx.session.Session;
    import flash.display.Sprite;
 
    /**
     * ...
     * @author
     */
    public class ServerMain extends Sprite {
        private var eventManager:EventManager;
        private var sessionManager:SessionManager;
 
        public function ServerMain():void {
            // entry point
            eventManager = ServerAS3SX.event;
            sessionManager = ServerAS3SX.session;
            ServerAS3SX.setRequestHandler(Entry, onEntry);
            ServerAS3SX.setRequestHandler(String, onString);
        }
 
        private function onEntry(entry:Entry):void {
            var room:uint = entry.room;
            var name:String = entry.name;
            var session:Session = sessionManager.getSession();
            session.setValue("name", name);
            session.setValue("room", room);
            eventManager.addUserEventHandler("room" + room);
            eventManager.dispatchServerEvent("<b>System : " + name + " さんが入室しました</b>", "room" + room);
        }
 
        private function onString(str:String):void {
            var session:Session = sessionManager.getSession();
            eventManager.dispatchServerEvent(session.getValue("name") + " : " + str, "room" + session.getValue("room"));
        }
 
    }
 
}

 

まずsetRequestHandlerでEntryオブジェクトとStringオブジェクトを受ける準備をしよう。

 

Entryオブジェクトが送られてきたときは引数から名前を部屋番号を取り出す。

前回も使ったSessionManagerで現在のセッションを取得し、"name"と"room"をキーにしてそれぞれ保存する。

そしてaddUserEventHandlerでselctorを"room"+部屋番号にして現在のセッションを登録する。

その後dispatchServerEventで、そのselectorに登録された全員にシステムメッセージを送る。

 

Stringオブジェクトが送られてきたときは名前を追記して、セッションが入っている部屋全員にレスポンスを送りたい。

現在のセッションを取得し、それぞれのキーで値を取り出して使おう。

 

 

 

 

今回のプロジェクトのソースファイルはこちら。setEndPointの引数は変えてあるので注意。

source

 

 

 

一斉送信でした。実際には一斉じゃないだろうけど。好きにグループ分け出来るのがいいね。欲を言えば現在のセッションしか登録できないので、GUIDを指定することで他のセッションをイベント登録できるといいなあ。

removeUserEventHandlerが使えるともうちょっと幅が広がると思う。まあ自分で管理すればいいだけの話だけど、せっかく提供してくれてる機能は使いたいよね。addSessionDisposeHandlerと併せてなんとかしてね。

 

次回はたぶんデータベースのお話。

 

 

スポンサーサイト
  1. 2011/09/15(木) 01:52:05|
  2. AS3SX
  3. | トラックバック:0
  4. | コメント:2
<<AS3SX 入門4 PersistentObjectについて(前編) | ホーム | AS3SX 入門2 Sessionについて>>

コメント

おもしろい!
asしか書けない私としては大いに期待しています!
これからも検証&解説がんばってください!
  1. 2011/09/27(火) 16:00:01 |
  2. URL |
  3.   #-
  4. [ 編集 ]

ありがとうございます!


記事としてまとめる前の話は結構Twitterでつぶやいてますのでよかったらそちらもご覧ください。
  1. 2011/09/27(火) 18:13:09 |
  2. URL |
  3. 9ballsyn #-
  4. [ 編集 ]

コメントの投稿


管理者にだけ表示を許可する

トラックバック

トラックバック URL
http://9ballsyndrome.blog.fc2.com/tb.php/39-3a27ef66
この記事にトラックバックする(FC2ブログユーザー)
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。