kingBook

导航

凹多边形碰撞检测

package {
    import flash.display.Sprite;
    import flash.geom.Point;
    import flash.text.TextField;
    import flash.text.TextFormat;
    import flash.events.MouseEvent;
    import flash.events.Event;

    public class ConcaveCollisionExample extends Sprite {
        private var poly1Sprite:Sprite;
        private var poly2Sprite:Sprite;
        private var resultTF:TextField;
        
        // 多边形本地坐标(相对于各自Sprite)
        private var poly1Local:Array = [
            new Point(0, 0),
            new Point(100, 0),
            new Point(100, 100),
            new Point(50, 50),
            new Point(0, 100)
        ];
        
        private var poly2Local:Array = [
            new Point(0, 0),
            new Point(100, 0),
            new Point(100, 100),
            new Point(50, 50),
            new Point(0, 100)
        ];

        public function ConcaveCollisionExample() {
            createPolygons();
            setupInteraction();
            createResultDisplay();
            updateCollision();
        }

        private function createPolygons():void {
            // 创建并绘制红色多边形
            poly1Sprite = new Sprite();
            poly1Sprite.x = 100;
            poly1Sprite.y = 100;
            drawPolygon(poly1Sprite, poly1Local, 0xFF0000);
            addChild(poly1Sprite);

            // 创建并绘制蓝色多边形
            poly2Sprite = new Sprite();
            poly2Sprite.x = 180;
            poly2Sprite.y = 150;
            drawPolygon(poly2Sprite, poly2Local, 0x0000FF);
            addChild(poly2Sprite);
        }

        private function drawPolygon(target:Sprite, points:Array, color:uint):void {
            target.graphics.clear();
            target.graphics.lineStyle(2, 0x000000);
            target.graphics.beginFill(color, 0.5);
            target.graphics.moveTo(points[0].x, points[0].y);
            for (var i:int = 1; i < points.length; i++) {
                target.graphics.lineTo(points[i].x, points[i].y);
            }
            target.graphics.lineTo(points[0].x, points[0].y);
            target.graphics.endFill();
        }

        private function setupInteraction():void {
            // 启用交互
            poly1Sprite.buttonMode = true;
            poly2Sprite.buttonMode = true;
            
            // 添加事件监听
            poly1Sprite.addEventListener(MouseEvent.MOUSE_DOWN, startDragPoly);
            poly2Sprite.addEventListener(MouseEvent.MOUSE_DOWN, startDragPoly);
            stage.addEventListener(MouseEvent.MOUSE_UP, stopDragPoly);
        }

        private function createResultDisplay():void {
            resultTF = new TextField();
            resultTF.defaultTextFormat = new TextFormat("Arial", 20, 0x000000);
            resultTF.x = 50;
            resultTF.y = 300;
            resultTF.width = 300;
            addChild(resultTF);
        }

        private function startDragPoly(e:MouseEvent):void {
            e.target.startDrag();
            addEventListener(Event.ENTER_FRAME, updateCollision);
        }

        private function stopDragPoly(e:MouseEvent):void {
            stopDrag();
            removeEventListener(Event.ENTER_FRAME, updateCollision);
            updateCollision();
        }

        private function updateCollision(e:Event = null):void {
            // 转换本地坐标为全局坐标
            var poly1Global:Array = convertLocalToGlobal(poly1Local, poly1Sprite);
            var poly2Global:Array = convertLocalToGlobal(poly2Local, poly2Sprite);
            
            // 检测碰撞
            var collision:Boolean = checkCollision(poly1Global, poly2Global);
            resultTF.text = "碰撞检测结果: " + collision;
        }

        private function convertLocalToGlobal(localPoints:Array, sprite:Sprite):Array {
            var globalPoints:Array = [];
            for each (var p:Point in localPoints) {
                globalPoints.push(new Point(sprite.x + p.x, sprite.y + p.y));
            }
            return globalPoints;
        }

        // 以下碰撞检测方法保持不变
        private function checkCollision(polyA:Array, polyB:Array):Boolean {
            for (var i:int = 0; i < polyA.length; i++) {
                var a1:Point = polyA[i];
                var a2:Point = polyA[(i + 1) % polyA.length];
                
                for (var j:int = 0; j < polyB.length; j++) {
                    var b1:Point = polyB[j];
                    var b2:Point = polyB[(j + 1) % polyB.length];
                    
                    if (segmentsIntersect(a1, a2, b1, b2)) {
                        return true;
                    }
                }
            }

            for each (var p:Point in polyA) {
                if (isPointInPolygon(p, polyB)) return true;
            }
            
            for each (p in polyB) {
                if (isPointInPolygon(p, polyA)) return true;
            }

            return false;
        }

        private function segmentsIntersect(a1:Point, a2:Point, b1:Point, b2:Point):Boolean {
            var denominator:Number = (b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y);
            if (denominator == 0) return false;

            var ua:Number = ((b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x)) / denominator;
            var ub:Number = ((a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x)) / denominator;

            return ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1;
        }

        private function isPointInPolygon(p:Point, polygon:Array):Boolean {
            var inside:Boolean = false;
            for (var i:int = 0, j:int = polygon.length - 1; i < polygon.length; j = i++) {
                var pi:Point = polygon[i];
                var pj:Point = polygon[j];
                
                if (((pi.y > p.y) != (pj.y > p.y)) &&
                    (p.x < (pj.x - pi.x) * (p.y - pi.y) / (pj.y - pi.y) + pi.x)) {
                    inside = !inside;
                }
            }
            return inside;
        }
    }
}

posted on 2025-03-01 22:40  kingBook  阅读(21)  评论(0)    收藏  举报