BreakとReturn

  • 2009 年 12月 7 日
  • kosuke

Progression 4 にある中断コマンド、BreakとReturnについて、その違いをメモ。

シーン /index/a/1 から シーン /index に移動する時、
シーン /index/a/1 のGotoで Breakの場合とReturnの場合で試します。

protected override function atSceneGoto():void{
	this.addCommand(
		new Break(),  // ←これを使う場合と
		new Return(), // ←これを使う場合の違い
		new Trace( "a/1 - atSceneGoto" )
	)
}

Breakを使った場合
new Trace( “a/1 – atSceneGoto” ) は実行されないが、その後はシーン遷移に基づき シーン /index まで実行される。
つまりBreakの場合、処理中のコマンドリストはBreak実行された時点で完了となり、その後のコマンドリストは引き続き処理される。

試しに、Gotoを以下にした場合、

protected override function atSceneGoto():void{
	this.addCommand(
		new SerialList( {
				onComplete:function():void{
					trace("onComplete");
				}
			}, 
			new Break(),
			new Trace( "SerialList" )
		),
		new Trace( "a/1 - atSceneGoto" )
	)
}

new Trace( “SerialList” )は処理されないけど、
trace(“onComplete”)
new Trace( “a/1 – atSceneGoto” )
は実行される。

Returnを使った場合
new Trace( “a/1 – atSceneGoto” ) は実行されず、Returnが実行された時点でシーン遷移が停止する。

Breakの時と同様以下を試すと

protected override function atSceneGoto():void{
	this.addCommand(
		new SerialList( {
				onInterrupt:function():void{
					trace("onInterrupt");
				}
			}, 
			new Return(),
			new Trace( "SerialList" )
		),
		new Trace( "a/1 - atSceneGoto" )
	)
}

new Trace( “SerialList” )
new Trace( “a/1 – atSceneGoto” )
とも処理されず、
trace(“onInterrupt”)は実行される。つまり中断になるわけです。
ちなみに、Progressionクラスの stop() メソッドもReturnと同じっぽい。
試しに以下を実行した場合も結果は同じだった。

protected override function atSceneGoto():void{
	this.addCommand(
		new SerialList( {
				interruptType:CommandInterruptType.SKIP,
				onInterrupt:function():void{
					trace("onInterrupt");
				}			}, 
			function():void{
				manager.stop();
			},
			new Trace( "SerialList" )
		),
		new Trace( "a/1 - atSceneGoto" )
	)
}

@nifty 年賀状 2010

  • 2009 年 11月 20 日
  • kosuke

@nifty 年賀状 2010 用にオリジナル年賀状素材を7点作りました。
といっても作ったのは僕じゃありませんが。Yさんのお仕事。
@nifty 年賀状 2010には多数年賀状素材が揃ってます。
年賀状をお探しの際は是非ご覧ください。

@nifty 年賀状 2010 用 オリジナル年賀状素材
http://nenga.nifty.com/
Producer / 株式会社グッドファーム・プランニング
Design&Illustration / Yoco,Nakamura.nipx

Proxyクラスのこと

  • 2009 年 11月 9 日
  • kosuke

Proxyクラスはどんな時使うものか見当のつかない状態だったのだけど、便利に使えそうなケースが見つかったのでエントリー。

Proxyについてはここに説明がある。
ActionScript 3.0 言語およびコンポーネントリファレンス
これ読んでも正直なんのこっちゃって思っていた。

思いついた方法は、複数のオブジェクトのいくつかのプロパティを一斉に変更したい時、Proxyを介して変更するってもの。いろんな方法があると思いますが、Proxyを介して行うのもなかなか便利そうです。

以下のように複数の表示オブジェクトがあり、それらのプロパティを変更したいとします。

This movie requires Flash Player 10.0.0

まず、表示オブジェクトを配列なりVectorなりに格納する。

var vector:Vector.<MovieClip>	= new Vector.<MovieClip>();
vector.push( this.arrow0 );
vector.push( this.arrow1 );
vector.push( this.arrow2 );
vector.push( this.arrow3 );

これをProxyを継承したクラスに渡す。

 
this.proxy	= new ProxyMcGroup( vector );
 

Proxyを継承したクラスではVectorを変数に代入する。
継承する時はdynamicで宣言しておいた方が、proxy.xのようにドットシンタックスでプロパティを参照してもエラーにならないのでいいと思う。

