[AS3] Progression4でSceneLoaderを使い外部ファイルのswfをシーンに足してみた

2010/05/16

こんにちは。きんくまです。

先日発売されたProg本を早速購入しました。
>> ProgressionによるFlashコンテンツ開発ガイドブック (単行本(ソフトカバー))

私はProgression2の頃に1回セミナーにいったことがあったのですが、少しさわってみて
正直わからん!となってしまい、そのあと機会を見つけてはチャレンジ > よくわからん!の
繰り返しでした。

ところが、上の本のチュートリアルを読んだところ、これがすごくわかりやすくてよかったです。
Web上で何回か公式のチュートリアルもやってはみたのですが、いまいちピンとこなかったんです。
が、何故か書籍版だとしっくりきました。
この本の後半が逆引きリファレンスとなっているので、そのあたりも合わせて読めたからよかったのかもしれませんね。

そんで、1回は実案件でやってみようと思い、今日一日やってみたところ、なんとか実案件で
ひっかかりそうなところはクリアできたかな、、と。
もともとprogのコマンドは単体でも使ったりしてたので、ページ遷移のところを主に勉強。

作ったのはこれ。(画像クリックでとびます)

prog4_fig1

>> 参考までにデータ一式を置いておきます。

今回は、SceneLoaderを使って外部ファイル化されたシーンを読み込むってところを調べてみました。
Index、PageAがメインのswfで
PageBとPageCが1つの別ファイルになっています。

※nium先生ご本人からの指摘で、絶対パスで書いても、読み込み前後どちらでもうまく動作するとのこと。
ちゃんとパスをもう一回確認するとうまくできました。ソースを修正しておきます。

制作する際に別ファイルだけの動きを確認したいなーと思ったのですが、sceneIdを相対パスで指定したところうまく動作しませんでした。
絶対パスをベタ書き(/index/hoge/fuga)にするとうまく動作するのですが、これだと単体の動作と他から読み込まれたときの動作でパスが変わってくるから、単体での動作確認がうまくできません。
なので、そのあたりをうまく解決したいなと思い、調べてみるとidをシーンに指定してあげれば
getSceneByIdなんていうのがあってこいつを使えばどこからでもSceneObjectを参照できるみたいです。
なので、そいつを使ってあげることでSceneObject.sceneIdを動的に変更することができました。

あと、SceneLoaderを拡張したClassSceneLoaderっていうのが本に載っていて、
プログレスバーみたいにswfを読み込んでいる状況をどうやって取得すればいいのかな?と思い、
LoadSWFを参考にして書いたのが下のプログラムです。

package sample.util {
	import flash.net.URLRequest;
	import flash.text.TextField;
	import jp.progression.commands.net.LoadScene;
	import jp.progression.scenes.SceneLoader;
	/**
	 * original: ProgressionによるFlashコンテンツ開発ガイドブック 4-3-5
	 */
	public class ClassSceneLoader extends SceneLoader
	{
		public var swfFileName:String;
		
		public function ClassSceneLoader(filename:String, name:String = null, initObject:Object = null) 
		{
			super(name, initObject);
			swfFileName = filename;
		}
		
		//シーンが読み込まれる際の処理
		protected override function atScenePreLoad():void {
			var tf:TextField = new TextField();
			addCommand(
				new LoadScene(new URLRequest(swfFileName), this, null, {
					//こんな感じにしておくと、ローディング状況が表示できた
					onStart:function() {
						container.addChild(tf);
						tf.x = 200;
						tf.y = 180;
					},
					onProgress:function() {
						var a:Number = this.bytesLoaded;
						var b:Number = this.bytesTotal;
						var n:int = Math.floor(100 * a / b);
						trace(n + "%");
						tf.text = n + "%";
					},
					onComplete:function() {
						container.removeChild(tf);
					}
				})
			);
		}
		
		//シーンが破棄された場合の処理
		protected override function atScenePostUnload():void {
			// 読み込んだシーンを破棄する
			unload();
		}
		
	}

}

