针对循环问题的碰撞检测,只测试了一个数组项?

时间:2011-04-02 18:33:39

标签: actionscript-3 collision-detection

[我道歉,如果这不是一个非常深入的问题,但我想一劳永逸地解决这个问题]

我试图查看四叉树,但在没有任何优化正常工作的情况下遇到碰撞检测时遇到了麻烦。做了搜索,发现了一个非常简洁的例子: http://wonderfl.net/c/kyLx (主要是onenterframeC部分)

试图模仿这一点,它将无法正常工作。 在特定对象之间仅检测到一些碰撞。当物体不移动时,由于某种原因,它似乎工作得更好。

我真的无法弄清楚问题是什么,代码与示例基本相同。我没有盲目复制粘贴它,我理解发生了什么,除了这一部分:

if (j <= i)
                        continue;
我永远不会变得更大吗?该线也完全消除了我的任何工作碰撞。

这是我做的: [查看结果:http://martinowullems.com/collision.swf

主要课程

package  
{
    import com.martino.objects.Square;
    import com.martino.world.TestWorld;
    import flash.display.MovieClip;
    import flash.events.Event;
    import net.hires.debug.Stats;
    /**
     * ...
     * @author Martino Wullems
     */
    public class CollisionTest extends MovieClip
    {
        var world:TestWorld;

        public function CollisionTest() 
        {
            addEventListener(Event.ADDED_TO_STAGE, onStage);
        }

        private function onStage(e:Event):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, onStage);

            SetupWorld();
            addChild(new Stats());
        }

        private function SetupWorld():void 
        {
            world = new TestWorld();
            addChild(world);

            addObjects(50);
        }

        private function addObjects(amount:int):void 
        {
            for (var i:int = 0; i < amount; ++i) {

                var square:Square = new Square(14);
                world.addObject(square);
                square.x = Math.random() * stage.stageWidth;
                square.y = Math.random() * stage.stageHeight;
                square.speedX = (Math.random() * 1) + 1;
                square.speedY = (Math.random() * 1) + 1;
            }
        }

    }

}

TestWorld

package com.martino.world 
{
    import com.martino.objects.Ball;
    import com.martino.objects.CollisionObject;
    import flash.display.MovieClip;
    import flash.events.Event;
    /**
     * ...
     * @author Martino Wullems
     */
    public class TestWorld extends MovieClip
    {
        public var objects:Array;

        public function TestWorld()
        {
            initWorld();
        }

        private function initWorld():void 
        {
            objects = new Array();
            addEventListener(Event.ENTER_FRAME, loopWorld);
        }

        private function loopWorld(e:Event):void 
        {
            for (var i:int = 0; i < objects.length; i++) {

                MoveObject(objects[i]);
                CheckCollision(i, objects[i]);
            }
        }

        private function CheckCollision(i:int, object:CollisionObject):void 
        {
            //for (var j:int = i + 1; i < objects.length; j++) {

            for (var j:int = 0; j < objects.length; j++) {
                //if (j <= i)
            //continue;

                var objectB:CollisionObject = objects[j];

                //hittest
                if (object.hitTestObject(objectB)) {

                    object.isHit = true;
                    objectB.isHit = true;
                }else {

                    object.isHit = false;
                    objectB.isHit = false;
                }

                /////////////////
                //  CHECK X Y //
                ////////////////

                /*if (object.x + object.width < objectB.x) {
                    } else if (object.x > objectB.x + objectB.width) {
                               object.isHit = objectB.isHit = false;

                    } else if (object.y + object.height < objectB.y) {
                               object.isHit = objectB.isHit = false;

                    } else if (object.y > objectB.y + objectB.height) {

                               object.isHit = objectB.isHit = false;
                    } else {
                        object.isHit = objectB.isHit = true;
                    }*/

                object.debugDraw();
                objectB.debugDraw();
            }
        }

        private function MoveObject(object:CollisionObject):void 
        {
            object.x += object.speedX;
            object.y += object.speedY;

            ////////////////////
            //check boundaries//
            ////////////////////

            if (object.x > stage.stageWidth)
            {
                object.speedX *= -1;

            }else if (object.x < 0)
            {
                object.speedX *= -1;

            }else if (object.y > stage.stageHeight)
            {
                object.speedY *= -1;

            }else if (object.y < 0)
            {
                object.speedY *= -1;
            }


        }

        public function addObject(object:CollisionObject):void
        {
            objects.push(object);
            addChild(object);
        }

    }

}