public dynamic class ProxyMcGroup extends Proxy{
 
	private var _item:Vector.<MovieClip>;
 
	public function ProxyMcGroup( _item:Vector.<MovieClip> ){
		super();
 
		this._item		= _item;
	}
 
}

Proxyを継承したクラスのsetPropertyをオーバーライトし、Vectorを繰り返し処理でプロパティを変更する。

override flash_proxy function setProperty(name:*, value:*):void{
	for each( var i:MovieClip in this._item ){
		i[name] = value;
	}
}

ひとまずこれだけで、複数オブジェクトのプロパティを一斉に変更できるようになる。
複数オブジェクトが同じプロパティを持つことを前提に、どのプロパティも変更できる(これが便利なポイント)はずです。

このままだと、setterだけなので取得が出来ない。
また例えばTweenerで動かす時はTweenerがhasOwnPropertyを使ってプロパティの有無を確認したりするので、必要に応じて拡張していく。
サンプルのは以下のようプロパティ値をDictionaryに保存するようにしたり、for…inステートメントでプロパティの参照が出来るようにしてみた。

package{
 
 
	import __AS3__.vec.Vector;
	import flash.display.MovieClip;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;
	import flash.utils.Dictionary;
 
 
	public dynamic class ProxyMcGroup extends Proxy{
 
 
		private var _item:Vector.<MovieClip>;
		private var _dictionary:Dictionary;
		private var _prop:Array;
 
 
		public function ProxyMcGroup( _item:Vector.<MovieClip> ){
			super();
 
			this._item			= _item;
			this._dictionary	= new Dictionary(true);
			this._prop			= [];
		}
 
 
		override flash_proxy function callProperty(methodName:*, ...args):*{
			trace( "callProperty:" + methodName + "," + args );
			return;
		}
 
 
	    override flash_proxy function getProperty(name:*):*{
	    	trace( "getProperty:" + name );
	    	return this._dictionary[name];
	    }
 
 
	    override flash_proxy function setProperty(name:*, value:*):void{
	    	trace( "setProperty:" + name + "," + value );
	    	if( !this._dictionary.hasOwnProperty(name) ){
	    		this._prop.push( name );
	    	}
	    	this._dictionary[name] = value;
	    	for each( var i:MovieClip in this._item ){
	    		i[name] = value;
	    	}
	    }
 
		override flash_proxy function hasProperty(name:*):Boolean{
	    	trace( "hasProperty:" + name );
			return this._dictionary.hasOwnProperty(name);
		}
 
 
		override flash_proxy function deleteProperty(name:*):Boolean{
			trace( "deleteProperty:" + name )
			this._prop = this._prop.filter(
				function( item:*, index:int, array:Array ):Boolean{
					if( item == name ) return false;
					else return true;
				}
			);
			return delete _dictionary[name];
		}
 
 
	    override flash_proxy function getDescendants(name:*):*{
	    	return;
	    }
 
 
		override flash_proxy function nextNameIndex(index:int):int{
			trace( "nextNameIndex:" + index );
			if( index < this._prop.length){
				return index + 1;
			}
			else{
				return 0;
			}
		}
 
 
		override flash_proxy function nextName(index:int):String{
			trace("nextName:" + index);
			return this._prop[index - 1];
		}
 
 
		override flash_proxy function nextValue(index:int):*{
			trace("nextValue:" + index);
			return this._dictionary[ this._prop[index - 1] ];
		}
 
 
	}
}

動かしているところはProgressionのSerialListを使っています。
動かす前に使うプロパティに値を入れておく。

this.proxy.rotation = 0;
this.proxy.alpha	= 1;
this.proxy.scaleX	= 1;
this.proxy.scaleY	= 1;
 
var comm:SerialList	= new SerialList( { onComplete:function():void{ this.execute(); } },
	new DoTweener( this.proxy, { rotation:360, transition:"easeInOutExpo", time:2 } ),
	new DoTweener( this.proxy, { alpha:0.5, transition:"easeNone", time:1 } ),
	new DoTweener( this.proxy, { scaleX:1, scaleY:1, _bezier:{ scaleX:0, scaleY:0 }, transition:"easeInOutExpo", time:1 } ),
	new DoTweener( this.proxy, { rotation:0, transition:"easeInOutExpo", time:2 } ),
	new DoTweener( this.proxy, { alpha:1, transition:"easeNone", time:1 } )
);
 
comm.execute();

ProxyはTweensy FXの時に久しく出てきて今回の使い方を気づいた。
思いもよらないところでつながることは良くある。何かを調べるってことは良いことだ。

インバースキネマティックを試す

  • 2009 年 11月 6 日
  • kosuke

