The Wall
One of the big "tricks" in making Breakout is to realise that
you should treat the Wall as an object in its own right, rather than simply having a bunch of separate global Brick objects.
By only having a single Wall object to worry about, things like collision detection become much easier: instead of having to check each ball against a set of individual bricks, we can delegate most of that problem to the Wall itself...
...Although this is clearly an oppressive act against the autonomous individuality of Bricks everywhere...
I need Arrays
The natural way of representing a wall is as a
two-dimensional array of bricks i.e. an array of rows,
where each row is itself an array of bricks.
As it happens, multi-dimensional arrays are actually
quite an easy thing to express in JavaScript...
array_2d = [
[1,1,1],
[0,1,2,1],
[2,0,2],
[1,2,0,3,0,0,2,1],
[3,3,4,3,3,4,3,3,4,3]
];
Bricks
How should we represent the bricks in our wall?
Perhaps the obvious answer is "as Brick objects".
...but there are reasons for considering other options.
What unique attributes does each brick have?
A position? (but that's implicit).
What else?
i.e. Roughly speaking, "simpler is better"
(all other things being equal)
aka "Keep It Simple Stupid"
"Entities should not be multiplied without necessity"
Bricks don't need to be full objects.
A simple integer is enough, in some cases.
Collision
Implementing "proper" collision detection is a big subject
(and one that we'll tackle more fully in a few weeks),
but it turns out that we can (mostly) get away with
a relatively simple approach for Breakout...
For one thing, we can actually treat the ball as just a point!
And, by taking advantage of the regular structure of the Wall,
we can very quickly narrow our search down to a single candidate brick (instead of having to explicitly
check against all of them).
Brick Co-ordinates
Due to the regularity of the Wall "grid", it is quite easy to convert any particular pair of x,y co-ordinates into a
pair of "brick co-ordinates".
The result gives us a very quick and easy way
of locating the corresponding brick in the wall...
var brickX = Math.floor( (posX - WALL_X_BASE) / BRICK_WIDTH );
var brickY = Math.floor( (posY - WALL_Y_BASE) / BRICK_HEIGHT );
This is so much nicer than having to test against them all!
Ball Brick Bounce
Calculating the bounce from a brick is pretty easy...
...assuming that you can detect the difference between
a collision on the side vs one on the top/bottom.
(HINT: If you can't, just assume it's a top/bottom one!)
But you can approximate it pretty well by considering the
point of approach, and comparing the x and y velocities
to let you "guess" sensibly at the corners.
Ball Bat Bounce
In its simplest form, the ball-bat bounce just uses the
same kind of trivial "negate the y-velocity" trick as PONG.
If you want to get fancier (e.g. sharper bounce angles for hits
at the bat edges), then you need to think about general
"angle of incidence equals angle of reflection" stuff....
High Quality Visual Aids (1)
High Quality Visual Aids (2)
Doing The Math(s)
B = (I.N) * N
A = I - B
R = A - B
or we can flatten all of that out to:
R = I - 2 * (I.N) * N
This "flattened" form is how you'll often see it written,
but I think the use of 'A' and 'B' intermediates is clearer.
Collectibles
You might want to have stuff dropping out of the broken bricks e.g. little capsules containing power-ups.
These need to be "dynamic objects" (i.e. they must be created and destroyed while the game is actually running).
You'll want some kind of collection object to manage them.
An array seems like a sensible choice here. :-)
In fact, you really want a list, but JS doesn't have those as a built-in collection type, so we simulate them with arrays...
The Splice
When using arrays to store dynamic objects,
you'll possibly need to delete things from
arbitrary positions in the array.
> foods = ["apple", "banana", "carrot", "dog", "elderberry"]
["apple", "banana", "carrot", "dog", "elderberry"]
> foods.splice(3,1)
["dog"]
> foods
["apple", "banana", "carrot", "elderberry"]
NB: Be careful if you are deleting things while looping
over a collection. Deleting can make you "skip one".
Power-Ups
Power-Ups (/Downs) can be applied to the Bat (/Bats)
or the Ball (/Balls) of the Player (/Players), possibly as
a consequence of them grabbing a Collectible.
The actual Power-Up (/Down) logic is usually fairly simple e.g. increase score, give extra life, change bat-width etc.
More interesting cases include things like: sticky bat, speed modifier (for Bat and/or Ball), multi-ball and gun (!)
Speed modifiers are interesting; should they compound?
Graphics
Adding a nice background shouldn't be too hard.
You could even make it animate and/or
respond to gameplay events.
If you want to use sprite-graphics for the game entities,
that would be cool...
But you might need a multi-sprite image pre-loader.
(I can give you one, if you want).