DisplayObjectを絡めるときのフラッシュ数の数学

バグに対処するように求められたら:ネストされた任意の数の.swfでframeRateを変更すると、セルフスタイルの「トゥイナー」が奇妙な振る舞いを始めました。 通常のアクティビティの代わりに、トゥイナーは値をスキップし、値を保持することができます。また、時々任意の瞬間に変数を最終値に設定し、作業の完了を報告できます。 申立人は、この問題をマルチレベルのネストと、ネイティブfpsと親fpsの不一致に関連付けました。



私はゼロからトゥイーンコードを記述しようとしましたが、レベルが1のみでfpsが一定であったにもかかわらず、私のバージョンも奇妙に動作することがわかりました。 問題を解決する過程で、私はいくつかの素晴らしいフラッシュトリックを学びました。



どんな困難があるのでしょうか? 独自のトゥイナーのコンストラクターで、オブジェクトへのリンク、変更する必要のあるパラメーター、最終値、および時間/フレームを渡します。このパラメーターは、この形式でスムーズに最終形式を取る必要があります。 簡単にするために、フレームごとの値が変化する場合を取り上げます。



public class SomeTweener { private var _obj:Object; private var _paramName:String; private var _endValue:Number; private var _frames:Number; public function SomeTweener(obj:Object, paramName:String, endValue:Number, frames:Number) { _obj = obj; _paramName = paramName; _endValue = endValue; _frames = frames; } }
      
      





はい、値を更新する時期を判断する最も簡単な方法は、コンストラクターに渡されたDisplayObjectからEvent.ENTER_FRAMEイベントをサブスクライブすることです 。 ただし、簡単な方法を探しているわけではなく、トゥイーンを汎用化しています。 つまり、 DisplayObjectだけでなくパラメータを変更するものです。 したがって、 文書化されていないas3のあまり知られてない機能を使用する必要があります。



DisplayListに追加さえされていないDisplayObjectは、フレームごとに入力イベントを正しく受け取ります。




コンストラクターを変更します。



 import flash.display.Shape; import flash.events.Event; import flash.events.IEventDispatcher; public class SomeTweener { private var _obj:Object; private var _paramName:String; private var _endValue:Number; private var _frames:Number; private var eventDispatcher:IEventDispatcher; public function SomeTweener(obj:Object, paramName:String, endValue:Number, frames:Number) { _obj = obj; _paramName = paramName; _endValue = endValue; _frames = frames; eventDispatcher = new Shape(); eventDispatcher.addEventListener(Event.ENTER_FRAME, tween); } private function tween(e:Event):void { } }
      
      





自分で確認できます。 tweenメソッドはfpsで定期的に呼び出されます。