CollisionObject

package com.martino.objects 
{
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    /**
     * ...
     * @author Martino Wullems
     */
    public class CollisionObject extends Sprite
    {
        public var size:int;
        public var speedX:int = 0;
        public var speedY:int = 0;
        public var graphic:Sprite;
        var sleeping:Boolean = false;

        public var isHit:Boolean = false;


        public function CollisionObject() 
        {
            addEventListener(MouseEvent.MOUSE_DOWN, grab);
            addEventListener(MouseEvent.MOUSE_UP, letGo);
        }

        private function grab(e:MouseEvent):void 
        {
            startDrag();
            speedX = 0;
            speedY = 0;
        }

        private function letGo(e:MouseEvent):void 
        {
            stopDrag();
        }

        public function Collision():void{


        }

        //////////////////////
    // setter and getter//
    //////////////////////


     public function set isHit(value:Boolean):void {
          _isHit = value;
          graphic.visible = _isHit;
          hitGraphic.visible = !_isHit;
     }

    public function get isHit():Boolean {
          return _isHit;
     }
    }

}

package com.martino.objects 
{
    import flash.display.Sprite;
    /**
     * ...
     * @author Martino Wullems
     */
    public class Square extends CollisionObject
    {
        public var hitGraphic:Sprite;

        public function Square(Size:int) 
        {
            size = Size;

            drawSquare();
        }

        private function drawSquare():void 
        {
            graphic = new Sprite();
            graphic.graphics.beginFill(0xFF0000);
            graphic.graphics.drawRect(0, 0, size, size);
            graphic.graphics.endFill();
            addChild(graphic);

            hitGraphic = new Sprite();
            hitGraphic.graphics.beginFill(0x0066FF);
            hitGraphic.graphics.drawRect(0, 0, size, size);
            hitGraphic.graphics.endFill();
            addChild(hitGraphic);
            hitGraphic.visible = false;
        }

        override public function Collision():void {

            trace("I collided with a friend (inside joke)");
        }

        public override function debugDraw():void {

            if (isHit) {

                graphic.visible = false;
                hitGraphic.visible = true;

            }else {

                graphic.visible = true;
                hitGraphic.visible = false;
            }
        }

    }

}

非常感谢任何帮助,希望进一步了解这一点!


编辑:更改了一些内容,有进展但我还不清楚其他内容!

改变了TestWorld.as中的一些内容:

