[AS3] Commandライブラリを作って非同期処理をする 2

2010/12/3

こんにちは。きんくまです。
前回は途中で終わっちゃたんで、とりあえず続きから。

今回作るもの
ICommand > Interface
Command > Commandのベース
TweenerCommand > Tweenerするコマンド
WaitCommand > タイマー
FunctionCommand > 関数実行

とりあえず、上のやつがあればだいたいのことはできるかと。
あと、Loader関係とかあると思うんですが、自分はこの辺はコマンドにしないで
地味に書いていくのが好きなんで、必要な人はお好みで作ってみるのもよいかと。

Interfaceの作成

Interfaceです。前回、自分なりのInterfaceの便利なところを書きました。
今回は実際の設計です。

ICommand.as

1
2
3
4
5
6
7
8
9
10
11
12
13
package kinkuma.command
{
    /**
     * ...
     * @author KinkumaDesign
     */
    public interface ICommand
    {
        function execute():void;
        function addEventListener(type:String, listener:Function):void;
        function removeEventListener(type:String, listener:Function):void;
    }
}

3つのメソッドを定義しました。コマンドを実行するのと、イベントを登録・削除するというものです。
ICommandからイベントの登録・削除機能を消してしまって、
実際に実装するCommand自体がEventDispatcherを継承して作ってもいいかもしれません。

Command.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package kinkuma.command
{
    import flash.events.Event;
    import flash.events.EventDispatcher;
    /**
     * ...
     * @author KinkumaDesign
     */
    public class Command implements ICommand
    {
        protected var _eDispatcher:EventDispatcher;
         
        public function Command()
        {
            _eDispatcher = new EventDispatcher();
        }
         
        public function execute():void
        {
            dispatchCompleteEvent();
        }
         
        public function addEventListener(type:String, listener:Function):void
        {
            _eDispatcher.addEventListener(type, listener);
        }
         
        public function removeEventListener(type:String, listener:Function):void
        {
            _eDispatcher.removeEventListener(type, listener);
        }
         
        protected function dispatchCompleteEvent():void
        {
            _eDispatcher.dispatchEvent(new Event(CommandEvent.COMMAND_COMPLETE));
        }
    }
}

・excuteしたら、COMMAND_COMPLETEイベントを発行する
・内部的にEventDispatcherのインスタンスを作って、外側からイベントを登録しにきたやつをそいつに渡してあげる

ということをしています。終了イベント名はfladdictさんのやつをみると、Event.COMPLETEを発行していたんですが、今回はProgressionの真似をして独自イベントを定義しました。

CommandEvent.as

1
2
3
4
5
6
7
8
9
10
11
12
package kinkuma.command
{
    /**
     * ...
     * @author KinkumaDesign
     */
    public class CommandEvent
    {
        public static const COMMAND_COMPLETE:String = "command_complete";
    }
 
}

独自のイベント名です。

ここからが、実際に使用するコマンドたちになります。
すべてのコマンドはCommandを継承して作っています。でも、もし自分でカスタムコマンドを作るときは、Commandを継承しなくても、ICommandを実装してあげれば、これから作るSerialCommand, ParallelCommandでも使えるようになります。

TweenerCommand.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package kinkuma.command
{
    import caurina.transitions.Tweener;
    import flash.events.Event;
    /**
     * ...
     * @author KinkumaDesign
     */
    public class TweenerCommand extends Command
    {
        private var _target:Object;
        private var _params:Object;
         
        public function TweenerCommand(p_scopes:Object, params:Object)
        {
            _target = p_scopes;
            _params = params;
        }
         
        override public function execute():void
        {
            var self:TweenerCommand = this;
            _params.onComplete = function():void {
                self.dispatchCompleteEvent();
            };
            Tweener.addTween(_target, _params);
        }
    }
 
}

基本的に、それぞれのコマンドはコンストラクタで引数を受け付けて、executeをoverrideして、それぞれの動きに書き換えてあげるというふうにしました。
あとTweenエンジンとしては開発の終わったTweenerですが、自分的にはまだまだ現役です。
この辺はお好みのTweenエンジンで書きなおすのもすぐに可能だと思います。

WaitCommand.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
package kinkuma.command
{
    import flash.events.TimerEvent;
    import flash.utils.Timer;
    /**
     * ...
     * @author KinkumaDesign
     */
    public class WaitCommand extends Command
    {
        private var _waitTime:Number;
        private var _timer:Timer;
         
        public function WaitCommand(time:Number = 0)
        {
            _waitTime = time;
        }
         
        override public function execute():void
        {
            _timer = new Timer(_waitTime * 1000, 1);
            _timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHD);
            _timer.start();
        }
         
        private function timerCompleteHD(e:TimerEvent):void
        {
            _timer.removeEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHD);
            _timer.stop();
            _timer = null;
            dispatchCompleteEvent();
        }
    }
 
}

タイマーをまわして、終わったら終了イベントを出すだけです。

FunctionCommand.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package kinkuma.command
{
    import flash.events.Event;
    /**
     * ...
     * @author KinkumaDesign
     */
    public class FunctionCommand extends Command
    {
        private var _targetFunc:Function;
         
        public function FunctionCommand(targetFunction:Function)
        {
            _targetFunc = targetFunction;
        }
         
        override public function execute():void
        {
            _targetFunc();
            dispatchCompleteEvent();
        }
    }
 
}

実行したいFunctionを登録して実行したら終了イベントを発行します

テストしてみる

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package
{
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.events.Event;
    import kinkuma.command.CommandEvent;
    import kinkuma.command.FunctionCommand;
    import kinkuma.command.TweenerCommand;
    import kinkuma.command.WaitCommand;
     
    /**
     * ...
     * @author KinkumaDesign
     */
    public class Main extends Sprite
    {
         
        public function Main():void
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
         
        private function init(e:Event = null):void
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
             
            var sp:Sprite = new Sprite();
            var g:Graphics = sp.graphics;
            g.beginFill(0xff0000, 1);
            g.drawCircle(0, 0, 100);
            g.endFill();
            addChild(sp);
            sp.x = 200;
            sp.y = 200;
            sp.alpha = 0;
             
            var tc:TweenerCommand = new TweenerCommand(sp, { alpha:1, x:400, y:300, time:1, transition:"easeinoutquad" } );
            tc.addEventListener(CommandEvent.COMMAND_COMPLETE, compHD);
            tc.execute();
             
            var wc:WaitCommand = new WaitCommand(0.5);
            wc.addEventListener(CommandEvent.COMMAND_COMPLETE, compHD);
            wc.execute();
             
            var fc:FunctionCommand = new FunctionCommand(this.compHD);
            fc.addEventListener(CommandEvent.COMMAND_COMPLETE, compHD);
            fc.execute();
        }
         
        private function compHD(e:Event = null):void
        {
            trace("comp");
        }
    }
     
}

今回はここまでです。これらのコマンド群が力を発揮するのは次回やるSerialとParallelです。

LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

LINEスタンプ作りました!
毎日使える。とぼけたウサギ。LINEスタンプ販売中! 毎日使える。とぼけたウサギ

ページトップへ戻る