Soundクラスのplay()の第一引数

Flash CS3に作った頃のSWFが最近動かなくなっているとのことで調査。
2年以上SWF自体は変更していないのでブラウザ(FlashPlayer)側に原因がありそうだということで調べていたら、単音をループ再生させているところが原因でした。
seChannel = se.play( -40, 9999);
playの第一引数にマイナス指定しているのは、ループ時に-40ミリ秒の無音を空けたかったため。以前はこれで動いてた。今のブラウザで見ると play() の第一引数がマイナスだと Chrome の FlashPlayer では0扱いとなり、FireFox では音が鳴らない上に、それ以外の部分まで操作不能になるという状況だった。
結局、-40でスクリプト側で無音を確保するのをやめて音声データ側に無音を継ぎ足して解決させました。

あと、CS3の時の.flaファイルをCS5で開いてパブリッシュしたら、フォント埋め込みのダイナミックフォントが一切表示されなくて焦った。
textField.embedFonts = true;
をコメントアウトすれば動くので、理由を探ったところ ActionScript 上の TextFormat インスタンスでのフォント指定文字列がCS5だと変わっていた。(※どうやらCS4から変わったらしい)
大重さんの「フォントの英語名を調べる – ActionScript 3.0入門ノート CS4」のエントリを見て英語名を調べて指定し直したところ、きちんとテキストが表示されるようになった。
※実は変更前も英語指定だったんだけど、なんか違う英語表記に変わっていた。

gotoAndStop(2)後のaddEventListenerの挙動

あるMC”panel”のフレーム1に”btn1″、フレーム2に”btn2″があり、これを条件分岐で切り替える構造のFlashだとする。下みたいな実装。

if(hoge){
panel.btn1.addEventListener(MouseEvent.CLICK, mouseDownHandler);
}else{
panel.gotoAndStop(2);
panel.btn2.addEventListener(MouseEvent.CLICK, mouseDownHandler);
}

要はフレーム移動直後に、その移動先フレームにのみ存在するボタンに対して addEventListener するケース。

FlashIDE上でのパブリッシュ設定が FlashPlayer10 の時は動くのに、FlashPlayer9 設定に切り替えると null エラーになる。

ビックリした。

ちなみに両フレームともにまたがるように配置されたボタンなら大丈夫、あくまでgotoAndStop移動後に初登場のオブジェクトに対してイベント付けた時に起こる。

インスタンスが存在するかどうか調べるAS3

インスタンスが、表示リストに存在しているかどうかは、getChildByName()メソッドを使って判定することができます。(via FlashゲームPG講座 for AS3.0)(contains を使った判定方法もこの類かと)

それとは違い、インスタンスを作ったかどうかを判定したい時がありましたよ!というのが今回のテーマ。

続きを読む インスタンスが存在するかどうか調べるAS3

FLVPlayback コンポーネントのバッファまわり

再生コントロールバーのない、高画質垂れ流し動画を使うケースは、なるたけロード時間を短くすることを心がけると思います。
FLVPlayback コンポーネントを使う場合、

  1. 再生の途中で途切れない程度に十分にダウンロード(バッファ)できたら再生開始
  2. それでも途中でバッファがなくなったら「ローディング中ですよ」アイコンとか表示
  3. そこからある程度バッファが貯まったら再生開始

という実装が良さそう。
まず1は FLVPlayback コンポーネントのデフォルトのバッファ時間は0.1らしい(via:godagoda.net)ので、5秒ぐらいにする。僕もプログレッシブダウンロードなんで「低速環境で画質アップ」効果を期待。

//バッファタイムをデフォルト0.1から5秒に変更
my_flvPlayback.bufferTime = 5;

2は bufferingStateEntered イベントを監視して、途中でバッファの為に動画が一時停止したらローディングアイコンをaddChildして表示する。bufferingStateEntered は途中で止まる時だけじゃなく、しょっぱなも呼び出されるイベントだということに注意。

再び再生が開始されたら playingStateEntered イベントでローディングアイコンを消す。
このときの再生って、また bufferTime で設定した秒数ぶん(5秒)バッファできたら再開するってことでいいのかな。
(※今から2,3を実装するところ)
FLVPlayback コンポーネント上に FLV ロードするような場合、ローカル環境上の「ダウンロードのシュミレート」ではシュミレートできないらしく、サーバーにアップして試すんだけど、今時ネットも高速回線なので、なかなかこういった低速回線用のデバッグが面倒。

追記:Firefox Throttle(Windowsのみ) というアドオンを使えば、回線速度を低速シミュレートできると kinkuma_design さまに教えていただきました。

