「FITC Tokyo 2009」詳細レポート

#2Keith Peters氏「Making Tings Move」物理アニメーションの基礎

11月28日、ベルサール汐留にて、FITC Tokyo 2009が開催された。以下は、Keith Peters氏のセッションのレポート。

Keith Peters氏「Making Tings Move」

Keith Peters(キースピータース)氏は、日本国内でも高い評判を得ている "ActionScript 3.0 アニメーション" の作者として有名であり、また彼が運営するbit-101.comは、世界中で愛され翻訳されているFlash開発のチュートリアル,ラボサイトである 。日本でも、彼のウェブログを覗いたことがあるという開発者も多いことだろう。

このセッションでは、アニメーションをActionScriptに落とし込む基本的なテクニックを解説した。

写真1 ActionScriptでアニメーションさせる方法を解説した著書が有名な、Keith Peters氏
画像

氏によれば、プログラミングでアニメーションさせる場合には、3つのプロセスを経て、それがサイクルしているいう。ひとつめは、"ルール"。オブジェクトをどのようなルールで、どこに動かすのか、またはどのような状態変化をさせるのかを決定するプロセス。ふたつめは"動かす"。このプロセスでオブジェクトを実際に動かしたり、変化を起こす。そして、"リフレッシュ"。前のプロセスで動かされたオブジェクトの確認や、初期化を行う。これを何度も何度も繰り返すことで、複雑なアニメーションをつくっていくことができるのだという。また、この繰返しに使用する処理はプログラミング言語によって異なり、ActionScript3.0では、"EnterFrame"と"Timer"だと紹介。実際にボールを平行移動するシンプルなサンプルを作成しながら、デモを披露した。氏は「ActionScriptで行うアニメーションのほぼ全てで、この処理が必要になってくる。あとはどのような"ルール"を当てはめるか、ということだ」との述べ、アニメーションを制御する"ルール"を紹介。ルールごとにわかりやすくデモを行いながら解説した。

写真2 スクリプトアニメーションでは3つのプロセスがサイクルしていると説明
画像
まずひとつめに重要な要素になってくるのが、Velocity(速度)である。Velocityは一見、Speed(速さ)と混同しがちだが、"速さ"に加えて"方向"を表すのが重要だという。また、これらのVelocityをXY座標にあてはめていくのがFlashアニメーションの基本であるとした。
写真3 "速さ"に加えて"方向"の概念を持つ、速度の利用が重要
画像

また、角速度からXY速度への変換の例では、度をラジアンに変換するコードから、Math.cosをXに,Math.sinをYに当てはめるといってた、三角関数を用いた基礎的なコードを紹介。

写真4 三角関数を用いてxy方向の速度を算出
画像

スピードに角度を自在に操ることで、柔軟性を得ることが出来るとした。

次に、スピードを変えたい場合のルールとして、Acceleration(加速)が紹介された。オブジェクトの移動スピードを上げたい場合にはもちろんのこと「スピードを落とす場合にもAccelerationと読んでいる」と述べた。Accelerationのシンプルなコードは以下のようになる。この例では、ボールがだんだん加速しながら移動していく。

//ballが加速していく
vx = 0;
vy = 0;
ax = .2;
ay = .3;
vx += ax;
vy += ay;
ball.x += vx;
ball.y += vy;

基本的な考え方として"加速を速度に追加させ、速度を位置に追加させる"と述べるキース氏。常に、Velocityに対してルールを加えていくという。また、加速の延長として、Gravity(重力)を紹介。Gravityはy軸方向のみの加速として定義される。これは、地球が常に同じ方向に物体をひっぱいてる事と同じだ。氏はコード自体は加速とほぼ変わらないとし、オブジェクトが落ちていくデモを見せた。Velocityの初期値をマイナス値にすることで、最初は上昇するものの、重力に引っ張られて落ちていくといった表現や、Gravityを極端に低くすると言ったパラメータのちょっとした変動で表現の幅が広がり、リアルになることを示した。氏は、⁠とはいえ、これは物理の教科書に書いてあることとは違う。つまり、完全な精度はない。だが、ゲームやアプリケーションに使うには十分だ。短時間で、短いコードで表現することが出来る。精度をだそうとすれば、その分負荷が掛かり、コードも複雑になる。」として、必ずしも精度の高いアルゴリズムを利用する必要がないことをアドバイス。

//重力に引っ張られてballが落ちていく
var vx = 2;
var vy:Number = -10;
var gravity:Number = .95;

addEventListener(Event.ENTER_FRAME,function(e){
  vy += gravity;
  ball.x += vx;
  ball.y += vy;
})

