イージング
本日から第8章イージングとバネに入ります。
イージング、なかなか聞き慣れない言葉だと思います。
特にサーバサイドJavaばっかりやってきた人にとっては。
そういう人は、インピータンスミスマッチに匹敵する用語だと思ってください。
内容は全く関係ないですが。。
イージングっていうのは、アニメーションでよくある、
スーッと動いて、スッと止まる動きのことです。
例えるなら、車が高速をギュイーンっと走って、
家の近所になったら減速して、車庫入れするとこはさらにゆっくりになる、そんな話。
億泰のザ・ハンドで空間を切り取って、グンって動く、、それは違うか。
さて、次のサンプルでは、ボールをドラッグして、好きなところでドロップすると、
ボールが中心へ向かって、スーッと動いてスッと止まります。
イージングを実現するには、
- 目標位置を設定する
- 目標位置までの距離を求める
- 距離に小数をかけて速度を求める ※この速度でオブジェクトを動かす
目標位置に着くまで、
- 目標位置までの距離を求める
- 距離に小数をかけて速度を求める ※この速度でオブジェクトを動かす
を繰り返すことになります。
具体的にはこんなかんじ。
// 目標までの距離を求める ※targetX、targetYが目標位置 var dx:Number = targetX - ball.x; var dy:Number = targetY - ball.y; // 目標までの距離に係数を掛ける var vx:Number = dx * easing; var vy:Number = dy * easing // 移動 ball.x += vx; ball.y += vy;
あと、こんなふうに距離をeasingの係数を利用して縮めていくと、
最終的には目標には辿り着かない。
たとえば、100メートル先に目標があったとして、そこまで移動したいとする。
1フレームすつ、距離の半分を移動した場合、
1フレーム目で50メートル、2フレーム目で75メートル、3フレーム目で87.5メートル、、、
というように最終的には100メートルに限りなく近づく、という結果になって、
100メートルに達することはない。
これをゼノンのパラドックスというらしい。Flashの世界でもそうなる。
じゃー、どうするかというと、オブジェクトの移動が、目標までラスト1ピクセルを切ったら、
もうゴールと見なしてあげましょう、ってのがFlashのテクニック。
1ピクセルの移動は体感的に全く問題はない、とKeith Petersさんは言っている。あ、著者の方ね。
で、コードのラストの部分はこんなふうにする。
var distance:Number = Math.sqrt(dx * dx + dy * dy); if(distance < 1 ){ ball.x = targetX; ball.y = targetY; removeEventListener(Event.ENTER_FRAME, onEnterFrame); }else{ // 目標までの距離に係数を掛ける var vx:Number = dx * easing; var vy:Number = dy * easing; // 移動 ball.x += vx; ball.y += vy; }
要点は以上です。
コードを掲載。
package { import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; public class Easing2 extends Sprite { private var ball:Ball; private var easing:Number = 0.2; private var targetX:Number = 200; private var targetY:Number = 200; public function Easing2() { init(); } private function init():void{ ball = new Ball(); addChild(ball); addEventListener(Event.ENTER_FRAME, onEnterFrame); ball.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown_ball); } private function onEnterFrame(evt:Event):void { // 目標までの距離を求める ※targetX、targetYが目標位置 var dx:Number = targetX - ball.x; var dy:Number = targetY - ball.y; var distance:Number = Math.sqrt(dx * dx + dy * dy); if(distance < 1 ){ ball.x = targetX; ball.y = targetY; removeEventListener(Event.ENTER_FRAME, onEnterFrame); }else{ // 目標までの距離に係数を掛ける var vx:Number = dx * easing; var vy:Number = dy * easing; // 移動 ball.x += vx; ball.y += vy; } } private function onMouseDown_ball(evt:MouseEvent):void { removeEventListener(Event.ENTER_FRAME, onEnterFrame); ball.startDrag(); ball.addEventListener(MouseEvent.MOUSE_UP, onMouseUp_ball); } private function onMouseUp_ball(evt:MouseEvent):void { ball.stopDrag(); ball.removeEventListener(MouseEvent.MOUSE_UP, onMouseUp_ball); addEventListener(Event.ENTER_FRAME, onEnterFrame); } } } import flash.display.Sprite; class Ball extends Sprite { private var radious:Number; private var color:uint; public var vx:Number; public function Ball(radius:Number = 40, color:uint = 0xff0000) { this.radious = radius; this.color = color; init(); } private function init():void{ graphics.beginFill(color); graphics.drawCircle(0, 0, radious); graphics.endFill(); } }
あと、イージングの考え方を透明度(alpha)とかに適用すれば、
フェードインやフェードアウトを実現できる。
回転や、カラーの変化などいろいろ使えるね。
以上、おなか減ったから帰る。