Flash CS4で目玉機能の一つでありながら、なんとなく影が薄いインバースキネマティック。
その理由か否か試してみてわかったことで、スクリプトからはちょっと使いづらいなぁと思った。

試してみたのはこちら。なんだか夢に出てきそうな気持ち悪さ。

This movie requires Flash Player 10.0.0

rotation関連のスライダーは花の幹の部分の全ジョイントを変更。
IKMoverは花のアイコンを動かしています。

まず、インバースキネマティックの構造定義をアーマチュアといい、シンボルをつなぐ場合、表示オブジェクトが骨(ボーン)でつながった構造になります。ちなみにシェイプにボーンを通すことも出来る。


▲オーサリングツールで設定

アーマチェアはIKArmatureクラスで定義されるのだけど、これがスクリプトでは作れない。
Flashのオーサリングツールからしか作れないということ。

つまり、new IKArmature()とかして、スクリプトから表示オブジェクトをボーンでつないでいくことは出来ません。定義されたアーマチェアの構造を変更するのも無理。たとえばスクリプトでボーンを追加するとかも出来ない。


じゃあ、スクリプトで何が出来るかっていうとオーサリングツールで設定できるプロパティの変更とボーンの接続部(ジョイント)を移動させるとかです。
たとえば今回使った回転関連のプロパティは以下のように対応しています。

蛇足ですが、上のキャプチャで最小の-45°のところ、スクリプトで取得するとラジアンになって返ってくる。でもスクリプトで設定するときは角度。うーん…。

ik2

普通の使用方法ならスクリプトですることも大抵はポーズの変更をすることかと思う。
そうなるとポーズを作るのに単純なアニメーションはスクリプトでもと思いますが、いわゆる機械的じゃないアニメーションというか…規則的でないアニメーションはタイムラインで作り込んでいく方が効率いいってなるんだよなぁ。何か工夫を考えたい。

AS2でリンケージ識別子が衝突する時のまとめ

  • 2009 年 10月 30 日
  • kosuke

先日、仕事でハマったところのまとめ。

僕の場合、普段は親SWFから子SWFを読み込んだら不用になったタイミングでアンロードします。その方が無駄にメモリー食わないとでしょうし。

しかし、コンテンツ毎に読み込むような、子SWFがいくつもあったりする場合、毎回ローディングするのが鬱陶しい…とか、サーバー負荷が…とかの理由でアンロードしない仕様で作る場合もあったりする。

この時、複数のSWFに同名のリンケージ識別子があると衝突することがあります。
AS2の場合、この回避には識別子をユニークにするしかない(であってる?)と思います。その挙動を記録しておきます。


同じリンケージ識別子

上記の検証ファイルは、親SWFのindex.swfから、
子SWFのcontent1.swfとcontent2.swfを読み込んで試したもの。

子SWFとなる二つのファイルには、同じリンケージ識別子Mainで、それぞれのクラスを定義した、色違い・マウスアクション違いの矩形をアタッチしています。

content1.swfとcontent2.swf

public var main:MovieClip;
 
public function onLoad():Void{
	//Mainをアタッチ
	this.main	= attachMovie( "Main", "main", this.getNextHighestDepth() );
}

content1.swfのMain。

public var field:TextField;
 
//マウスプレスで「1」を表示	
public function onPress():Void{
	this.field.text = "1";
	this.field._alpha = 100;
	Tweener.addTween( this.field, { _alpha:0, transition:"easeNone", time:1 } );
}

content2.swfのMain。

public var field:TextField;
 
//マウスプレスで「2」を表示	
public function onPress():Void{
	this.field.text = "2";
	this.field._alpha = 100;
	Tweener.addTween( this.field, { _alpha:0, transition:"easeNone", time:1 } );
}

親SWFの各ボタンは、load、unload、子がアタッチしたMainインスタンスをremoveするボタンを設置。

