[AS3] シーケンス遷移(ページ遷移)を自作する2 (非同期処理を組み込む)

2010/02/5

こんにちは。きんくまです。
先日の節分の日に、家族で豆まきをしました。
私が鬼役だったので、外で家族が豆をまいてくれるのを「出待ち」してたんです。そしたら、その日は雪がちょろっとふってきていて、すごく寒かったです。
早く出てきて豆まいてほしかったです。

さて、前回のシーケンス遷移の続きです。
今回は前回のものに、非同期処理を加えてみました。
シーンのイベント処理はProgressionを参考にしました。

>> ファイル一式

非同期処理にはNextを使います。
>> Next は非同期処理を簡素に記述するために作られたライブラリです。

やり方にはちょっとクセがあるのですが、JavaScriptでjQueryをさわったことがある人だったらすぐに慣れると思います。
非同期処理には、他にもたくさんあります。
>> 非同期処理 (AS3) (Spark project)
このほかにもProgressionのCommandやfladdictさんのCommandもありますね。
>> AS3で非同期処理を行う為のcommandsライブラリ

で、Nextは非同期処理をクラスを個別につくらなくても、関数単位でも組み込むことができるお手軽さがウリだと思います。
ソースを書く量が減らせて、面倒くさがりな私にはぴったりです。

それで、今回はシーン移動のときの非同期処理に使いました。
すべてのシーンのベースとなるSceneBase は前回と比べてinit関数はやめてstartSceneとstopSceneのみにしました。

package test.base
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import org.libspark.next.*;
	/**
	 * ...
	 * @author KinkumaDesign
	 */
	public class SceneBase extends MovieClip
	{
		protected var _nextScene:SceneBase;
		protected var _trigger:Trigger;
		
		public function getNextScene():SceneBase
		{
			return _nextScene;
		}
		
		public function SceneBase() 
		{
			
		}
		
		public function startScene():ITrigger
		{
			_trigger = new Trigger();
			_trigger.call();
			return _trigger;
		}
		
		public function stopScene():ITrigger
		{
			_trigger = new Trigger();
			_trigger.call();
			return _trigger;
		}
		
		protected function dispatchCompleteEvent():void
		{
			dispatchEvent(new Event(Event.COMPLETE));
		}
	}

}

メインはこんな感じ

package  test
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import org.libspark.next.*;
	import test.base.SceneBase;
	/**
	 * ...
	 * @author KinkumaDesign
	 */
	public class Main extends MovieClip
	{
		private var _childScene:SceneBase;
		
		//シングルトン
		private static var _instance:Main;
		public static function getInstance():Main
		{
			return _instance;
		}
		
		public function Main() 
		{
			if (_instance == null) {
				_instance = this;
				init();
			}else{
				throw new Error('Error. This is singleton class.');
			}
		}
		
		private function init():void
		{
			_childScene = new TopScene();
			_childScene.addEventListener(Event.COMPLETE, childSceneCompleteHD);
			_childScene.startScene();
			addChild(_childScene);
		}
		
		private function childSceneCompleteHD(e:Event):void
		{
			_childScene.removeEventListener(Event.COMPLETE, childSceneCompleteHD);
			var tempScene:SceneBase = _childScene.getNextScene(); //一時保存
			var self:Main = this;
			
			//マウス無効
			setMouseEventEnable(false);
			
			//終了処理
			N.push(_childScene.stopScene)
			.func(function(){;
				self.removeChild(self._childScene);
				self._childScene = null;
				self._childScene = tempScene;
				self.startChildScene();
			}).start();
		}
		
		//新シーン処理
		private function startChildScene():void
		{
			var self:Main = this;
			N.push(self._childScene.startScene)
			.func(function() {
				self._childScene.addEventListener(Event.COMPLETE, self.childSceneCompleteHD);
				self.setMouseEventEnable(true);
			}).start();
			addChild(_childScene);
		}
		
		//マウスイベントをとるか
		public function setMouseEventEnable(isPossible:Boolean):void
		{
			this.mouseChildren = this.mouseEnabled = isPossible;
		}
	}

}

ここで、マウスイベントをとるかとらないかという関数をつくってあります

		//マウスイベントをとるか
		public function setMouseEventEnable(isPossible:Boolean):void
		{
			this.mouseChildren = this.mouseEnabled = isPossible;
		}

これはどういうものかというと、非同期処理の最中にボタンを押されるといろいろと面倒なことになるので、それを防ぐためにつけてあります。

ルート以下につるしてあるすべてのマウスイベントを一時的にオン・オフすることができるというものです。作成するアイデアとなったのは、下のページです。
どうもです。
>> AS3.0 マウスイベントの伝播の理解とTIPS ( flair4 blog )

オプションページはこんな感じ

