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:
- Create your ball object and your brick objects. Add all the bricks to a array
- Create all your graphics (ball and bricks), and position them based on the info in their respective objects
- Every frame, in Main (or your physics code), update the position of
ballObj
based on its velocity
- Run through the
brickObjs
array and check if we have a collision
- 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)
- 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)