diff --git a/source/main.cpp b/source/main.cpp index d77d9ca116d83a8ae28bde15538ff9015eef7aed..f4b769accf60f0f5ec02f91318e16f79dbe8e037 100755 --- a/source/main.cpp +++ b/source/main.cpp @@ -17,38 +17,128 @@ #include "MicroBit.h" -MicroBit ubit; + +/* + * NOTE: this global variable is our MicroBit instance. + * + * I'd much rather declare this in main() only (I don't like globals) and + * interact with it from my classes via a reference or a pointer to it, however + * this does not appear to work, for some unknown reason... + */ +MicroBit UBIT; -class EventThingy { +/** + * @brief Main class responsible for the game loop and logic + */ +class Game { public: - EventThingy() { - ubit.messageBus.listen( - MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, this, &EventThingy::event_handler_a - ); - - ubit.messageBus.listen( - MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, this, &EventThingy::event_handler_b - ); - } + /** + * @brief Default Constructor + */ + Game(); - void event_handler_a(MicroBitEvent) { - ubit.display.image.setPixelValue(2, 2, 1); - } + /** + * @brief Starts a new run of the game + * @note method blocks until game over. + */ + void run(); - void event_handler_b(MicroBitEvent) { - ubit.display.image.setPixelValue(2, 2, 0); - } + /* begin event handler methods */ + + /** + * Handles Button A Press event + */ + void press_button_a(MicroBitEvent); + + /** + * Handles Button B Press event + */ + void press_button_b(MicroBitEvent); + + /* end event handler methods */ + +private: + /** + * @brief Draws whatever's in the screen buffer to display + */ + void draw(); + + // internal screen-buffer, which we draw to first before pasting to display + MicroBitImage screen_buffer; }; +Game::Game() + : screen_buffer(5, 5) // our screen buffer mirrors the display dimensions +{} + +void Game::run() { + UBIT.display.scroll("NEW GAME!"); + // init screen display mode, to be sure it is in a known-state + // TODO: consider changing to greyscale to allow "mutli-coloured" blocks + UBIT.display.setDisplayMode(DISPLAY_MODE_BLACK_AND_WHITE); + // register event-handlers + UBIT.messageBus.listen( + MICROBIT_ID_BUTTON_A, + MICROBIT_BUTTON_EVT_CLICK, + this, + &Game::press_button_a + ); + UBIT.messageBus.listen( + MICROBIT_ID_BUTTON_B, + MICROBIT_BUTTON_EVT_CLICK, + this, + &Game::press_button_b + ); + while (true) { // TODO: change to use game-over condition + // sleep to conserve CPU cycles and allow other fibers a chance to run + UBIT.sleep(10); // 10ms sleep, or 100Hz tick rate + this->draw(); // render screen buffer + } + // TODO: add the rest of the game logic + UBIT.display.scroll("GAME OVER!"); + // TODO: display final score + // TODO: de-register event-handlers + UBIT.messageBus.ignore( + MICROBIT_ID_BUTTON_A, + MICROBIT_BUTTON_EVT_CLICK, + this, + &Game::press_button_a + ); + UBIT.messageBus.ignore( + MICROBIT_ID_BUTTON_B, + MICROBIT_BUTTON_EVT_CLICK, + this, + &Game::press_button_b + ); +} + +void Game::draw() { + // XXX: debug drawing, fill the screen buffer with black + this->screen_buffer.clear(); + // render our screen buffer + UBIT.display.image.paste(this->screen_buffer); +} + +void Game::press_button_a(MicroBitEvent e) { + // XXX: debug + this->screen_buffer.setPixelValue(0, 2, 255); +} + +void Game::press_button_b(MicroBitEvent e) { + // XXX: debug + this->screen_buffer.setPixelValue(4, 2, 255); +} + int main() { // Initialise the micro:bit runtime. - ubit.init(); + UBIT.init(); - EventThingy eventer; + UBIT.display.scroll("BLOCKS!"); - while (true) { - ubit.sleep(10); // 10ms sleep, or 100Hz tick rate + while (true) { // indefinitely start new games + Game game; + game.run(); } // TODO: potentially remove this call, if clarified that it is not required.