Sunflat のブログ

ソフトウェア開発についての話題が多いかも

gotoAndPlayの謎(2)

Flash Liteを知っている人向け,…というか単なるメモです)

id:sunflat:20060927 の続き.外部のムービークリップから,tellTarget() { gotoAndPlay() }で再生ヘッドをジャンプさせると,ムービークリップ内部のフレームアクションと干渉して誤動作する問題に関して.

どうやらFlashでは,全ムービークリップの現在位置のフレームアクションが一旦実行予約された後,後から一気に実行される仕組みになっているようだ(推測).
一方で,gotoAndPlay()系の関数は,対象となるムービークリップの再生ヘッド位置(_currentframe)を即変更しまう.

例えば,前回の現象は,mc1がframe 12にいる場合に,他のMovieClipのアクション「 tellTarget(”/mc1”) { gotoAndPlay(10); }」と,mc1のアクション「prevFrame(); play();」が実行予約された後,一気に実行されるために発生する.

これを回避するためには,(他のMovieClipからの)gotoAndPlay()を,即実行するのではなく,実行予約(実行予約系列の末尾に追加)して,今予約されている全アクションを実行した後にgotoAndPlay()を実行してもらえば良さそう.

例えば上の例の場合は,mc1のアクション「prevFrame(); play();」の実行後に,「 tellTarget(”/mc1”) { gotoAndPlay(10); }」が実行されれば問題無い.

解決案

どうすれば,任意のアクションを実行予約系列の末尾に追加できるんだろうか.
とりあえず,新たなムービークリップインスタンスを生成して,そのムービークリップのフレームアクションの中に,追加したいアクションを書いておけば良い気がする.


シーンのルートに,「jmp」というフレームラベルで,以下のようなサブルーチンを定義

jmpc=(jmpc+1)%1024;
duplicateMovieClip("jmp", "jmp" add jmpc, jmpc+30000)
tellTarget( "jmp" add jmpc) {
	t=/:jmpt;
	l=/:jmpl;
}


シーンのルートに,jmpというインスタンス名で空のムービークリップを作成し,先頭フレームに以下のフレームアクションを記述

/:jmpn=_name;
if (/:jmpn ne 'jmp') {
	/:jmpl=l;
	trace(/:jmpn add ":" add t add " to " add l);
	
	// 再生ヘッドを移動させる
	tellTarget(t) { gotoAndPlay(/:jmpl); }
	
	// 自分を消す
	tellTarget("/") { removeMovieClip(jmpn); }

}else{
	// prototype役
	_visible=false;
}


実際にgotoAndPlay()を実行したい時は,以下のようにする.

// tellTarget("targetMovieClip") { gotoAndPlay(label); } の代わり

/:jmpt=targetMovieClip._target;
/:jmpl=label;
tellTarget("/") { call("jmp"); }


もっとマシな解決策がありそうな気がするが,一応望みどおり動いているみたい.

その他の検証結果

  • gotoAndPlay()を呼び出した直後から,既に移動先フレームに存在する子ムービークリップにアクセスできるようだ