追記2:上記2,3も実装。シークバーのないビデオコンテンツだとしても、ローディング状況を確認しつつ開発したい時は、コンポーネントインスペクタから、SeekBarをステージ上に配置して、インスタンス名 sb(任意)とした時

my_flvPlayback.seekBar = sb;

とするだけでローディング状況をバーで知ることができて簡単。あとはお好みで BufferingBar も使えます。こちらはバッファ状態になった時だけ床屋のくるくるみたいなのが表示されるというパーツ。
別方法として FLVPlayback コンポーネントにスキンをあてる方法もあるけど、なぜか当て込むと コンポーネントのwidthが2倍に算出されておかしかったのでやめた。スキンの場合はスキン用のswfも別途アップロードするのを忘れずに。

追記3:バッファ状況も十分なのに映像が止まることがある。裏側でガベージコレクションが発動してる疑惑。もしそうなら、動画再生中は強制的に GC を止めたい。できるのか?

追記4:ここまでの記事を全部見直し。再生が始まった後で、ダウンロード待ちの状態に戻して十分にダウンロードされてから自動的に再生を再開するには、pause() メソッドを使用し、次に playWhenEnoughDownloaded() メソッドを使用します。とある。3 の playingStateEntered も「バッファリング状態に移行してから再生状態に移行することが多いので、play() メソッドを呼び出した直後または対応するコントロールをクリックした直後には、イベントが発生しない場合があります。」とあるので、上記リスト通りの実装すると信頼性低くなるなこりゃ。

playingStateEntered がデリケートなんだったら stateChange で監視しようと思ったんだけど、同じ動画を再度見ようとすると STATE_CHANGE すら動かない場合がある。困った。
ここまでわかったのは、VideoEvent.READY だからといって、即 playWhenEnoughDownloaded() とは限らないので、playWhenEnoughDownloaded() で再生スタートしたタイミングで任意メソッドを動かしたいんだけど、playingStateEntered も stateChange も(ローカルでは動くのに、ネットに上げると)バッファされないケース(でもstateは変わってるのになぁ?)で呼び出されないケースがあるからこれから独自実装しようとしている。

FLV使う時さぁ

前のエントリ

  1. FLV動画をタイムラインに貼付け、タイムライン上で所定の場所にフレームスクリプトを書いて制御する
  2. 動画にキューポイントを設定し、制御する

で、1を選ぶデメリットって何だろうなと。
→追記:swf全部ロードしてからでないと再生が始まらないことか。
→さらに追記:これ嘘でした。子swfのルートのタイムラインに貼り付けたFLVはプログレッシブダウンロードできます。feb19様にいただいたコメントを参照!

親swfから子swfをロードする構成で、子swfのタイムラインに直接貼るか、子swfにFLVPlaybackコンポーネントを貼るかの違いであれば、どっちでもいいような、むしろ1の方が手っ取り早いように思えてきた。親swf自体にFLVPlaybackコンポーネントを用意するのが(unloadのやり方が下手くそな僕には)メモリリーク対応的にはベストかもだけど、今回それはやらないとして。やっぱりそうしたほうがいいな。最終的にはコメントに追記したような仕様にしました。メモリリークも解決しました。

子swfから親swfの変数・メソッドを呼び出す

flvビデオをタイムラインに貼付けてちょっとフレームアクション追加してswf化、それを子swfとして、親swfからロードして使うというケースがあるとします。
その中で再生中のムービーのあるタイミングで親swfのメソッドを実行したいことがあります。
つまり表題のように子swfから親swfの変数・メソッドを呼び出すというケース。

続きを読む 子swfから親swfの変数・メソッドを呼び出す

addEventListenerで実行するメソッドにパラメーター渡す

タイトルの通り、そういうことをしたい時があります。

探したら apeirophobia さまのブログに書かれていました。
apeirophobia: addEventListenerで一緒に引数を渡したい

addEventListener(Event.SELECT, hoge(3));
private function hoge(num:int){
	return function(e:Event):void{
		trace("番号:"+num);
	}
}

みたいな感じにするそうな。
hogeメソッドにvoid指定するとなんでエラーになるのかとか、そういうプログラム的なことにあまり興味が湧かずにコピペして動いて安心してしまう僕はプログラマ属性ゼロだなぁと思ったりした。

ある条件下でのフレームのランダム移動における再帰処理

あまりこんなケースはないと思うけれど、
あるムービークリップシンボルのフレーム内を直前のフレームと重複がないように移動させたい。ただし次に移動すべきフレームは配列として[1,4,5,10]のような配列に記録されている時:

続きを読む ある条件下でのフレームのランダム移動における再帰処理