//content1.swfをロード
public function loadContent1():Void{
	if( this.content1.main.getBytesLoaded() ) return;
	//ロード前ならロード
	if( !this.content1.getBytesLoaded() ){
		this.loader.loadClip( "content1.swf", this.content1 ); 
	}
	//ロード済みの場合onLoad実行
	else{
		trace("loaded");
		this.content1.onLoad();
	}
}
 
 
//content2.swfをロード
public function loadContent2():Void{
	if( this.content2.main.getBytesLoaded() ) return;
	//ロード前ならロード
	if( !this.content2.getBytesLoaded() ){
		this.loader.loadClip( "content2.swf", this.content2 ); 
	}
	//ロード済みの場合
	else{
		trace("loaded");
		this.content2.onLoad();
	}
}
 
 
//content1.swfアンロード
public function unloadContent1(){
	this.content1.unloadMovie();
}
 
 
//content2.swfアンロード
public function unloadContent2(){
	this.content2.unloadMovie();
}
 
 
//content1.swfがアタッチしたmainを削除
public function removeContent1(){
	this.content1.main.removeMovieClip();
}
 
 
//content2.swfがアタッチしたmainを削除
public function removeContent2(){
	this.content2.main.removeMovieClip();
}

これを使って、
Content1LoadクリックしてContent2Loadクリックすると、子SWFのMainが表示されます。表示された矩形をクリックすると左側は「1」右側では「2」が表示されます。

続けて、Content1Removeをクリック。左側のmainがremoveされる。
再度、Content1Loadをクリック。再び左側のmainがアタッチされて表示される。
左側のmainをクリックすると、今度は「1」のはずが「2」と表示されます。

removeでは、読み込んだ子のSWF自体をunloadしていません。この時同じリンケージ識別子があると再アタッチの際、あとで設定されたリンケージ識別子のクラスが適用されるみたい。シンボル自体は正しく表示されるのだけれど。

この症状はunloadをした場合とか、上書きで読み込んだ場合等は発生しないです。
Content1Unloadをクリック。Content1Loadをクリックした場合、正しく「1」が表示されます。

再アタッチしなければ問題なさそうな気もする。
とにかくリンケージ識別子のネーミングには気をつけよう。
というか僕的にはunloadしたい。

読み込んだものを消さない仕様の場合(に限らないが…)、複数人で制作する場合って、ある程度、親子それぞれの仕様とかネーミングルールとか気をつけて決めないと結合した時に面倒なことになりそうですね。

Logic Express 9 買った

  • 2009 年 10月 25 日
  • kosuke

AS3によるサウンドライブラリFLMMLSiONを触っていたら、DTM熱が沸いてつい買ってしまったLogic Express 9。よせばいいのに…俺。

きっかけは、先のSiONを試そうと文法を学びつつMMLを打っていたはずが、音が出るのが楽しくなってきて、いつの間にか好きな曲の耳コピーになり、DominoやGarageBandでピアノロールと格闘することに…。GarageBandに触発された時は三日坊主だった音楽アプリですが今回は結構夢中になってました。

そうするとDominoやGarageBandでやりたいことは出来るのだけど、Dominoは慣れないWindows環境、GarageBandはMIDI書き出しが出来ない(MIDI書き出ししたいのは、あとでMIDIをMMLに変換かけたいから。もともとはFlashの手法として活用するのが目的だし。)のがどうも気になってきて、どうせ新しく覚えるなら今後も使うアプリにしようと思ったわけ。
GarageBandでMIDI書き出しが出来れば、DTMシロウトの僕にはそれで充分だったんですけどね。

僕の周りはWeb関連の仕事をしている人がほとんどで、DTMに詳しい人はいませんが案外DTMアプリ持っていたりする。やってみたくなるんだよなぁ。音って。誰にも直感的だしね。

周りはReason使ってる人が多い。
DTMのアプリは、PhotoShopとかIllustratorみたいな「超定番」ってない感じだよね。3Dもそんな感じか。選べるってことは素晴らしいが悩む。
僕はReasonかCubaseにしようかなぁと思ったけど、最終的にGarageBandからの流れでLogic Expressにした。さすがにLogic Proは高くてろくに使わなかった時、後悔する可能性があるんで。

僕の音楽の知識は昔、ギターやってましたって位。
アプリがあったからって一朝一夕で出来ることじゃないでしょうけど何かに役立つといいなぁ。
たまには別のこともやってみたいみたいな。自分的にはそんな感じです。

Progression4 LoopListを試してみた

  • 2009 年 10月 23 日
  • kosuke

Progression4に追加された新しいコマンドリストの一つにLoopListがあります。
LoopListは名前の通り、登録されたコマンドを繰り返し処理するコマンドリストです。
これを試していてProgression4で変わったことも気づいたので記録します。


LoopListを試す

LoopListはループの回数をrepeatCountで指定出来ます。
上のサンプルだと、indexSceneでは、

this.addCommand(
	new LoopList( 2, null,
		new DoTweener( this.logo, { scaleX:0.5, scaleY:0.5, transition:"easeNone", time:0.25 } ),
		new DoTweener( this.logo, { scaleX:1, scaleY:1, transition:"easeNone", time:0.25 } )
	)
)

