Search code examples
actionscript-3collision

actionscript 3.0 can't figure out why a collision fails with one line in an array of lines


can't figure out why the ball object falls right through line[2] while it bounces off all the others. I have two classes below; a main class that creates the lines along with some collision and motion code for the ball, and a class for the ball. I included a comment above the line in the main class which pertains to the line that doesn't interact. When the program runs, it bounces off of all the lines with some distance based collision code - but passes right through one of the lines- the line created in the array at line[2]

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

    public class MultiAngleBounce extends Sprite
    {
        private var ball:Ball;
        private var lines:Array;
        private var numLines:uint = 6;
        private var gravity:Number = 0.3;
        private var bounce:Number = -0.6;



        public function MultiAngleBounce()
        {
            init();
        }

        private function init():void
        {
            ball = new Ball(20);
            addChild(ball);
            ball.x = 100;
            ball.y = 100;

            //create five lines
            lines = new Array();
            for(var i:uint = 0; i < numLines; i++)
            {
                var line:Sprite = new Sprite();
                line.graphics.lineStyle(1);
                line.graphics.moveTo(-50, 0);
                line.graphics.lineTo(50, 0);
                addChild(line);
                lines.push(line);
            }

            lines[0].x = 100;
            lines[0].y = 100;
            lines[0].rotation = 30;

            lines[1].x = 100;
            lines[1].y = 230;
            lines[1].rotation = 50;

            //why does this one get ignored
            lines[2].x = 250;
            lines[2].y = 180;
            lines[2].rotation = -30;

            lines[3].x = 150;
            lines[3].y = 330;
            lines[3].rotation = 10;

            lines[4].x = 230;
            lines[4].y = 250;
            lines[4].rotation = -30;

            lines[5].x = 300;
            lines[5].y = 350;
            lines[5].rotation = -20;

            addEventListener(Event.ENTER_FRAME, onEnterFrame);

        }

        private function onEnterFrame(event:Event):void
        {
            //normal motion code
            ball.vy += gravity;
            ball.x += ball.vx;
            ball.y += ball.vy;

            //bounce off ceiling, floor, walls
            if(ball.x + ball.radius > stage.stageWidth)
            {
                ball.x = stage.stageWidth - ball.radius;
                ball.vx *= bounce;
            }
            else if(ball.x - ball.radius < 0)
            {
                ball.x = ball.radius;
                ball.vx *= bounce;
            }
            if(ball.y + ball.radius > stage.stageHeight)
            {
                ball.y = stage.stageHeight - ball.radius
                ball.vy *= bounce;
            }
            else if(ball.y - ball.radius < 0)
            {
                ball.y = ball.radius;
                ball.vy *= bounce;
            }

            //check each line
            for(var i:uint = 0; i < numLines; i++)
            {
                checkLine(lines[i]);
            }
        }

        private function checkLine(line:Sprite):void
        {
            //get the bounding box of the line
            var bounds:Rectangle = line.getBounds(this);
            if(ball.x > bounds.left && ball.x < bounds.right)
            {
                //get angle, sine and cosine
                var angle:Number = line.rotation * Math.PI / 180;
                var cos:Number = Math.cos(angle);
                var sin:Number = Math.sin(angle);

                //get position of ball, relative to line
                var x1:Number = ball.x - line.x;
                var y1:Number = ball.y - line.y;

                //rotate coordinates
                var y2:Number = cos * y1 - sin * x1;

                //rotate velocity
                var vy1:Number = cos * ball.vy - sin * ball.vx;

                //perform bounce with rotated values
                if(y2 > -ball.height / 2 && y2 < vy1)
                {
                    //rotate coordinates
                    var x2:Number = cos * x1 + sin * y1;

                    //rotate velocity
                    var vx1:Number = cos * ball.vx + sin * ball.vy;

                    y2 = -ball.height / 2;
                    vy1 *= bounce;

                    //rotate everything back;
                    x1 = cos * x2 - sin * y2;
                    y1 = cos * y2 + sin * x2;
                    ball.vx = cos * vx1 - sin * vy1;
                    ball.vy = cos * vy1 + sin * vx1;
                    ball.x = line.x + x1;
                    ball.y = line.y + y1;
                }
            }
        }
    }
}



package
{
    import flash.display.Sprite;

    public class Ball extends Sprite
    {
        public var radius:Number;
        private var color:uint;
        public var internalAngle:Number;
        public var internalRadius:Number;
        internal var vx:Number = 0;
        internal var vy:Number = 0;

        public function Ball(radius:Number = 40, color:uint = 0xff0000)
        {
            this.radius = radius;
            this.color = color;
            init();
        }

        public function init():void {
            graphics.beginFill(color);
            graphics.drawCircle(0, 0, radius);
            graphics.endFill();

        }
    }
}

Solution

  • You bounds check

    if(ball.x > bounds.left && ball.x < bounds.right)
    

    is failing for the second line. The ball hasn't attained enough speed by the time it reaches lines[2] that it can get completely into the bounds rect. You can use

    if(line.hitTestObject(ball))
    

    to do collision detection instead.