参考までに外部ファイルの1ページも

package sample.view.page 
{
	import jp.progression.casts.CastSprite;
	import jp.progression.commands.tweens.DoTweener;
	import jp.progression.scenes.SceneId;
	import jp.progression.scenes.SceneObject;
	import sample.view.button.BasicButton;
	import jp.progression.scenes.getSceneById;
	/**
	 * ...
	 * @author KinkumaDesign
	 */
	public class PageB extends CastSprite
	{
		public var btn1:BasicButton;
		public var btn2:BasicButton;
		public var btn3:BasicButton;
		
		public function PageB( initObject:Object = null ) 
		{
			super( initObject );
			
			btn1 = getChildByName("btn1") as BasicButton;
			btn1.setLabelStr("index");
			btn1.sceneId = new SceneId("/index");
			
			btn2 = getChildByName("btn2") as BasicButton;
			btn2.setLabelStr("Page A");
			btn2.sceneId = new SceneId("/index/page_a");
			
			btn3 = getChildByName("btn3") as BasicButton;
			btn3.setLabelStr("Page C");
			//var pageC:SceneObject = getSceneById("PageC");
			//btn3.sceneId = pageC.sceneId;
			btn3.sceneId = new SceneId("/page_b/page_c");
		}
		
		override protected function atCastAdded():void 
		{
			alpha = 0;
			btn1.alpha = 1;
			btn2.alpha = 1;
			btn3.alpha = 1;
			
			addCommand(
				new DoTweener(this, { alpha:1, time:0.5 } )
			);
		}
		
		override protected function atCastRemoved():void 
		{
			addCommand(
				new DoTweener(this, { alpha:0, time:0.5 } )
			);
		}
	}

}

これでなんとか今から実装するものに間に合いそうです。
さわった感じ、自分で実装するのより楽になるのは、今のところ下記の点かなー。

・ページ遷移のロジックに全くさわらなくてもよい
・コマンドによる非同期処理(これはフレームワークを通じて使えるので統一された書き方ができて、後からソースを見やすそうですね)
・想定されるイベントがあらかじめ登録されているので、実装はそれを上書き(override)するだけ。
なので、addEventListener、removeEventListenerをほとんど使わなくてもよい。

これは確かに慣れてくれば、おまかせコースな感じでいいかも!ですね。
あと、nium先生、本が1冊書けるぐらいの質と量をよく作りこんだなー。すげーなー。とも思いました。
いや、ホントすごいです。レベル高し。

それで今日のまとめとして、サイトを作るのにやることは以下の3つ

1.シーンを作る(シーンは他のシーンとの関連性を定義する。また、そのシーンの見た目であるページを登録する。という2つの大きな役割がある)
2.ページを作ってシーンに登録する
3.ページにボタン(CastButton)を配置してボタンにシーンのパスを登録する

というのが基本の流れで、あとはこれの量産です。
そんで上の1~3だけだと、ページ遷移がパッパッパときりかわるだけなので、フェードインなどのなめらかな遷移ができるようにコマンドを使い非同期処理でのりづけするというイメージだと思いました。

自分が最初に困ってしまったのは、progはいろいろできるので逆にどれが一番最小の構成なのかが
よくわからなかったところだと思いました。
最小構成さえわかってしまえば、あとはそれに便利機能を肉付けしていくだけなんで、都度勉強していけばどんどん楽になっていけるかなと。

あとは、ページやシーンなどのファイルがすぐにいっぱいになっちゃうので、1つのクラスを再利用してクラスファイルを増やさない生産性をあげる作り方なんてのも、もうちっと勉強したいと思いました。
CastButtonのクラス流用は簡単にできたので、やっぱそこだなー。

ではでは。

LINEで送る
Pocket

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

ページトップへ戻る