Scene1では、

this.addCommand(
	new LoopList( 2, null,
		new DoTweener( this.logo, { scaleX:2, scaleY:2, transition:"easeNone", time:0.25 } ),
		new DoTweener( this.logo, { scaleX:1, scaleY:1, transition:"easeNone", time:0.25 } )
	)
)

で、それぞれ2回繰り返しを指定しシーン遷移時に拡大縮小しています。

これは問題ないと思う。
注意すべきは、コマンドを単体で使う時。

Scene2のLoopListは、ナビゲーションから開始や停止できるようにしています。

this.t0 = new DoTweener( this.logo, { x:520, transition:"easeNone", time:0.5 } );
this.t1 = new DoTweener( this.logo, { x:120, transition:"easeNone", time:1 } );
this.t2 = new DoTweener( this.logo, { x:320, transition:"easeNone", time:0.5 } );
 
this.comm = new LoopList( 2, null, 
	this.t0,
	this.t1,
	this.t2
);

ここではシーン遷移時に処理しているのではなくて、LoopListのインスタンスをマウスイベントで実行したり停止したりしています。

注意すべきは、LoopListを実行して停止してもループ回数を数えるcountは0に戻らないという点。
なので、Scene2でexecuteボタンを押すと、初回は2回ループで停止しますが再度executeを実行してからは無限ループになります。止めるにはstopを使う。
countは読み取り専用で書き込めないのと、カウンタを戻すresetメソッドはprotectedで宣言されている為countを戻すのは、あらかじめLoopListを継承したカスタムコマンドを使うとかかなぁと。

stopメソッドで止めた時と、interruptメソッドで中断した時の挙動の違いも確認。
stopで止める時は、処理中のコマンドが終わった時点でループが停止になる。
停止後に再度executeした時も、その次のコマンドから実行されています。

対して、interruptで中断した時は他と同様にコマンド中断処理が実行されます。
再度executeした時も、中断処理後そのままならループの最初のコマンドから実行される。この時もcountは0なっていない。

またProgression3と違って、コマンド中断時の処理方法をinterruptTypeで指定できる。
CommandInterruptTypeクラスに定数が用意されていて、

  • ABORT:int = 1
    コマンド中断時、その時点の状態で停止するように指定します。
  • RESTORE:int = 0
    コマンド中断時、処理が実行される以前の状態に戻すように指定します。
  • SKIP:int = 2
    コマンド中断時、処理が完了された状態と同様になるように指定します。

のようになっています。デフォルトはSKIPみたい。

これまで、エラーをキャッチしてexecuteCompleteとかやっていたのをこれだけで処理できるわけです。
中断した時のループ位置をとって、そこからループ再開させたりとかややこしいことをしたい場合は、イベント発生をキャッチして処理しなきゃいけないですが、大抵の場合、このinterruptTypeのパターンで済むんじゃないですかね。

上のサンプルでは、コンボボックスでLoopListに登録しているDoTweenerのinterruptTypeを変更出来るようにしています。挙動の違いが確認できると思う。

やっぱり便利になってるなぁ。

Progression4 Bata SceneLoaderを試してみた

  • 2009 年 10月 14 日
  • kosuke

Progression4 Bata、粛々と試しています。
目玉機能のSceneLoaderを試してみたのだけど、SCENE_POST_UNLOADイベントの挙動で悩んでいる。

API Referenceによれば、SceneLoaderがSWFを読み込み済みで、シーン移動時の目的地がシーンオブジェクト自身、または親階層の時にSceneEvent.SCENE_UNLOADが発生した時、atSceneUnloadが動くはずだと思う。

これを前提に試してみたものは、

indexScene以下に、4つのSceneLoaderを作って別々のSWFを読み込ませている。
SceneLoaderのatScenePreLoadでローディングバーを表示している。

SceneLoaderのatSceneUnloadでunloadを実行しているのだけれど、親に戻る時(Progression4Bataの文字を押した時)はもれなくSCENE_POST_UNLOADイベントが発生して、atSceneUnloadが動いている。ここまではOK。

問題は別のSceneLoaderに移動した時、atSceneUnloadが動いたり動かなかったりする。
atSceneUnloadが動かなければunloadがされないので、もう一度同じSceneLoaderに移動した時は、atScenePreLoadは動かないのでロディングバーは表示されない。これは期待通り。
Flashの出力を見てもscenePostUnloadが出力されないのだが、なんでなんだろう。