キース氏は、⁠ここまでのサンプルでは、ステージの端まできたら消えてしまっていた。これではつまらない。"環境に対してオブジェクトがどう反応するか"について、考えてみよう」として、Bouncing(弾性)を解説。このデモでは、ステージの端にオブジェクトが当たった時に跳ね返るといった例を紹介。⁠ボールがステージの端当たったかどうかを判定するには、ボールの位置と半径が、ステージの端とどういう関係にあるかを考える」とし、コードを提示。ボールが端を超えた場合、ボールの位置をステージ端からボールの半径を差し引いた分まで押し戻し、Velocityに-1を乗算すれば方向を反転することができ、弾性を再現できる。また、Friction(抵抗・摩擦)の解説では、"常に速度に対して逆方向に働く力"として、⁠摩擦は速度を超える力ではならない」と述べ、よく使われるシンプルな抵抗処理として、Velocityに対して0.9あたりを乗算する方法を紹介した。

写真5 シンプルに抵抗を処理してもさほど問題ないと説明
画像
//弾性と摩擦
var vx:Number = 3;
var vy:Number = -5;
var gravity:Number = .6;
var bounce:Number = -.7;
var bottom:Number = 400;
var friction:Number = .95;

addEventListener(Event.ENTER_FRAME,function(e){
  vy += gravity;
  vy *= friction;
  vx *= friction;
  ball.x += vx;
  ball.y += vy;
  if(ball.y+ball.height/2 > bottom){
    ball.y = bottom - ball.height/2;
    vy *= bounce;
  }
})

氏は、⁠ここまではルールを当てはめていくだけのシンプルなものだ」として、次にインタラクションを加えた表現として、マウスを使ってボールを投げるデモを解説。addEventListenerを使用して、ドラッグアンドドロップを実装。ドラッグ中かどうかを判断するプロパティを定義した。ボールが実際に落ちるEnterFrame内では、ドラッグ中でなければ今まで同様落下の処理を、ドラッグ中であれば、ボールの座標をセーブし、Velocityに対してボールの現在座標と、前回セーブした座標の差を割り当てることで、ボールを投げるといった表現ができるようになった。

//ボールのドラッグとスロー
var vx:Number = 3;
var vy:Number = -5;
var gravity:Number = .6;
var bounce:Number = -.7;
var friction:Number = .99;

var left:Number = 0;
var top:Number = 0;
var right:Number = 550;
var bottom:Number = 400;

var dragging:Boolean;
var oldx:Number = 0;
var oldy:Number = 0;

addEventListener(Event.ENTER_FRAME,function(e){
  if(!dragging){
    vy += gravity;
    vy *= friction;
    vx *= friction;
    ball.x += vx;
    ball.y += vy;
    if(ball.x + ball.width/2 > right){
      ball.x = right - ball.width/2;
      vx *= bounce;
    }else if(ball.x - ball.width/2 < left){
      ball.x = left + ball.width/2;
      vx *= bounce;
    }else if(ball.y - ball.height/2 < top){
      ball.y = top + ball.height/2;
      vy *= bounce;
    }else if(ball.y+ball.height/2 > bottom){
      ball.y = bottom - ball.height/2;
      vy *= bounce;
    }
  }else{
    vx = ball.x - oldx;
    vy = ball.y - oldy;
    oldx = ball.x;
    oldy = ball.y;
  }
});

ball.addEventListener(MouseEvent.MOUSE_DOWN,onDrag)

function onDrag(e):void{
  dragging = true;
  ball.startDrag();
  stage.addEventListener(MouseEvent.MOUSE_UP,onDrop)
}

function onDrop(e):void{
  stage.removeEventListener(MouseEvent.MOUSE_UP,onDrop);
  dragging = false;
  ball.stopDrag();
}

この他に、イージングと、それを応用したバネについての考え方について解説した。イージングでは複雑な方程式が必要になるとし、ライブラリを使用するのがよいという。その一部として、Tween , Tweener , gTween , TweenLite ,TweenMax を紹介した。バネの表現では、"力は伸びに比例する" のフックの法則を紹介。"バネ定数*距離"の方程式を利用した、デモを行った。

//バネ
var vx:Number = 3;
var vy:Number = -5;
var k:Number = .2;

var gravity:Number = 6;
var friction:Number = .9;

addEventListener(Event.ENTER_FRAME,function(e){
  
  var dx:Number = mouseX - ball.x;
  var dy:Number = mouseY - ball.y;
  var ax:Number = k * dx; 
  var ay:Number = k * dy;
  
  vx += ax;
  vy += ay;
  vy += gravity
  
  vx *= friction;
  vy *= friction;
  
  ball.x += vx;
  ball.y += vy;
  
});
写真6 バネの仕組みをデモする、Keith Peters氏
画像

このセッションでは、基礎的ながら、わかりやすく実践的なアニメーションについて学ぶことが出来た。こうした現実世界に存在する様々な法則をルールとして当てはめることで、よりリアルな表現が可能になる。現在キース氏の著書Adovanced ActionScript3.0 Animationの邦訳が進行中とのことで、今から楽しみだ。

おすすめ記事

記事・ニュース一覧