スポンサーサイト

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

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

[ActionScript 3.0] 線分の交差判定を利用して多角形同士の交差判定を行う

2007-12-15 | 18:33

前回の線分の交差判定を使って多角形同士が交差するか判定する。
(多角形を構成する線分同士の交差を判定しているので、多角形同士が完全に離れている場合と多角形が他の多角形に完全に含まれる場合の区別はつかない。)

package
{
        import flash.display.*;
        import flash.geom.*;
        import flash.events.Event;
        
        [SWF(width="500", height="500", backgroundColor="#ffffff")]
        public class PentagonCross extends Sprite
        {
                public var vertexes:Array;
                public var checkObjects:Array;
                
                private var WIDTH:int = 500;
                private var HEIGHT:int = 500;
                
                private var V:int = 8;
                
                public function PentagonCross()
                {
                        this.vertexes = [];
                        this.vertexes.push( new Ball(0xff, 2, 200, 50));
                        this.vertexes.push( new Ball(0xff, 2, 300, 50));
                        this.vertexes.push( new Ball(0xff, 2, 150, 90));
                        this.vertexes.push( new Ball(0xff, 2, 200, 150));
                        this.vertexes.push( new Ball(0xff, 2, 360, 350));
                        this.vertexes.push( new Ball(0xff, 2, 290, 410));
                        this.vertexes.push( new Ball(0xff, 2, 250, 300));
                        this.vertexes.push( new Ball(0xff, 2, 100, 350));
                        this.vertexes.push( new Ball(0xff, 2, 100, 200));
                        this.vertexes.push( new Ball(0xff, 2, 100,100));
                        
                        for each (var v:Ball in vertexes){
                                addChild(v);
                        }
                        
                        var vertexes2:Array = [];
                        vertexes2.push( new Ball(0xff00, 2, 100, 150));
                        vertexes2.push( new Ball(0xff00, 2, 200, 150));
                        vertexes2.push( new Ball(0xff00, 2, 150, 190));
                        vertexes2.push( new Ball(0xff00, 2, 100, 180));
                        for each (v in vertexes2){
                                v.vx = V;
                                addChild(v);
                        }
                        
                        var vertexes3:Array = [];
                        vertexes3.push( new Ball(0xff00, 2, 200, 250));
                        vertexes3.push( new Ball(0xff00, 2, 300, 350));
                        vertexes3.push( new Ball(0xff00, 2, 250, 390));
                        vertexes3.push( new Ball(0xff00, 2, 200, 350));
                        for each (v in vertexes3){
                                v.vx = V;
                                addChild(v);
                        }
                        
                        checkObjects = [];
                        checkObjects.push(vertexes2);
                        checkObjects.push(vertexes3);
                        
                        this.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
                }
                
                private function enterFrameHandler(event:Event):void
                {
                        // vertexes内の点は (250,250)を中心に回転
                        var rad:Number = 0.02;
                        var px:Number = 250;
                        var py:Number = 250;
                        for each (var v:Ball in vertexes){
                                var x:Number = v.x -px;
                                var y:Number = v.y -px;
                                v.x = x*Math.cos(rad) - y*Math.sin(rad) +px;
                                v.y = x*Math.sin(rad) + y*Math.cos(rad) +py;
                        }
                        
                        for each (var a:Array in checkObjects){
                                for each (var v2:Ball in a){
                                        if (a[0].x > WIDTH)
                                        v2.vx = -V;
                                        if (a[0].x < 0)
                                        v2.vx = V;
                                        v2.x += v2.vx;
                                }
                        }
                        
                        var j:int;
                        
                        graphics.clear();
                        graphics.lineStyle(3, 0x0000ff, 0.5);
                        graphics.moveTo(vertexes[0].x, vertexes[0].y);
                        for(j= 0; j < vertexes.length ; j++){
                                graphics.lineTo(vertexes[j].x, vertexes[j].y);
                        }
                        graphics.lineTo(vertexes[0].x, vertexes[0].y);
                        
                        graphics.lineStyle(3, 0xff00, 0.5);
                        for each(a in checkObjects){
                                graphics.moveTo(a[0].x, a[0].y);
                                for(j= 0; j < a.length ; j++){
                                        graphics.lineTo(a[j].x, a[j].y);
                                }
                                graphics.lineTo(a[0].x, a[0].y);
                        }
                        
                        // 交差判定
                        var lines:Array = balls2Lines(vertexes);
                        
                        for each(a in checkObjects){
                                var lines2:Array = balls2Lines(a);
                                
                                var cross:Boolean = false;
                                
                                graphics.lineStyle(3,0x0);
                                for(var k:int = 0 ; k < lines.length ; k++){
                                        for(var l:int = 0 ; l < lines2.length ; l++){
                                                graphics.moveTo(lines[k].p1.x ,lines[k].p1.y);
                                                graphics.moveTo(lines[k].p2.x ,lines[k].p2.y);
                                                if(Line.isCross(lines[k], lines2[l])){
                                                        cross = true;
                                                        break;
                                                }
                                        }
                                }
                                
                                if(cross){
                                        graphics.beginFill(0xff0000, 0.8);
                                        graphics.moveTo(a[0].x, a[0].y);
                                        for(j= 1; j < a.length ; j++){
                                                graphics.lineTo(a[j].x, a[j].y);
                                        }
                                        graphics.lineTo(a[0].x, a[0].y);
                                        graphics.endFill();
                                }
                        }
                }
                
                private function balls2Lines(a:Array):Array{
                        var lines:Array = [];
                        for(var j:int = 0 ; j < a.length-1 ; j++){
                                var b1:Ball = a[j];
                                var b2:Ball = a[j+1];
                                
                                lines.push(new Line(new Point(b1.x, b1.y), new Point(b2.x, b2.y)));
                        }
                        lines.push(new Line(new Point(a[a.length-1].x, a[a.length-1].y),
                                                                                                           new Point(a[0].x, a[0].y)));
                        return lines;
                }
        }
}

