[AS3] 内積による位置判定+補正

2009/08/3

こんにちは。きんくまです。
なんだかんだで8月ですね。蝉もたくさん鳴いてます。

今回は内積による表裏の位置判定をしたあとに、もし裏だったら表に位置補正するというものです。
言葉だとよくわからないと思うので、作りました。

 
■遊び方
・各玉をドラッグできる
・補正ありをチェックすると表の位置だけになるように補正開始

3点の玉を互いにばねとして干渉させあった場合に、赤い玉は表側、裏側の2点で収束する位置ができます。
これに表裏の判定をつけてあげることで、表側にだけ居続けることができます。位置によっては補正が弱い場合もあるけど…。

内積の位置判定は以下のサイトからそのままもってきています。ありがとうございます。
>> 点が線を境にどちら側にあるか判定を取る(HAKUHIN’s home page)

それで、これをどう利用するかといいますと、形状記憶みたいなことができます。クラゲ時計では、ほっておくともとの形状に戻る力が働きます。
>> クラゲ時計を見る

以下ソースです。

Main

package
{
  import flash.display.Graphics;
  import flash.display.MovieClip;
  import flash.display.Sprite;
  import flash.events.Event;
  import flash.events.MouseEvent;
  import flash.geom.Rectangle;

  public class Main extends Sprite
  {
    public var frontBack:MovieClip;
    public var correctSwitch:MovieClip;
    public var currentDragMC:MovieClip;
    public var canvas:Sprite;
    public var isCorrectSpring:Boolean = true;
    public var ball:Ball;
    public var basePoint1:Ball;
    public var basePoint2:Ball;
    public var balls:Array;
    public var arrow:MovieClip;
    public var startBtn:MovieClip;

    public function Main()
    {
      init();
    }

    private function init():void
    {
      balls = [basePoint1, basePoint2, ball];
      canvas = new Sprite();
      addChildAt(canvas, 0);
      registerEvent();
      initLook();

      startBtn.addEventListener(MouseEvent.CLICK, startBtnClickHD);

    }

    private function startBtnClickHD(e:MouseEvent):void
    {
      startBtn.removeEventListener(MouseEvent.CLICK, startBtnClickHD);
      startBtn.visible = false;
      stage.addEventListener(Event.ENTER_FRAME, enterframeHD);
    }

    private function enterframeHD(e:Event):void
    {
      update();
      draw();
    }

    private function draw():void
    {
      var g:Graphics = canvas.graphics;
      g.clear();
      g.lineStyle(1, 0x999999, 1);
      g.moveTo(basePoint1.x, basePoint1.y);
      g.lineTo(basePoint2.x, basePoint2.y);
    }

    private function update():void
    {
      var i:int, j:int;
      var myball:Ball;
      var target:Ball;
      for (i = 0; i < 3; i++) {
        if (i == 0 || i == 1) {
          //continue;
        }
        myball = balls[i];
        myball.initDvector();
        for (j = 0; j < 3; j++) {
          if (i == j) {
            continue;
          }
          target = balls[j];
          myball.updateDVector(target);
          myball.updateDVector(target);
        }
        if (i < 2) {
          myball.updateVector();
        }
      }
      correctVector();
      ball.updateVector();

      updateArrow();
    }

    private function updateArrow():void
    {
      var dx:Number = basePoint2.x - basePoint1.x;
      var dy:Number = basePoint2.y - basePoint1.y;
      var rad:Number = Math.atan2(dy, dx) + Math.PI;
      arrow.rotation = 180 * rad / Math.PI;
      arrow.x = dx / 2 + basePoint1.x;
      arrow.y = dy / 2 + basePoint1.y;
    }

    //裏と表によって元の位置に戻すように補正
    private function correctVector():void
    {
      var dx1:Number = basePoint2.x - basePoint1.x;
      var dy1:Number = basePoint2.y - basePoint1.y;
      var tmp:Number = dx1;
      dx1 = -dy1;
      dy1 = tmp;
      var dx2:Number = ball.x - basePoint1.x;
      var dy2:Number = ball.y - basePoint1.y;
      //内積
      var productSpace:Number = dx1 * dx2 + dy1 * dy2;
      //裏側だったら
      if (productSpace < 0) {
        frontBack.gotoAndStop("back");
        if (!ball.isDragging && isCorrectSpring) {
          var dx3:Number = (basePoint2.x + basePoint1.x) / 2 + dx1;
          var dy3:Number = (basePoint2.y + basePoint1.y) / 2 + dy1;
          ball.dvx += dx3 - ball.x;
          ball.dvy += dy3 - ball.y;
        }
      }else {
        frontBack.gotoAndStop("front");
      }
    }

    private function initLook():void
    {
      frontBack.gotoAndStop("front");
      correctSwitch.gotoAndStop("on");
    }

    private function registerEvent():void
    {
      correctSwitch.addEventListener(MouseEvent.CLICK, correctSwitchClickHD);
      correctSwitch.buttonMode = true;
    }

    private function correctSwitchClickHD(e:MouseEvent):void
    {
      isCorrectSpring = !isCorrectSpring;
      if (isCorrectSpring) {
        correctSwitch.gotoAndStop("on");
      }else {
        correctSwitch.gotoAndStop("off");
      }
    }


  }

}

Ball

package
{
  import flash.display.MovieClip;
  import flash.events.MouseEvent;
  import flash.geom.Rectangle;

  public class Ball extends MovieClip
  {
    public var dvx:Number = 0;
    public var dvy:Number = 0;
    public var vx:Number = 0;
    public var vy:Number = 0;
    public var spring:Number = 0.07;
    public var friction:Number = 0.8;
    public var isDragging:Boolean = false;
    public var springLen:Number = 100;

    public function Ball()
    {
      this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHD);
      this.buttonMode = true;
    }

    private function mouseDownHD(e:MouseEvent):void
    {
      isDragging = true;
      this.startDrag(false, new Rectangle(0,0,stage.stageWidth, stage.stageHeight));
      stage.addEventListener(MouseEvent.MOUSE_UP, stageMouseUpHD);
    }

    private function stageMouseUpHD(e:MouseEvent):void
    {
      isDragging = false;
      this.stopDrag();
      stage.removeEventListener(MouseEvent.MOUSE_UP, stageMouseUpHD);
    }

    public function initDvector():void
    {
      dvx = 0;
      dvy = 0;
    }

    public function updateDVector(target:MovieClip):void
    {
      if (isDragging) {
        return;
      }
      var rad:Number = Math.atan2(this.y - target.y, this.x - target.x);
      var targetX:Number = target.x + Math.cos(rad) * springLen;
      var targetY:Number = target.y + Math.sin(rad) * springLen;
      dvx += targetX - this.x;
      dvy += targetY - this.y;
    }

    public function updateVector():void
    {
      vx += dvx * spring;
      vy += dvy * spring;
      vx *= friction;
      vy *= friction;
      this.x += vx;
      this.y += vy;
      if (x < 0) {
        x = 0;
      }else if (x > stage.stageWidth) {
        x = stage.stageWidth;
      }
      if (y < 0) {
        y = 0;
      }else if (y > stage.stageHeight) {
        y = stage.stageHeight;
      }
    }
  }

}
LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

LINEスタンプ作りました!
毎日使える。とぼけたウサギ。LINEスタンプ販売中! 毎日使える。とぼけたウサギ

ページトップへ戻る