0

I have an object and a ball in an as3 scene. My question is how do I make the ball bounce off the object along the y axis. I already have it bouncing offf the x axis and it's fine. The problem is that simply adding the y axis in the code makes the ball bounce incorrectly from the object. This is the code on the main timeline and inside the brick class

var ballXSpeed:Number = 8;//X Speed of the Ball
 var ballYSpeed:Number = 8;//Y Speed of the Ball
 mcBall.addEventListener(Event.ENTER_FRAME, moveBall);
 function moveBall(event:Event):void {
mcBall.x +=  ballXSpeed;//Move the ball horizontally
mcBall.y +=  ballYSpeed;//Move the ball vertically

not sure if this code is relevant:

if (mcBall.x >= stage.stageWidth - mcBall.width){
//if the ball hits the right side
of the screen, then bounce off//
ballXSpeed *=  -1;
}

And inside the brick:

  if (this.hitTestObject(_main.mcBall))
        {
    _main.ballYSpeed *=  -1;
    /_main.ballXSpeed *=  -1; does not work/

Thank you and Happy new year!

James
  • 3,551
  • 1
  • 28
  • 38
Johnnien
  • 19
  • 7

1 Answers1

0

The reason why it's not working is because you don't know where your ball has hit your brick (the bottom, the left, the right, etc.)

This line:

this.hitTestObject(_main.mcBall)

is just telling you that a collision occurred, but you've no other information than that. One very basic method would be to just check the position of your ball after the collision. Something like:

if( this.hitTestObject(_main.mcBall) )
{
    // hold our ball position
    var bx:Number = _main.mcBall.x;
    var by:Number = _main.mcBall.y;
    var br:Number = _main.mcBall.width * 0.5;

    // get our bounds (assuming that the brick has it's registration point
    // in the center) - extend by the radius of the ball to cover the points
    var left:Number     = this.x - this.width * 0.5 - br; 
    var right:Number    = this.x + this.width * 0.5 + br;
    var top:Number      = this.y - this.height * 0.5 - br;
    var bottom:Number   = this.y + this.height * 0.5 + br;

    // check the position of the ball in relation to our brick
    if( ( bx >= left && bx <= right && by >= bottom ) ||    // bottom
        ( bx >= left && bx <= right && by <= top ) )        // top
    {
        _main.mcBall.ballYSpeed *= -1;
    }
    else // hit the left or the right
    {
        _main.mcBall.ballXSpeed *= -1;
    }
}

This is a very basic method, and will probably break around the corners of the brick, or if the ball is going too quickly.

You can get much more robust collision detection by looking up some collision detection formulas:

I'd also recommend looking up vectors (http://www.intmath.com/vectors/vectors-intro.php) and normals (perpendicular vectors), as they'll make your like much easier. E.g. your ball's position from one frame to another is a vector - the side of one of your blocks is another.

Once you've detected a collision, then you can use this simple reflect method to reflect your ball, no matter the gradient of the side that it hit:

public function reflect( vector:Point, normal:Point ):void
{
    // using the formula [R = V - (2 * V.N) * N] or [V -= 2 * N * (N.V
    var dot:Number  = ( vector.x * normal.x ) + ( vector.y * normal.y );
    var vn2:Number  = 2.0 * MathUtil.dot( vector, normal );
    vector.x        = vector.x - ( normal.x * vn2 );
    vector.y        = vector.y - ( normal.y * vn2 );
}

In that example, vector would be your ball's speed, and normal would be the perpendicular vector for the side of the brick that was hit (e.g. the normal for the bottom side of the brick would point down, for the top side of the brick would point up, for the left side would point left, etc)

Edit 03/01

Hm, I'm not sure why you're not getting collision - I downloaded your files, created a simple project (I don't have the version of Flash that you're using), and have a simple ball colliding with a simple brick. The collisions aren't perfect, because this sort of collision detection is very basic, but it works. When you say you "cannot get any collision at all", have you tried putting a trace() inside the collision block to see if it's being called?

There are a few things you could try:

1) Push the ball outside of the block before doing the collision response - with this form of collision detection, the ball is inside the block before it's detected. Sometimes, this means that the next frame, it's also inside and so the ballXSpeed/ballYSpeed gets reflected again. You can move the ball so that it's just touching the block before reflecting:

if( bx >= left && bx <= right && by >= bottom ) // bottom
{
    _main.mcBall.y = bottom; // move the ball so that it's touching
    _main.mcBall.ballYSpeed *= -1; // reflect
}
...

2) If you have multiple blocks, then your problem can be that they're all performing the same collision check with the ball - there's a good chance that if the ball is inside one block, it's also inside another - this is especially true because you're using hitTestObject(), which compares the bounding boxes of the elements (you're not colliding with the ball, you're colliding with the imaginary bounds box that surrounds the ball, i.e. another square). In this case, one block will reflect the ball, then the next one will re-reflect the ball. You need to move your collision detection to a centralised location (e.g. your Main) - keep a list of all blocks, change your collision to be a loop, and when you detect a collision, break out. Something like:

