From ba27d5ee26e3deb57737f7b97a1be09e2b1a6bc3 Mon Sep 17 00:00:00 2001 From: Adam Greenwood-Byrne Date: Thu, 16 Jul 2020 11:03:12 +0100 Subject: [PATCH] Better collision detection in part6-breakout --- part6-breakout/README.md | 27 +++++++++++++++++++++++++- part6-breakout/kernel.c | 41 +++++++++++----------------------------- 2 files changed, 37 insertions(+), 31 deletions(-) diff --git a/part6-breakout/README.md b/part6-breakout/README.md index f6a7744..133a568 100644 --- a/part6-breakout/README.md +++ b/part6-breakout/README.md @@ -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. 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. diff --git a/part6-breakout/kernel.c b/part6-breakout/kernel.c index 750933f..8cf02af 100644 --- a/part6-breakout/kernel.c +++ b/part6-breakout/kernel.c @@ -53,42 +53,23 @@ void moveObject(struct Object *object, int xoff, int 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= objects[i].x && x <= objects[i].x + objects[i].width) { - if (y >= objects[i].y && y <= objects[i].y + objects[i].height) { - if (&objects[i] != ball && objects[i].alive == 1) { - return &objects[i]; - } + if (&objects[i] != with && objects[i].alive == 1) { + if (with->x + xoff > objects[i].x + objects[i].width || objects[i].x > with->x + xoff + with->width) { + // with is too far left or right to ocllide + } 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; } -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 unsigned char getUart() @@ -207,7 +188,7 @@ void main() uart_loadOutputFifo(); // Are we going to hit anything? - foundObject = detectCollision(velocity_x, velocity_y); + foundObject = detectCollision(ball, velocity_x, velocity_y); if (foundObject) { if (foundObject == paddle) {