Search code examples
actionscriptcollision-detection

actionscript 3.0 built-in collision detection seems to be flawed even with perfect rectangles


This is my first post. I hope the answer to this is not so obviously found- I could not find it. I have a collision detection project in as3- I know that odd shapes will not hit the built-in detection methods perfectly, but supposedly perfect rectangles are exactly the shape of the bounding boxes they are contained it- yet- running the code below, I find that every once in a while a shape will not seem to trigger the test at the right time, and I cannot figure out why.

I have below two classes- one creates a rectangle shape, and a main class which creates a shape with random width and height, animates them from the top of the screen at a random x value towards the bottom at a set rate, mimicking gravity. If a shape hits the bottom of the screen, it situates itself half way between the displayed and undisplayed portions of the stage about its lower boundary, as expected- but when two shapes eventually collide, the expected behavior does not always happen- the expected behavior being that the shape that has fallen and collided with another shape should stop and rest on the top of the shape it has made contact with, whereas sometimes the falling shape will fall partially or completely through the shape it should have collided with.

does anyone have any idea why this is?

here are my two classes below in their entirety:

// box class //

package
{
    import flash.display.Sprite;

    public class Box extends Sprite
    {
        private var w:Number;
        private var h:Number;
        private var color:uint;
        public var vx:Number = 0;
        public var vy:Number = 0;

        public function Box(width:Number=50,
                            height:Number=50,
                            color:uint=0xff0000)

        {
            w = width;
            h = height;
            this.color = color;
            init();
        }

        public function init():void{
            graphics.beginFill(color);
            graphics.drawRect(0, 0, w, h);
            graphics.endFill();
        }
    }
}

//main class//

package
{
    import flash.display.Sprite;
    import flash.events.Event;

    public class Boxes extends Sprite
    {
        private var box:Box;
        private var boxes:Array;
        private var gravity:Number = 16;


        public function Boxes()
        {
            init();
        }
        private function init():void

        {   
            boxes = new Array();
            createBox();
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
        }

        private function onEnterFrame(event:Event):void
        {
            box.vy += gravity;
            box.y += box.vy;

            if(box.y + box.height / 2 > stage.stageHeight)
            {
                box.y = stage.stageHeight - box.height / 2;
                createBox();
            }
            for(var i:uint = 0; i < boxes.length; i++)
            {
                if(box != boxes[i] && box.hitTestObject(boxes[i]))
                {
                    box.y = boxes[i].y - box.height;
                    createBox();
                }
            }

    }

        private function createBox():void
        {
            box = new Box(Math.random() * 40 + 10,
                          Math.random() * 40 + 10, 
                          0xffaabb)
            box.x = Math.random() *stage.stageWidth;
            addChild(box);
            boxes.push(box);
        }
}
}

Solution

  • Make sure box.vy never exceeds any of the heights of any boxes created. Otherwise, it is possible the box can pass through other boxes while falling. (if box.vy = 40 and boxes[i].height=30, it is possible to pass right over it).

    Just add a check:

    if(box.vy>terminalVelocity)box.vy=terminalVelocity)
    

    Where terminalVelocity is whatever the minimum height a box can be (in your code, it looks like 10). If you really want those small boxes, you will have to use something more precise than hitTestObject.