var bricks:Array = new Array(); // add all your bricks to this array (NOTE: remember to remove them when they're destroyed)

private function _onEnterFrame( e:Event ) // in Main
{
    var len:int = bricks.length;
    for( var i:int = 0; i < len; i++ )
    {
        if( this._checkBallCollisionWithBrick( this.mcBall, bricks[i] ) ) // same logic as before, just in a function
            break; // stop the loop
    }
}

This means you will only ever collide with one brick at a time.

3) Start using vectors and math for your collision

This is the best solution, but also the hardest, as you need to change how your game is set up, and it's a bit more advanced in terms of coding.

Basically, you need to split the logic of your game from the visuals. Take your ball for example. You would have a ball in memory, which holds position, velocity, radius, etc, and then you would have your ball graphics, which are updated just before rendering. In pseudo code it would run like this:

  1. Create your ball object and your brick objects. Add all the bricks to a array
  2. Create all your graphics (ball and bricks), and position them based on the info in their respective objects
  3. Every frame, in Main (or your physics code), update the position of ballObj based on its velocity
  4. Run through the brickObjs array and check if we have a collision
  5. If we have a collision, move the ballObj so it's just touching the brick collided, and reflect it's velocity (if you want to do it properly, you would determine when the ballObj collided with the brickObj (e.g. % of the frame time), so you could re-move ballObj along it's new velocity for the remainder of the frame, and perhaps collide with another object)
  6. At the end of the frame, update your ballGraphics to be at the position held in ballObj

Like I said, it's a bit more complex, but the results are better. It's always good to know this sort of stuff, but if you don't really care, you can also use a physics engine like Box2D: http://www.box2dflash.org/ (not as simple as you're probably looking for)

Community
  • 1
  • 1
divillysausages
  • 7,883
  • 3
  • 25
  • 39
  • Thank you! I For the past 2 hours I tried to make it work with the code that you give me in my brick as file, and cannot get any collision at all I looked up all the other methods as well and read about the vectors.... Can you tell me where can I use the reflect method. Can I use it inside that brick as file? Can you look at the files? https://app.box.com/s/0acyz9wkgniaug8zd96x The brick on the right is with the code from the first paragraph. – Johnnien Jan 02 '15 at 15:15
  • I've updated the post - physics is not something that really something that can be summed up in a post, so it depends if you want to keep it simple like you have it, or go a lot more in-depth – divillysausages Jan 03 '15 at 12:10
  • Thank you So much. It's really unfortunate you can't open cs5 files. It would have taken you 10 minutes to fix this and I would have paid you. My game is already done and it works with the code I have except for when the ball hits the brick from the x axis, which does not happen very often, but it Does Happen.....It's normal speed, so any collision would have worked. I have set the visuals and collisions already.... This does answer my question theoretically. Thank you for your efforts! – Johnnien Jan 03 '15 at 23:37
  • I am sorry, the first block of code does really work. I had to change _main.mcBall.ballYSpeed into simply _main.ballYSpeed. The problem now is that it could never get hit on all four sides. If I adjust it to 3, the fourth will not work, but it's much better than before. Thank you! – Johnnien Jan 07 '15 at 13:04
  • "If I adjust it to 3, the fourth will not work" - I'm not sure I understand you here - if you adjust what to 3? – divillysausages Jan 07 '15 at 15:50
  • If I adjust 3 sides I mean, it will not bounce of the fourth side. It would go inside the brick. – Johnnien Jan 14 '15 at 20:40