- 2009/11/19 04:13
- Progression
実力を上げるには先達の思考を盗むに限るよねー、って事で、
Progressionのソースをコツコツと精読して行くシリーズ開始します。
最初は、シーン遷移がどうなってるのかを理解するのにトライします。
なお、Progression4ではコンフィギュレーションが4種類あって、それぞれの設定でシーン遷移の仕組みが変わります。
今回は、WebConfigを適用した場合を見ていくことにします。
クラス図
なお、UML図に関してはかなりテキトーです。
何か間違いがありましたら、是非ともツッコミ入れてください。お願いしますー。
処理の流れ
僕がソース追えた分だけですが、処理の流れを何となく書きます。
登場人物
- Progression
- SceneManager
- SceneObject
- ExecutorObject
- CommandExecutor
起点となるのは、Progressionインスタンスであるmanagerのgotoを呼び出すところから始まります。
1.manager.goto
このメソッド内で、sceneManagerに委譲をします。
シーン遷移に関しては、丸投げ状態みたいです。
//Progression.as ( line727 ~)
public function goto( sceneId:SceneId, extra:Object = null ):Boolean {
// 読み込まれた Progression インスタンスであれば
if ( _loader ) { return _loader.manager.goto( _root.localToGlobal( sceneId ), extra ); }
return _sceneManager.goto( sceneId, extra );
}
Progression4で登場した、swf連結機能を使っている場合がif内ですかね。
2.sceneManager.goto と、_gotoProgress
まず、呼ばれたgotoメソッド内で、移動のためのイニシャライズ処理が行われてます。
「移動先が○○だった場合、××・・・」みたいな処理です。
あまり深く追わずにおきますが、基本的には、出発シーンのsceneId、目的シーンのsceneIdの
整合性確認と設定をしてるみたいです。
そこで、最終的には、private なメソッド、_gotoProgressが呼ばれます。
// SceneManager.as (line 176~)
public function goto( sceneId:SceneId, extra:Object = null ):Boolean {
// ... 省略してますが、スンゴイ前処理が書かれてます ...
// 移動処理を開始する
return _gotoProgress();
}
そして、_gotoProgressメソッド内で、実際の移動処理が行われます。
色々と、怒涛の前処理がありますが、最終的にやってる事は、現在のシーンのSceneObjectのインスタンスメンバであるExecutorObjectインスタンスを取得して、execute()する、という事です。
// SceneManager.as
private function _gotoProgress():Boolean {
// ExecutorObject を取得する
_executor = _current.executor;
// ExecutorObject が存在すれば
if ( _executor ) {
// イベントリスナーを登録する
_executor.addEventListener( ExecuteEvent.EXECUTE_COMPLETE, _executeComplete );
_executor.addEventListener( ExecuteEvent.EXECUTE_INTERRUPT, _executeInterrupt );
_executor.addEventListener( ExecuteErrorEvent.EXECUTE_ERROR, _executeError );
// 実行する
_executor.execute( new SceneEvent( _eventType, false, false, _eventType ), _extra );
}
}
SceneObjectのインスタンスメンバ、_executor:ExecutorObjectには、
WebConfig適用時はCommandExecutorインスタンスが格納されています。
3._executor.execute
CommandExecutorインスタンスのexecuteメソッド内の仕組みは若干トリッキーで、
結果的にCommandExecutor内の_executeFunctionメソッドが実行されます。
// CommandExecutor.as ( line 75 ~)
public override function execute( event:Event, extra:Object = null, preRegistration:Boolean = true ):void {
// SerialList を作成する
_current = new SerialList();
// 親のメソッドを実行する
super.execute( event, extra, preRegistration );
}
/**
* 実行される ExecutorObject の実装です。
*/
private function _executeFunction():void {
// イベントリスナーを登録する
_current.addEventListener( ExecuteEvent.EXECUTE_COMPLETE, _executeComplete );
_current.addEventListener( ExecuteEvent.EXECUTE_INTERRUPT, _executeInterrupt );
_current.addEventListener( ExecuteErrorEvent.EXECUTE_ERROR, _error );
// コマンドを実行する
_current.execute( super.extra );
}
CommandExecutor(ExecutorObjectのサブクラス)から、super.executeメソッドが呼ばれている所があります。
その箇所で、_executorと関連付けられているSceneObjectインスタンスがイベントをディスパッチしているクダリがあります。
// ExecutorObject.as ( line 247 ~ )
public function execute( event:Event, extra:Object = null, preRegistration:Boolean = true ):void {
// ...省略
// 引数を保存する
_event = event;
// イベントを送出する
_target.dispatchEvent( _event );
// 状態を変更する
_dispatching = false;
// 処理を実行する
//_executeFunctionには、サブクラス(CommandExecutor)の_executeFunctionメソッドが参照されています。
if ( _executeFunction != null ) {
_executeFunction();
}
// ...省略
}
クラス図からも解ると思いますが、メソッド内にある_targetが、関連付けられているSceneObjectインスタンスです。
隠蔽するために、IEventDispatcher型の変数に格納されてます。
発行されているイベント(_event)は、2.のSceneManagerの_gotoProgressメソッド内で指定されたSceneEventです。
なので、ここが、atSceneLoad,atSceneInit等のメソッドの実行タイミングになるわけですね。
SceneManagerの_gotoProgressメソッドは、遷移の際に辿って行くSceneObjectインスタンスが存在する限り、繰り返し実行されます。
繰り返し実行されているカラクリは、_executorの実行が完了した段階で、ExecuteEvent.EXECUTE_COMPLETEの
リスナ関数_executeCompleteが実行され、 _gotoCompleteが呼ばれ、その中で、
_currentSceneId、_destinedSceneId、_eventType の値から、以降に移動すべきシーンを判別しています。
判別の結果を踏まえて、再び_gotoProgress()が呼ばれる(もしくは次に移動すべきシーンがない場合は、遷移終了となる)、
という仕組みです。
まとめ
言葉で追っていくと中々解り辛いんですが、結局のところ、シーン遷移で一番頑張ってるクラスは
SceneManagerクラス、という事になるんでしょうかね。
ソースを実際に読んでみて、自分が色々と勘違いしていたことがわかりました。
今まではシーン・ツリー構造(複合配列的なもの)からシーンオブジェクトを引っ張り出しながら、
atSceneLoad,atSceneInitなんかを実行していると思ってたのですが、実際はSceneIdインスタンスの計算だけで、
移動順序を導き出してたんですねー。
シーン・ツリー構造を、遷移ロジックで利用しないというのは、お互いに依存関係を作らない方が、
柔軟な操作ができるから、とかですかね。
最近、自分で汎用的なタイリングクラスを作ろうとして、タイル構造とタイルの移動アニメーションロジックを
お互いにシンクロさせて作ってたら、最終的にとりとめが付かない状態になって破滅した記憶がよみがえりました・・・。
最終的に、タイル構造はツリー的なものではなく、フラットな状態にして、逐次構造を走査するようにし、アニメーションロジックとは
無関係にするようにしたら、かなりすんなりと出来上がりました。
むー、先達のソースは、ムリしてでも時間作って精読すべきだったなー、と反省。
——-
今回は遷移を実現するための部分だけを見たんですが、その結果、シーン遷移を中断する仕組みも何となく把握できたかなー。
コチラは、manager.stop()とやると、結果的に該当シーンのExecutorObjectインスタンスのinterruptが呼ばれて、結果、
CommandExecutorの実態コマンド(_current:SerialList)のinterruptが呼ばれる、という仕組みみたいです。
いやー、勉強になった。
コメント:0
トラックバック:0
- この記事のトラックバック URL
- http://djakarta-trap.net/blog/2009/11/read_progression_1/trackback/
- トラックバックの送信元リスト
- Progressionを精読してみる(1) -scene process編- - djakarta-trap より