package com.martino.world 
{
    import com.martino.objects.Ball;
    import com.martino.objects.CollisionObject;
    import flash.display.MovieClip;
    import flash.events.Event;
    /**
     * ...
     * @author Martino Wullems
     */
    public class TestWorld extends MovieClip
    {
        public var objects:Array;

        public function TestWorld()
        {
            initWorld();
        }

        private function initWorld():void 
        {
            objects = new Array();
            addEventListener(Event.ENTER_FRAME, loopWorld);
        }

        private function loopWorld(e:Event):void 
        {
            var object:*;

            for (var i:int = 0; i < objects.length; i++) {

                MoveObject(objects[i]);
                //CheckCollision(i);// doesn't work here for some reason [case 1]

            }

            CheckCollision(0); //[case 2]

        }

        private function CheckCollision(i:int):void 
        {               
                //test collision
                for (var i:int = 0; i < objects.length; i++){ //only use in case 2

                    var elementA:CollisionObject;
                    var elementB:CollisionObject;
                    elementA = objects[i];

                for (var j:int = i + 1; j < objects.length; j++) {

                    if (j <= i){
                        continue; //j resets each I loop and therefor sets collision to false while it could be true
                          }

                    elementB = objects[ j ]// as ObjSprite;

                    if (elementA.hitTestObject(elementB)) {
                       elementA.isHit = elementB.isHit = true;

                    }
                }
            } //[case 2]



        }

        private function MoveObject(object:CollisionObject):void 
        {
            object.x += object.vx;
            object.y += object.vy;

            ////////////////////
            //check boundaries//
            ////////////////////

            if (object.x > stage.stageWidth)
            {
                object.vx *= -1;

            }else if (object.x < 0)
            {
                object.vx *= -1;

            }else if (object.y > stage.stageHeight)
            {
                object.vy *= -1;

            }else if (object.y < 0)
            {
                object.vy *= -1;
            }

            object.isHit = false;// where do we check when it isn't colliding? this seems messy!
        }

        public function addObject(object:CollisionObject):void
        {
            objects.push(object);
            addChild(object);
        }

    }

}

还在collisionobject中添加了一个setter和getter(编辑前的部分)。

不知道为什么我不能将checkcollision放在回车框功能的循环中? (当我没有显示碰撞时)。在moveobjects中放置“isHit = false”以重置点击检查也似乎非常混乱。

我似乎无法找出的对象何时发生碰撞以重置它们。 在hittest上做一个else语句以检查是否没有碰撞不起作用,似乎是合乎逻辑的,因为在hittestcheck中可能只有2个项目发生碰撞。

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

我必须查看原始来源才能理解这一点。它在下面,供参考。

这一行

if (j <= i) continue;

是一种排列检查;它基本上确保每个组合只被检查一次,而不是多次。但是,为此,您需要有两个For循环 - 内部循环和外部循环。

你用以下几行做了同样的事情:

for (var j:int = i + 1; i < objects.length; j++) {

尝试使用for循环而不是从零开始的循环。不过,请留下“if j&lt; = i”这一行。我认为这将解决您的问题。 (这两个语句不能在这个循环中共存;如果一起使用,它们将导致你所描述的问题。)

祝你好运。

网站的原始资料来源:

    for (i = 0; i < myrects.length; i++) {
        elementA = myrects[ i ] as ObjMyRect;
        for (j = 0; j < myrects.length; j++) {
            if (j <= i)
                continue;
            elementB = myrects[ j ] as ObjMyRect;
            if (elementA.rect.x + elementA.rect.width < elementB.rect.x) {
            } else if (elementA.rect.x > elementB.rect.x + elementB.rect.width) {
            } else if (elementA.rect.y + elementA.rect.height < elementB.rect.y) {
            } else if (elementA.rect.y > elementB.rect.y + elementB.rect.height) {
            } else {
                elementA.isHit = elementB.isHit = true;
            }
        }
    }

(对于它的价值,我认为这个人的代码实际上会检查对象以防止碰撞 - 他应该将“if j&lt; = i”行更改为“if j&lt; i”。你解决了这个问题你原来的循环。)

答案 1 :(得分:0)

在查看他的代码之后,回顾一下你的代码。

这部分是必要的,以确保您不会浪费时间通过循环并重新检查已经比较的项目。

if (j <= i)
                    continue;

想象一下,阵列中有3个项目,并将项目3与项目0进行比较。然后将项目3与项目1和项目3与项目2进行比较。然后将项目2与项目3进行比较?你已经做到了。您希望将项目2与任何比自身小的项目进行比较,以避免重复。

你的代码接近他的代码,但是你已经用他已经定义的hitTestObject换掉了他的hitTest版本(使用position + dimension)。我只在第一个广场上看到一次击中测试。似乎有些东西......我会在那里放下一些跟踪陈述,看看有什么了。

最后,当您取消注释代码时,它是否有效?