続けましょう。 繰り返しますが、最も簡単な方法- トゥイーン呼び出しごとに、送信された値を同じ値に変更します(easeNone型のツイン-つまり、均一)。 これを行うには、最終値と開始値の違いとトゥイーンの継続時間に基づいてコンストラクターで増分増分を計算し、クラスフィールドに増分を書き込む方が適切です。 トゥイーンメソッド自体では、既に取得されているフレームの数を確認し、設定値に達したら、ツイニングを中断します。



 import flash.display.Shape; import flash.events.Event; import flash.events.IEventDispatcher; public class SomeTweener { private var _obj:Object; private var _paramName:String; private var _endValue:Number; private var _frames:Number; private var eventDispatcher:IEventDispatcher; private var increment:Number; public function SomeTweener(obj:Object, paramName:String, endValue:Number, frames:Number) { _obj = obj; _paramName = paramName; _endValue = endValue; _frames = frames; increment = (endValue - Number(obj[paramName])/frames; eventDispatcher = new Shape(); eventDispatcher.addEventListener(Event.ENTER_FRAME, tween); } private function tween(e:Event):void { if (_frames == 0) { e.currentTarget.removeEventListener(e.type, tween); return; } obj[paramName] += increment; _frames--; } }
      
      







ツイニングの残りの「チック」のカウンターとしてフレームを使用しても構いません。トゥイーン時間として秒を使用しないことに同意しました。 さらに、 framesパラメーターを除き、コンストラクターのどこでも使用されず、値に渡された値を独自の目的で変更することを誰も(私たちも)責めません。



どうやら-すべてのトゥイーンの準備ができました。 そして、それは動作し、ほとんどの場合-正しくも動作します。 しかし、彼がどのような場合でも正常な結果をもたらさない場合が1つあります。 私は小さな例を挙げます:



 import flash.display.Sprite; import flash.events.Event; public class SomeClass extends Sprite { private var sprite:Sprite; public function SomeClass() { sprite = new Sprite(); sprite.x = 1; sprite.addEventListener(Event.ENTER_FRAME, traceSome); var tween:SomeTweener = new SomeTweener(sprite, 'x', -1, 40); } private function traceSome(e:Event):void { trace(sprite.x); } }
      
      







このコードを呼び出した結果、トレースから何が得られますか? 論理的には、0.05の増分で減少する40の数字の列。 実際には、 DisplayObjectには少なくとも1つのドキュメント化されていない機能があります。その座標(および場合によっては他のプロパティ)は常に0.05の倍数です。 それらに複数の値を割り当てようとすると失敗します。次に描画されるときに、最も近い倍数に丸められてゼロになります。 この特定の例では、この効果は私たちを脅かすべきではありません(実際、それはすべての栄光で現れます)が、例えば、絡みが現れるはずのフレームの値を80に増やすと、0.025に等しい増分が得られ、軌跡が「フリーズ」します「ゼロでは、-1に達することはありません。



別の機能があります。 FlashPlayerランタイムでは、 Number型は64ビットの浮動小数点数です。 このため、オーバーレイが頻繁に発生します。 例で説明する最も簡単な方法:



 trace(String(-.35 - .05)) // 0.39(9)97
      
      







これは、数値型( DisplayObject座標フィールドを含む)のすべての値でフラッシュがどのように動作するかです。何もする必要はありません。 SomeClassクラスのtraceSomeメソッドの例は、40フレームのトゥイーン時にも失敗するのは当然です。 練習により、 sprite.x-0.35の値から各フレームに切り上げられた値まで正確に移動できないことが示されています。 サイクルは次のとおりです。

  1. オブジェクトフィールドの値を取得します(-0.35)
  2. 増分の値で増加します(-0.35 +(-0.05)= -0.39(9)97)
  3. オブジェクトフィールドに書き込みます(-0.39(9)97)
  4. (非表示の必須項目)DisplayObjectインスタンスの座標フィールドの値は丸められます(-0.35)
  5. 次のフレームに入り、オブジェクトフィールドの値(-0.35)を取得します
  6. 後藤2


隠された4番目の点を取り除くことは不可能です。 ただし、 Number数学の共生とDisplayObject座標値の制限に起因するエラーにより、正確に3行追加されます。 これを行うには、サイクルの最初と5番目の段落を変更し、バリューストアを永続的に「台無しにする」代わりに、独自に開始する必要があります。



 import flash.display.Shape; import flash.events.Event; import flash.events.IEventDispatcher; public class SomeTweener { private var _obj:Object; private var _paramName:String; private var _endValue:Number; private var _frames:Number; private var eventDispatcher:IEventDispatcher; private var increment:Number; private var currentValue:Number; public function SomeTweener(obj:Object, paramName:String, endValue:Number, frames:Number) { _obj = obj; _paramName = paramName; _endValue = endValue; _frames = frames; currentValue = Number(obj[paramName]); increment = (endValue - Number(obj[paramName])/frames; eventDispatcher = new Shape(); eventDispatcher.addEventListener(Event.ENTER_FRAME, tween); } private function tween(e:Event):void { if (_frames == 0) { e.currentTarget.removeEventListener(e.type, tween); return; } currentValue += increment; obj[paramName] = currentValue; _frames--; } }
      
      







MVCはそれと何の関係があるのでしょうか? :-)



PS:はい、既存のトゥイーンコードは改善することができますし、改善すべきです。 遅延開始、メッセージングを追加します。 イージングおよびその他のマルチフィールドツインを追加できます。 ただし、これはこのタスクには適用されないため、宿題として残します。




All Articles