スポンサーサイト

-------- | --:--

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[ActionScript 3.0]外積

2007-08-07 | 21:05

二つのベクトル(Va,Vb)の外積Va*Vbを求めた場合、外積の値は
|Va|*|Vb|*sin(Θ)
なので、Vaを基準にしたVbの角度が0~180なら外積はプラスになり、180~360なら外積はマイナスになる。
(なぜなら角度が0~180の時はsinの値は正であり、180~360の時はsinの値は負なので)

これを利用して、自分の位置と進行方向と対象物の位置がわかっている場合は、外積の正負を求めることによって対象物が自分の進行方向を基準にして左右どちら側にあるかが判定できる。
下のFlashでは、赤い矢印の進行方向ベクトルと、赤い矢印から見た青い矢印の方向ベクトルとの外積を求めて表示している。 赤い矢印の進行方向を基準にして青い矢印が右側にあるときは外積はプラスになり、左側にあるときは外積はマイナスになるのがわかる。

(一般的な数学のxy座標ではy軸は上のほうがプラスだが、このプログラムでは画面の左上が原点でy軸は下側がプラスになるので注意が必要)

package {
    import flash.display.*;
    import flash.events.*;
    import flash.text.*;

    [SWF(width="400", height="400", backgroundColor="#ffffff")]
        public class CrossProduct extends Sprite {
            private var _tf:TextField;
            private static var COLLISION_THRESHOLD:Number = 20;
            private var redArrow:Arrow = new Arrow(0xff0000);
            private var blueArrow:Arrow = new Arrow(0x0000ff);
            private var arrows:Array = new Array();

            public function CrossProduct() {
                _tf = new TextField();
                _tf.autoSize=TextFieldAutoSize.LEFT;
                addChild(_tf);

                redArrow.x = Math.random()*400;
                redArrow.y = Math.random()*400;
                blueArrow.x = Math.random()*400;
                blueArrow.y = Math.random()*400;
                redArrow.vx = Math.random()*1;
                redArrow.vy = Math.random()*1;
                blueArrow.vx = Math.random()*1;
                blueArrow.vy = Math.random()*1;
                arrows.push(redArrow);
                arrows.push(blueArrow);
                addChild(redArrow);
                addChild(blueArrow);
                addEventListener(Event.ENTER_FRAME, onEnterFrame);
                drawLine();
            }

            public function onEnterFrame(event:Event):void {
                for each(var arrow:Arrow in arrows){
                    arrow.x += arrow.vx;
                    arrow.y += arrow.vy;

                    if(arrow.x < COLLISION_THRESHOLD && arrow.vx < 0){
                        arrow.vx *= (-1);
                    }
                    if(arrow.x > 400 - COLLISION_THRESHOLD && arrow.vx > 0){
                        arrow.vx *= (-1);
                    }
                    if(arrow.y < COLLISION_THRESHOLD && arrow.vy < 0){
                        arrow.vy *= (-1);
                    }
                    if(arrow.y > 400 - COLLISION_THRESHOLD && arrow.vy > 0){
                        arrow.vy *= (-1);
                    }

                    var degree:Number = Math.atan(arrow.vy/arrow.vx)*180/Math.PI;
                    if(arrow.vx < 0)
                        degree += 180;
                    arrow.rotation = degree;
                }

                // 赤い矢印から見た青い矢印の方向ベクトルの成分
                var dx:Number = blueArrow.x - redArrow.x;
                var dy:Number = blueArrow.y - redArrow.y;
                // 赤い矢印の速度ベクトルと,赤い矢印から見た青い矢印の方向ベクトルの外積
                var crossProduct:Number = redArrow.vx*dy - redArrow.vy*dx;
                _tf.text = "cross product : " + crossProduct;

                drawLine();
            }

            private function drawLine():void{
                var a:Number = redArrow.vy / redArrow.vx;
                var b:Number = redArrow.y - a * redArrow.x;
                graphics.clear();
                graphics.lineStyle(1, 0, 0.3);
                graphics.moveTo(redArrow.x, redArrow.y);
                graphics.lineTo(b*(-1)/a, 0);
                graphics.moveTo(redArrow.x, redArrow.y);
                graphics.lineTo((400 - b)/a, 400);
            }
        } 
}
package {
    import flash.display.Sprite;

    public class Arrow extends Sprite {

        private var _vx:Number;
        private var _vy:Number;
        private var _id:int;

        public function Arrow(color:Number = 0xff0000) {
            graphics.lineStyle(1, 0, 1);
            graphics.beginFill(color);
            graphics.moveTo(-10, -5);
            graphics.lineTo(0, -5);
            graphics.lineTo(0, -10);
            graphics.lineTo(10, 0);
            graphics.lineTo(0, 10);
            graphics.lineTo(0, 5);
            graphics.lineTo(-10, 5);
            graphics.lineTo(-10, -5);
            graphics.endFill();
        }

        public function get vx():Number{
            return _vx;
        }

        public function set vx(v:Number):void{
            _vx = v;
        }

        public function get vy():Number{
            return _vy;
        }

        public function set vy(v:Number):void{
            _vy = v;
        }

        public function get id():int{
            return _id;
        }

        public function set id(v:int):void{
            _id = v;
        }

        public function turn(rad:Number):void{
            var x:Number = _vx;
            var y:Number = _vy;
            _vx = Math.cos(rad)*x - Math.sin(rad)*y;
            _vy = Math.sin(rad)*x + Math.cos(rad)*y;
        }
    }
} 
スポンサーサイト

Comment

Post a comment

Secret

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。