ズームのブラー

  • 2009 年 10月 13 日
  • kosuke

こちらは作ってみたけど、重くて使えなかったという代物。残念な話が続くなぁ。
ズームのブラー表現する場合って、どうしたって繰り返し拡大したイメージを重ねるしかないのかなぁ。
何かあったら教えて欲しいです。

ズームブラー

var blur:BlurZoom = new BlurZoom( ズームをかけたい対象, ズーム, オフセットX(0.5が中心), オフセットY(0.5が中心), クオリティ )

で適用します。

重いですがどうぞ。
画像が小さければギリギリ使えるかも。

as3
as2

package jp.nipx.effect{
 
 
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObjectContainer;
	import flash.geom.Matrix;
	import flash.geom.Rectangle;
	import flash.display.PixelSnapping;
	import flash.geom.ColorTransform;
 
 
	public class BlurZoom extends Bitmap{
 
		public function BlurZoom( container:DisplayObjectContainer, zoom:int=0, offsetX:Number=0.5, offsetY:Number=0.5, quality:Number=5 ){
			super( new BitmapData( 1,1 ), PixelSnapping.AUTO, true );
			this._rect	= new Rectangle();
 
			this.container	= container;
			this._zoom	= zoom;
			this._offsetX	= offsetX;
			this._offsetY	= offsetY;
			this._quality	= quality;
 
			this.render();
		}
 
		public var container:DisplayObjectContainer;
 
		private var _rect:Rectangle;
		private var _distance:Number = 0;
 
		private var _zoom:int;
		public function get zoom():int{
			return this._zoom;
		}
		public function set zoom(n:int):void{
			this._zoom	= n;
			this.render();
		}
 
		private var _offsetX:Number;
		public function get offsetX():Number{
			return this._offsetX;
		}
		public function set offsetX(n:Number):void{
			this._offsetX = n;
			this.render();
		}
 
		private var _offsetY:Number;
		public function get offsetY():Number{
			return this._offsetY;
		}
		public function set offsetY(n:Number):void{
			this._offsetY = n;
			this.render();
		}
 
		private var _quality:Number;
		public function get quality():Number{
			return this._quality;
		}
		public function set quality(n:Number):void{
			this._quality = n;
			this.render();
		}
 
		public function render():void{
			if( this.container.contains( this ) ) this.container.removeChild( this );
			if( this._zoom == 0 ) return;
 
			var rect:Rectangle	= this.container.getRect( this.container );
			var width:Number	= rect.right - rect.left;
			var height:Number	= rect.bottom - rect.top;
 
			if( this._rect.equals( rect ) ){
				this.bitmapData.fillRect( this._rect, 0x00000000 );
			}
			else{
				this.bitmapData.dispose();
				this.bitmapData = new BitmapData( width, height, true, 0x00000000 );
				var a:Number = Math.sqrt( Math.pow( width, 2 ) + Math.pow( height, 2 ) );
				var b:Number = a + 1;
				this._distance = b / a - 1;
			}
 
			var tx:Number = ( 0<rect.left ) ? 0 : -rect.left;
			var ty:Number = ( 0<rect.top )  ? 0 : -rect.top;
 
			this.bitmapData.draw( this.container, new Matrix( 1, 0, 0, 1, tx, ty ) );
 
			for( var i:int=1; i<this._zoom; i++ ){
				var s:Number	= 1 + ( this._distance * this._quality ) * i;
				var x:Number	= ( width  * s - width )  * this.offsetX;
				var y:Number	= ( height * s - height ) * this.offsetY;
 
				this.bitmapData.draw( this.container, new Matrix( s, 0, 0, s, tx - x, ty - y ), new ColorTransform( 1, 1, 1, 1/this._zoom ), null, null, false )
			}
 
			this.x = -tx;
			this.y = -ty;
			this.container.addChild( this );
		}
 
 
 
 
	}
}

ライフライン

  • 2009 年 10月 13 日
  • kosuke

今年のYJICA2009に応募したバナー作品です。
今度こそ金をと作ったものでしたがみごとに惨敗しましたねー。
また頑張ります。

CreativeDirection&Flash / KOSUKE,Nakamura. nipx
Illustration / Hiroki,Miura. MopStudio

なお、本作品制作にはモップスタジオの三浦氏に多大なるご協力をいただきました。久々のプライベートワークということでクライアントワークでは得られない楽しみもありましたが、貴重な時間を割いていただいた三浦氏にこころよりお礼申し上げます。

@