import flash.display.*;
internal class Ball extends Sprite{
        public var vx:int = 0;
        public var vy:int = 0;
        public var radius:int;
        public var currentColor:int;
        public function Ball(c:Number=0, radius:Number = 0, x:int=0,y:int=0){
                this.x = x;
                this.y = y;
                graphics.lineStyle(1, 0, 0.5);
                graphics.beginFill(c);
                graphics.drawCircle(0,0,radius);
                graphics.endFill();
                this.radius = radius;
        }
        
        public function set color(c:int):void{
                if(currentColor != c){
                        currentColor = c;
                        graphics.clear();
                        graphics.lineStyle(1, 0, 0.5);
                        graphics.beginFill(currentColor);
                        graphics.drawCircle(0,0,radius);
                        graphics.endFill();
                }
        }
        
}

import flash.geom.*;
internal class Line{
        public var p1:Point;
        public var p2:Point;
        public function Line(p1:Point, p2:Point){
                this.p1 = p1;
                this.p2 = p2;
        }
        
        // 直線の交点(線分の交点ではない)
        public static function crossPoint(lhs:Line, rhs:Line):Point {
                var a:Point = new Point(lhs.p2.x - lhs.p1.x, lhs.p2.y- lhs.p1.y);
                var b:Point = new Point(rhs.p2.x - rhs.p1.x, rhs.p2.y- rhs.p1.y);
                var c:Point = new Point(rhs.p1.x - lhs.p1.x, rhs.p1.y- lhs.p1.y);
                
                var result:Point = new Point();
                
                var cross_b_c:Number = b.x*c.y - b.y*c.x;
                var cross_b_a:Number = b.x*a.y - b.y*a.x;
                
                if(cross_b_a == 0)
                return null;
                
                result.x = lhs.p1.x + a.x * cross_b_c / cross_b_a;
                result.y = lhs.p1.y + a.y * cross_b_c / cross_b_a;
                
                return result;
        }
        
        public static function isCross(lhs:Line, rhs:Line):Boolean{
                var p:Point = crossPoint(lhs,rhs);
                
                return (p != null &&
                (p.x - rhs.p1.x) * (p.x - rhs.p2.x) + (p.y - rhs.p1.y) * (p.y - rhs.p2.y) < 0) &&
                ((p.x - lhs.p1.x) * (p.x - lhs.p2.x) + (p.y - lhs.p1.y) * (p.y - lhs.p2.y) < 0)
                ;
        }
}


凸な多角形であれば、行列式を使った判定方法を利用する方法もある。
スポンサーサイト

Comment

Post a comment

Secret

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