Better collision detection in part6-breakout

This commit is contained in:
Adam Greenwood-Byrne 2020-07-16 11:03:12 +01:00
parent 05fc8b4733
commit ba27d5ee26
2 changed files with 37 additions and 31 deletions

View file

@ -85,8 +85,33 @@ i=8 : (i % zoom) = 0 -> advance the pointer
... ...
``` ```
Perhaps you can see why we changed our loop to count from 1 rather than 0? Perhaps you can see why we changed our outer loop to count from 1 rather than 0?
If you want, you can now make these changes to _fb.c_ in your part5-framebuffer code and exercise them properly in _kernel.c_ to check that they work. Don't forget to update the function definition in _fb.h_ to include the `zoom` parameter too. If you want, you can now make these changes to _fb.c_ in your part5-framebuffer code and exercise them properly in _kernel.c_ to check that they work. Don't forget to update the function definition in _fb.h_ to include the `zoom` parameter too.
It is also now trivial to modify `drawString` to take a `zoom` parameter and pass it through, so I won't document the changes here. It is also now trivial to modify `drawString` to take a `zoom` parameter and pass it through, so I won't document the changes here.
Object tracking
---------------
As we can now draw text (e.g. a score/lives counter), rectangles (paddle & bricks) and circles (ball), we can recreate the Breakout game screen. Check out `initBall()`, `initPaddle()`, `initBricks()` and `drawScoreboard(score, lives)` in our new _kernel.c_.
In addition to the graphics code, you'll see that we're keeping a record of each game object we create in the global `objects` array:
* its (x, y) coordinates
* its width & height
* what type of object it is (ball, paddle or brick)
* whether it's "alive"
We also store a global pointer to the ball and paddle object, so they're easy to track down!
As we'll need to knock out our bricks during gameplay, we create `removeObject(object)`, which simply draws a filled black rectangle over the object we pass, and sets its `alive` parameter to 0 to signal that it's now out of play.
To know that our ball is about to hit a brick (or indeed the paddle), we'll need to detect **collisions**. We simply conduct a search of the alive objects and return the first object we find whose coordinates overlap. If no object is found, we return 0. `detectCollision(object, xoff, yoff)` implements this. Note that `xoff` and `yoff` can be negative since the ball could be travelling in any direction.
Keyboard input
--------------
We'll be using the UART to take input, just like we did in part4-miniuart.
`getUart()` simply checks if a key has been pressed and, if so, it returns the character, otherwise 0. We don't want this function to wait for a key, because gameplay needs to continue regardless.

View file

@ -53,42 +53,23 @@ void moveObject(struct Object *object, int xoff, int yoff)
object->y = object->y + yoff; object->y = object->y + yoff;
} }
struct Object *objectAt(unsigned int x, unsigned int y) struct Object *detectCollision(struct Object *with, int xoff, int yoff)
{ {
for (int i=0; i<numobjs;i++) { for (int i=0; i<numobjs;i++) {
if (x >= objects[i].x && x <= objects[i].x + objects[i].width) { if (&objects[i] != with && objects[i].alive == 1) {
if (y >= objects[i].y && y <= objects[i].y + objects[i].height) { if (with->x + xoff > objects[i].x + objects[i].width || objects[i].x > with->x + xoff + with->width) {
if (&objects[i] != ball && objects[i].alive == 1) { // with is too far left or right to ocllide
return &objects[i]; } else if (with->y + yoff > objects[i].y + objects[i].height || objects[i].y > with->y + yoff + with->height) {
} // with is too far up or down to ocllide
} else {
// Collision!
return &objects[i];
} }
} }
} }
return 0; return 0;
} }
struct Object *detectCollision(int xoff, int yoff)
{
struct Object *collision;
unsigned int x = ball->x + xoff;
unsigned int y = ball->y + yoff;
collision = objectAt(x,y);
if (collision) return collision;
collision = objectAt(x + ball->width, y);
if (collision) return collision;
collision = objectAt(x, y + ball->height);
if (collision) return collision;
collision = objectAt(x + ball->width, y + ball->height);
if (collision) return collision;
return 0;
}
// KEY HANDLER // KEY HANDLER
unsigned char getUart() unsigned char getUart()
@ -207,7 +188,7 @@ void main()
uart_loadOutputFifo(); uart_loadOutputFifo();
// Are we going to hit anything? // Are we going to hit anything?
foundObject = detectCollision(velocity_x, velocity_y); foundObject = detectCollision(ball, velocity_x, velocity_y);
if (foundObject) { if (foundObject) {
if (foundObject == paddle) { if (foundObject == paddle) {