First of all, I planed to post this topic somewhere else, so I'm not sure if it has its place in Function Space. If not, please forgive me and feel free to delete my post.
I made a JavaScript bricks breaking game for fun (and training). The source code is here and a demo can be played here.
First thing, I must tell you about the way my ball is moving: x
and y
directions on a HTML canvas, obviously. But these variables can only be assigned with 1
or -1
values, otherwise I have no idea how to detect a collision between my ball and an object (brick or bar). If the ball moves by 10 pixels on a tick, I can't say if it hits something during its move.
Because of this 1
and -1
value, my ball always have a rebound of 90°, and all games are nearly the same… And the only way to accelerate the ball would be to have a specific Interval (timer) for the ball. I'm not sure if that's ok...
This was the first thing. Collisions now. I am currently handling only 2 types of collisions: bricks' bottoms and top of the bar with this messy code called on each tick of the game:
if (_ballY - Breakoid.BALL_SIZE <= Breakoid.NBROWS * (Breakoid.BRICK_HEIGHT + Breakoid.EMPTY_SPACE)
&&
_ballY - Breakoid.BALL_SIZE > Breakoid.BRICK_HEIGHT) // this if statement checks if the ball is in bricks zone.
{
var Y = Math.floor((_ballY - Breakoid.BALL_SIZE + Breakoid.BRICK_HEIGHT) / (Breakoid.BRICK_HEIGHT + Breakoid.EMPTY_SPACE)) - 1
var X = Math.floor((_ballX - Breakoid.BALL_SIZE + _brickWidth) / (_brickWidth + Breakoid.EMPTY_SPACE)) -1
if (_bricksArray[Y][X]) {
_bricksArray[Y][X] = false
_ballDirY = 1
}
}
I'd like, of course, to make my ball rebound against my bricks' sides (and bar too). But I can't do another messy thing like the code up-there, because what if I want to make different levels with loaded "bricks maps" then? I must have an efficient code.
I must confess I'm pretty stucked. Those two problems are finally the same one: how can I properly handle collisions in a bricks breaking game?
I thought about a Bricks
class (there will be one anyway) with a detectCollision()
magic method but I'm not convinced...
Direction: By representing the direction of your ball as an (x,y) pair where x and y can only be either -1 or 1, your ball can move in only four directions: (-1, -1), (-1, 1), (1, -1), and (1,1). One fix is to allow x and y to take on any values. Then, for example, a ball traveling "upward" has direction (0, 1). A ball moving at angle 60 degrees from the +x axis has a direction of approximately (0.5, 0.866). And in general, a ball moving at an angle ${\theta}$ has direction ${(\cos\theta, \sin\theta)}$.
Collisions: A ball colliding (elastically) against a flat, motionless surface is governed by a simple law: the incoming angle formed is the same as the outgoing angle.
Suppose your ball's direction is represented by (x, y). If the ball bounces off a vertical surface, then the new direction is (-x, y). Likewise, if the ball bounces off a horizontal surface, then the new direction is (x, -y). (What if the surface is not horizontal or vertical? Then you must compute an angle between the surface and the ball's direction, and then compute the new direction. I can explain this if you like.).
However, this still doesn't fix one thing. If your rectangles are all aligned in a grid, then the angle at which your ball hits a surface never changes. If you start the ball going straight up, then it will bounce straight down, and then straight up and so on, forever. And if you start it going at an 18 degree angle, then it will bounce off the horizontal surfaces at an 18 degree angle and off the vertical surfaces at a 78 degree angle always. You need some way to introduce changes to the ball's direction, and how you do that is up to you.
edit: I looked around for a place with some good information on vector maths: http://tutorial.math.lamar.edu/Classes/CalcII/Vectors_Basics.aspx http://www.onlinemathlearning.com/vectors.html
That was very nice to you to answer my question using images and links, thank you!
I was aware about the "only 4 directions" thing but couldn't find a way to express it... Anyway: trigonometric circle, I should have known! Thank you for that.
Regarding the bounces thing, I remember my Physics class and that's the way I dealt with rebounds. I was also aware of the "perpetual rebound" thing but I was wondering if I was right. Thank you for making this clear. I thought about a random variable, very small, at each bounce to fix this (Based on my experience with other brick breaking games, that's what others do).
However, my interrogation is more about the "when" that the "how". Detect collision seems to be very difficult with the trigonometric thing because each brick (or bar) side is at a given x
position. But my ball can have a x
direction of 0.3 or 1.3 for example. Then, "when does the ball touched a brick?", that's a difficult question to me...
That was very nice of you to answer my question using images and links, thank you!
I was aware about the "only 4 directions" thing but couldn't find a way to express it... Anyway: trigonometric circle, I should have known! Thank you for that.
Regarding the bounces thing, I remember my Physics class and that's the way I dealt with rebounds. I was also aware of the "perpetual rebound" thing but I was wondering if I was right. Thank you for making this clear. I thought about a random variable, very small, at each bounce to fix this (Based on my experience with other brick breaking games, that's what others do).
However, my interrogation is more about the "when" that the "how". Detect collision seems to be very difficult with the trigonometric thing because each brick (or bar) side is at a given x
position. But my ball can have a x
direction of 0.3 or 1.3 for example. Then, "when does the ball touched a brick?", that's a difficult question to me...
*******WOW sorry about that. I wanted to edit my reply (first sentence) but I messed it up.*****
Oh, there's nothing wrong with how you're doing the collision detection. You know when there's a collision simply by checking for a collision every tick (this is what you're doing). And how do you know if there's a collision? You need to find the closest brick in the grid to the ball (you're doing this by direct computation, which is much better than iterating over the whole array), and then compare the bounds of the brick with the bounds of the ball. That is, you have the ball's position coordinates P=(px, py). You need the brick's min and max x-coordinates, and its min and max y-coordinates; and you compute the same min and max position coordinates for the ball. Then it's just a matter of checking if the brick's min x is greater than the ball's max x, or if the brick's max x is greater than the ball's min x, and same for the y direction.
For efficiency, I would suggest you pre-compute the bounds of each brick when you set up the array of bricks. That is, it would be faster if every tick you just did something like brick[i][j].minX and brick[i][j].maxX to get the bounds of the brick instead of computing this every tick (this will work since the brick's positions do not change).
Mhh good idea indeed, thank you ! I'm going to try this :)
This is really an insightful opinion!