Murayama blog.

プログラミング教育なブログ

摩擦 リアルな計算Ver


久しぶりにASの勉強も少し。。
3日サボるとだいぶ勘が鈍りますね。はい、そうですね。


本日は摩擦の勉強。
激しく地味なサンプルです。起動してすぐはボールが動いてるんですけど、摩擦によって止まります。

最初は動いてたんですよ、このボール。よかったらリロードしてみてください。


そんでコード。
地味に摩擦の計算をする部分のコードがかっこいい。誰も見ないだろうけど。

package
{
  import flash.display.Sprite;
  import flash.display.StageAlign;
  import flash.display.StageScaleMode;
  import flash.events.Event;
  
  public class Friction1 extends Sprite
  {
    private var ball:Ball;
    private var vx:Number = 0;
    private var vy:Number = 0;
    private var fliction:Number = 0.1;
    
    
    public function Friction1()
    {
      init();
    }
    
    private function init():void{
      
      stage.scaleMode = StageScaleMode.NO_SCALE;
      stage.align = StageAlign.TOP_LEFT;
      
      ball = new Ball;
      ball.x = 200;
      ball.y = 200;
      vx = Math.random() * 10 - 5;
      vy = Math.random() * 10 - 5;
      
      addChild(ball);
      addEventListener(Event.ENTER_FRAME, onEnterFrame);
    }
 
    private function onEnterFrame(evt:Event):void
    {
      // 縦横のスピードから1方向のなスピードと角度を求める
      var speed:Number = Math.sqrt(vx * vx + vy * vy);
      var radians:Number = Math.atan2(vy, vx);
      
      // 摩擦によるスピードの減速
      if(speed > fliction){
        speed -= fliction;
      }else{
        speed = 0;
      }
      
      // 縦横のスピードに戻す
      vx = Math.cos(radians) * speed;
      vy = Math.sin(radians) * speed;
      ball.x += vx;
      ball.y += vy;
    }
  }
}
 
import flash.display.Sprite;
 
class Ball extends Sprite
{
  public var radious:Number;
  public var color:uint;
  public var vx:Number;
  public var vy: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();
  }
}


ボールには縦横のスピードがあって、それがvx、vyという変数に格納されています。
で、摩擦は変数flictionに0.1って値が入ってます、と。
仮にvxに5、vyに3みたいな数値が格納されているとして、
単純に摩擦をデクリメントすると、
vxが4.9、vyが2.9になってしまいます。
一見、問題なさそうですが、これだと先にvy縦のスピードが0になってしまって横に滑る変な動きになっちゃいます。
#この例だと、摩擦による0.1のデクリメントをあと29回繰り返せば、vxが2.0、vyが0になってしまいます。


なんで摩擦を縦横のスピードにちょうどいいかんじに割り当てるには、
ピタゴラスの定理で縦横のスピードを1方向のスピードに変換します。
あわせて、角度も取得します。

      // 縦横のスピードから1方向のなスピードと角度を求める
      var speed:Number = Math.sqrt(vx * vx + vy * vy);
      var radians:Number = Math.atan2(vy, vx);
      
      // 摩擦によるスピードの減速
      if(speed > fliction){
        speed -= fliction;
      }else{
        speed = 0;
      }

純粋な1方向のスピードに摩擦をかけたら、
もとの縦横のスピードに戻します。
このとき、あらかじめ取得しておいた角度を使用します。

      // 縦横のスピードに戻す
      vx = Math.cos(radians) * speed;
      vy = Math.sin(radians) * speed;
      ball.x += vx;
      ball.y += vy;


こんなかんじにすれば、ちょうどよい摩擦をかけることができます。