- 締切済み
Fpsを増減させても一定のスピードで再生する方法
Adobe Flash Pro CS6 でAS3を使っています。 質問はタイトルの通りなんですが例えばルートにフラッシュの再生速度を速くしたり遅くしたりするFps変更スイッチと mcA,mcBと2つのムービークリップがあるとして mcAはFPS変更の影響をうけるようにし、逆にmcBはFps変更の影響をうけないように2つのムービークリップを同時に再生をしたいのです。そのときmcA,mcB両方とも1フレームも欠けることなく再生したいです。 自分で試してみた方法は、mcBの中の全フレームに stop();を記述しルートに function mc_Play():void { mcB.play(); } setInterval(mc_Play,200); と記述して再生スピードを強制的に固定する方法を試したのですが、Fps変更ボタンを押してFps変更を行うときに、setIntervalで制御しきれていないのかもしれませんが、微妙にmcBの再生速度が遅くなったり速くなったりと変化してしまいます。何か他に良い方法はありませんでしょうか?例ではムービークリップの数を少なくしていますが実際のプロジェクトファイルでは、ムービークリップの数は20以上ありそれぞれが10フレーム以上の長さのアニメーションファイルを持っています。その20以上あるムービークリップの数個だけFPS増減の影響をうけないように再生速度を固定したいのです。
- みんなの回答 (1)
- 専門家の回答
みんなの回答
- BlurFiltan
- ベストアンサー率91% (1611/1754)
厳密な話なので良くわからない部分もありますが Timerクラスを利用すれば updateAfterEvent() が利用できるので解決することかもしれません。 メインタイムラインのフレーム1のステージ上には 仮に「fps4_btn」「fps8_btn」「fps12_btn」「fps16_btn」「fps20_btn」 というインスタンス名を付けた5つのボタンと 「mcA」と「mcB」というムービークリップがあるとします。 ※参考【添付図】↓ また, 「mcA」と「mcB」の内部は複数のフレームがあって, 「mcA」と「mcB」の中には何もスクリプトを書かないものとします。 (「mcB」の中には stop(); など一切書かないものとします。) その場合の メインタイムラインのフレーム1に書くスクリプト例です。 //------------------------------------ //***↓前置き(ボタンの動作)↓*** for (var i:int = 4; i <= 20; i+=4) { this["fps"+i+"_btn"].addEventListener(MouseEvent.CLICK,changeFPS(i)); } function changeFPS(fps:int):Function { return function():void { stage.frameRate = fps; } } //***↓本題(mcB 内の制御)↓*** //Timer インスタンス tm を作成(200ミリ秒毎,無限回数) var tm:Timer = new Timer(200,0); //指定ミリ秒毎に 関数 mc_Play を実行 tm.addEventListener(TimerEvent.TIMER,mc_Play); //タイマースタート tm.start(); function mc_Play(e:TimerEvent):void { //もし mcB 内が最終フレームであれば if (mcB.currentFrame == mcB.totalFrames) { //mcB 内を フレーム1 で停止 mcB.gotoAndStop(1); //それ以外は } else { //mcB 内を 次のフレーム で停止 mcB.nextFrame(); } //表示を即更新 e.updateAfterEvent(); } //------------------------------------ updateAfterEvent() は フレームレートに依存せず イベントが発生した時点で表示を更新するメソッドです。 ActionScript 3.0 の場合,この updateAfterEvent() は MouseEvent,KeyboardEvent,及び TimerEvent に対して使うことができます。 Timer クラスを使うにしても setInterval を使うにしても setTimeout を使うにしても ある程度誤差があるため正確な時間で動作をさせることはできませんが setInterval よりも setTimeout, setTimeout よりも Timer の方が管理しやすい(扱いやすい)ことは確かです。 (私は上記3者の中で, 戻り値 ID の管理が大変な setInterval が最も苦手(大嫌い)です。 setInterval を書いたフレームをループ再生させたり, setInterval の停止や開始を繰り返すと, ID がグチャグチャになります。) それと, > mcBの中の全フレームに stop();を記述し と書かれていますが Timer を使う使わないにかかわらず そういう面倒なことをする必要はりませんよ。 上のスクリプトにも書いた MovieClip.nextFrame() が「ムービークリップ内を次のフレームに進めて停止」いう意味のメソッドです。 また MovieClip.currentFrame プロパティで ムービークリップ内の現在表示中のフレーム数が取得できますから MovieClip.gotoAndStop(MovieClip.currentFrame + 1); と書いても 「ムービークリップ内を次のフレームに進めて停止」という意味になります。 またこちらの方が 「ムービークリップ内を3フレーム先に進めて停止」のようなこともできるので 汎用性は高いです。 しかしどちらにしても 行き止まりの最終フレームでは止まってしまうので, そうなるような場合に限って MovieClip.gotoAndStop(1); や MovieClip.play(); のようなことをする必要が出て来ますが。
お礼
御回答ありがとうございます。 たしかにnextFrameのほうがいいですね。 updateAfterEventというのは知りませんでした。使ってみましたがこれがあるお陰で表示速度が一定になりました。ありがとうございます。 それと追加の質問をさせてください。 いま作成しているフラッシュなんですが、ルートのフレームが3フレームあります。そのルートに内部にアニメーションファイルを持ったムービークリップを複数配置している形になります。 更にルートの1フレームにstop();を記述し、フレーム移動用のボタンを配置しそのボタンを押すとルートのフレームが1-2-3-2-3-2-3...と移り変わるように設定しています。 ボタン用のスクリプトはこういう感じになります。 if(this.currentFrame ==1) { this.gotoAndStop(2); } else if(this.currentFrame ==2) { this.gotoAndStop(3); } else { this.gotoAndStop(2); } 更にルートの2フレーム目に教えていただいた、//***↓本題(mcB 内の制御)↓*** 以下のスクリプトを記述しているので、最初にボタンを押し2フレーム目に移動した時点で addEventListenerをし、タイマーをスタートさせる形にしていました。 ここで疑問に思ったのですが、3フレームから2フレームにボタンを押して移動した場合、 更にTimerオブジェクトにaddEventListenerをしていることになるんでしょうか?だとするとボタンを押してフレーム移動をするたびにaddEventLilstnerを実行していることになりフレーム移動をすればするほど処理が重くなってきたりしそうな気がするのですがどうなのでしょうか?何か別の処理を加えるべきでしょうか? それと、このままだと、1フレーム目から2フレーム目に移動するときはいいのですが、3フレーム目から2フレーム目に移動すると、すでにタイマーがスタートしているのに更にtm.start();が実行されてしまいます。 タイマー用の関数の中にtraceを入れて確かめましたが、3Fから2Fにフレームが移動する度にタイマーが起動されていました。なので、3フレームから2フレームに移動する前に一度タイマーを停止して、フレーム移動後に改めてタイマーを起動するようにしましたが、これだとタイマーが重複して起動されることがなくなりました。 変更したボタン用スクリプトはこういう感じになりました。 if(this.currentFrame ==1) { this.gotoAndStop(2); tm.start(); } else if(this.currentFrame ==2) { this.gotoAndStop(3); } else { tm.stop(); this.gotoAndStop(2); tm.start(); } ただここで疑問なんですが、最後のelse以下をこうしてしまうと、動いていたタイマーが停止できません。 else { this.gotoAndStop(2); tm.stop(); tm.start(); } 結果、タイマーが多重起動されてしまうのですが、これはなぜでしょうか?今まで動いていたタイマーイベントと、フレーム移動後に動き出すタイマーイベントは別もの扱いになるのでしょうか? それともう一つ疑問に思ったことがあります。 タイマーにcurrentCountをつけてタイマー実行回数を調べていたんですが、2フレーム目でタイマーをスタートし、2フレームから3フレームに移動する間は実行回数は増え続けていくんですが、3フレーム目から2フレーム目に移動した時点でcurrentCountが一度0にリセットされます。これはどうしてなんでしょうか?