package test 
{
	import flash.display.MovieClip;
	import flash.events.MouseEvent;
	import kinkuma.BAS3Trigger;
	import org.libspark.betweenas3.easing.*;
	import org.libspark.next.*;
	import test.base.SceneBase;
	/**
	 * ...
	 * @author KinkumaDesign
	 */
	public class OptionScene extends SceneBase
	{
		public var titleBtn:MovieClip;
		public var startBtn:MovieClip;
		
		public function OptionScene() 
		{
			
		}
		
		override public function startScene():ITrigger 
		{
			var self:OptionScene = this;
			var tr:Trigger = new Trigger();
			alpha = 0;
			N.push(BAS3Trigger, this, { alpha:1 }, 0.6, Quad.easeIn)
			.func(function(){
				self.startBtn.addEventListener(MouseEvent.CLICK, startClickHD);
				self.titleBtn.addEventListener(MouseEvent.CLICK, titleClickHD);
				tr.call();
			}).start();
			return tr;
		}
		
		private function startClickHD(e:MouseEvent):void 
		{
			_nextScene = new GameScene();
			dispatchCompleteEvent();
		}
		
		private function titleClickHD(e:MouseEvent):void 
		{
			_nextScene = new TopScene();
			dispatchCompleteEvent();
		}
		
		override public function stopScene():ITrigger 
		{
			startBtn.removeEventListener(MouseEvent.CLICK, startClickHD);
			titleBtn.removeEventListener(MouseEvent.CLICK, titleClickHD);
			var tr:Trigger = new Trigger();
			N.push(BAS3Trigger, this, { alpha:0 }, 0.4, Quad.easeIn)
			.func(function() {
				tr.call();
			}).start();
			return tr;
		}
	}

}

ここで、BAS3Triggerというクラスがでてきました。
今回トゥイーンエンジンはBetweenAS3を使っているので、それ用のTriggerクラスを作っています。

package kinkuma 
{
	import flash.display.DisplayObject;
	import org.libspark.betweenas3.BetweenAS3;
	import org.libspark.betweenas3.core.easing.IEasing;
	import org.libspark.betweenas3.events.TweenEvent;
	import org.libspark.betweenas3.tweens.ITween;
	import org.libspark.next.*;
	
	/**
	 * ...
	 * @author KinkumaDesign
	 */
	public class BAS3Trigger extends Trigger
	{
		private var _tw:ITween;
		
		public function BAS3Trigger(target:Object, params:Object, time:Number, easing:IEasing, delay:Number = 0) 
		{
			_tw = BetweenAS3.to(target, params, time, easing);
			_tw = BetweenAS3.delay(_tw, delay);
			_tw.addEventListener(TweenEvent.COMPLETE, tweenCompHD);
			_tw.play();
		}
		
		override public function halt(... args:Array):void 
		{
			_tw.removeEventListener(TweenEvent.COMPLETE, tweenCompHD);
			_tw.stop();
		}
		
		private function tweenCompHD(e:TweenEvent):void 
		{
			_tw.removeEventListener(TweenEvent.COMPLETE, tweenCompHD);
			call();
		}
		
	}

}

あと、節となるゲームシーン

package test 
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import test.base.GameSceneBase;
	import test.base.SceneBase;
	import kinkuma.BAS3Trigger;
	import org.libspark.betweenas3.easing.*;
	import org.libspark.next.*;
	/**
	 * ...
	 * @author KinkumaDesign
	 */
	public class GameScene extends SceneBase
	{
		public var popupBtn:MovieClip;
		public var titleBtn:MovieClip;
		private var _childScene:SceneBase;
		
		public function GameScene() 
		{
			
		}
		
		override public function startScene():ITrigger 
		{
			var self:GameScene = this;
			var tr:Trigger = new Trigger();
			alpha = 0;
			N.push(BAS3Trigger, this, { alpha:1 }, 0.6, Quad.easeIn)
			.func(function() {
				self.popupBtn.addEventListener(MouseEvent.CLICK, self.popupClickHD);
				self.titleBtn.addEventListener(MouseEvent.CLICK, self.titleClickHD);
				tr.call();
			}).start();
			return tr;
		}
		
		private function popupClickHD(e:MouseEvent):void 
		{
			_childScene = new PopupScene();
			addChild(_childScene);
			var self:GameScene = this;
			Main.getInstance().setMouseEventEnable(false);
			N.push(_childScene.startScene)
			.func(function() {
				self._childScene.addEventListener(Event.COMPLETE, self.childSceneCompleteHD);
				Main.getInstance().setMouseEventEnable(true);
			}).start();
		}
		
		private function childSceneCompleteHD(e:Event):void 
		{
			_childScene.removeEventListener(Event.COMPLETE, childSceneCompleteHD);
			
			Main.getInstance().setMouseEventEnable(false);
			
			var self:GameScene = this;
			N.push(_childScene.stopScene)
			.func(function() {
				self.childSceneTransitionCompleteHD();
				Main.getInstance().setMouseEventEnable(true);
			}).start();
		}
		
		private function childSceneTransitionCompleteHD():void
		{
			removeChild(_childScene);
			
			_nextScene = _childScene.getNextScene();
			
			//何もしない
			if (_nextScene == null) {
			
			//GameSceneの子シーンになれるんだったら
			}else if (_nextScene is GameSceneBase) {
				/*
				 * 子シーンを追加してchildSceneCompleteHDを登録する処理
				 * 今回は別の子シーンがないので何もしない
				 */
				
			//子シーンでない場合は親に通達する
			}else {
				dispatchCompleteEvent();
			}
		}
		
		private function titleClickHD(e:MouseEvent):void 
		{
			_nextScene = new TopScene();
			dispatchCompleteEvent();
		}
		
		override public function stopScene():ITrigger 
		{
			popupBtn.removeEventListener(MouseEvent.CLICK, popupClickHD);
			titleBtn.removeEventListener(MouseEvent.CLICK, titleClickHD);
			var tr:Trigger = new Trigger();
			N.push(BAS3Trigger, this, { alpha:0 }, 0.4, Quad.easeIn)
			.func(function() {
				tr.call();
			}).start();
			return tr;
		}
	}

}

なんか長々となってしまいました。興味がある方はソースを見てみてください。
これにswfaddressを組み込めれば、簡易自作ページ遷移システムになると思います。でもこれがすごく厄介そうだなー。

ではー。


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

ページトップへ戻る