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

2010/12/3

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

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

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

Interfaceの作成

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

ICommand.as


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

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

package kinkuma.command
{
	/**
	 * ...
	 * @author KinkumaDesign
	 */
	public class CommandEvent
	{
		public static const COMMAND_COMPLETE:String = "command_complete";
	}

}

独自のイベント名です。

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

TweenerCommand.as

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

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

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を登録して実行したら終了イベントを発行します

テストしてみる

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アプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

ページトップへ戻る