A space invaders game using the micro:bit. This example uses buttons, 'fibers' (like threads or tasks), the display, and the sleep functions. It is one of the more elaborate examples useful for someone wanting to build a game or understand the scheduler. This is a one-way translation of the microbit-samples repository on GitHub. Please don't try to push changes here, instead push them to the source repo at https://github.com/lancaster-university/microbit-samples

Dependencies:   microbit

Committer:
LancasterUniversity
Date:
Wed Jul 13 16:03:49 2016 +0100
Revision:
0:efccf53eee4c
Update to git: v2.0.0-rc4-5-g115d5a8

Who changed what in which revision?

UserRevisionLine numberNew contents of line
LancasterUniversity 0:efccf53eee4c 1 /*
LancasterUniversity 0:efccf53eee4c 2 The MIT License (MIT)
LancasterUniversity 0:efccf53eee4c 3
LancasterUniversity 0:efccf53eee4c 4 Copyright (c) 2016 Lancaster University.
LancasterUniversity 0:efccf53eee4c 5
LancasterUniversity 0:efccf53eee4c 6 Permission is hereby granted, free of charge, to any person obtaining a
LancasterUniversity 0:efccf53eee4c 7 copy of this software and associated documentation files (the "Software"),
LancasterUniversity 0:efccf53eee4c 8 to deal in the Software without restriction, including without limitation
LancasterUniversity 0:efccf53eee4c 9 the rights to use, copy, modify, merge, publish, distribute, sublicense,
LancasterUniversity 0:efccf53eee4c 10 and/or sell copies of the Software, and to permit persons to whom the
LancasterUniversity 0:efccf53eee4c 11 Software is furnished to do so, subject to the following conditions:
LancasterUniversity 0:efccf53eee4c 12
LancasterUniversity 0:efccf53eee4c 13 The above copyright notice and this permission notice shall be included in
LancasterUniversity 0:efccf53eee4c 14 all copies or substantial portions of the Software.
LancasterUniversity 0:efccf53eee4c 15
LancasterUniversity 0:efccf53eee4c 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
LancasterUniversity 0:efccf53eee4c 17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
LancasterUniversity 0:efccf53eee4c 18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
LancasterUniversity 0:efccf53eee4c 19 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LancasterUniversity 0:efccf53eee4c 20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
LancasterUniversity 0:efccf53eee4c 21 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
LancasterUniversity 0:efccf53eee4c 22 DEALINGS IN THE SOFTWARE.
LancasterUniversity 0:efccf53eee4c 23 */
LancasterUniversity 0:efccf53eee4c 24
LancasterUniversity 0:efccf53eee4c 25
LancasterUniversity 0:efccf53eee4c 26 //
LancasterUniversity 0:efccf53eee4c 27 //
LancasterUniversity 0:efccf53eee4c 28 // A simple game of Space Invaders for the BBC micro:bit, using the
LancasterUniversity 0:efccf53eee4c 29 // accelerometer and buttons to control the player's ship.
LancasterUniversity 0:efccf53eee4c 30 //
LancasterUniversity 0:efccf53eee4c 31 // As well as illustrating the use of sensors, the display and events,
LancasterUniversity 0:efccf53eee4c 32 // this demonstration also provides a highly elegant example of
LancasterUniversity 0:efccf53eee4c 33 // how fibers can be used to create safe and elegant programs... Note the
LancasterUniversity 0:efccf53eee4c 34 // use of event handlers when the player fires, and the indepenent fibers
LancasterUniversity 0:efccf53eee4c 35 // used to control the players ship, aliens, bullets and screen refresh...
LancasterUniversity 0:efccf53eee4c 36 //
LancasterUniversity 0:efccf53eee4c 37 //
LancasterUniversity 0:efccf53eee4c 38
LancasterUniversity 0:efccf53eee4c 39 #include "MicroBit.h"
LancasterUniversity 0:efccf53eee4c 40
LancasterUniversity 0:efccf53eee4c 41 #define GAME_ON 0
LancasterUniversity 0:efccf53eee4c 42 #define GAME_OVER 1
LancasterUniversity 0:efccf53eee4c 43
LancasterUniversity 0:efccf53eee4c 44 struct Point
LancasterUniversity 0:efccf53eee4c 45 {
LancasterUniversity 0:efccf53eee4c 46 int x;
LancasterUniversity 0:efccf53eee4c 47 int y;
LancasterUniversity 0:efccf53eee4c 48 };
LancasterUniversity 0:efccf53eee4c 49
LancasterUniversity 0:efccf53eee4c 50 MicroBit uBit;
LancasterUniversity 0:efccf53eee4c 51 MicroBitImage invaders(5,5);
LancasterUniversity 0:efccf53eee4c 52 int score;
LancasterUniversity 0:efccf53eee4c 53 int game_over;
LancasterUniversity 0:efccf53eee4c 54 int level;
LancasterUniversity 0:efccf53eee4c 55 int INVADER_SPEED = 750;
LancasterUniversity 0:efccf53eee4c 56 int PLAYER_SPEED = 150;
LancasterUniversity 0:efccf53eee4c 57 int BULLET_SPEED = 50;
LancasterUniversity 0:efccf53eee4c 58 Point player;
LancasterUniversity 0:efccf53eee4c 59 Point bullet;
LancasterUniversity 0:efccf53eee4c 60
LancasterUniversity 0:efccf53eee4c 61 /**
LancasterUniversity 0:efccf53eee4c 62 * Add a new row of space invaders to the game.
LancasterUniversity 0:efccf53eee4c 63 */
LancasterUniversity 0:efccf53eee4c 64 int
LancasterUniversity 0:efccf53eee4c 65 addRow()
LancasterUniversity 0:efccf53eee4c 66 {
LancasterUniversity 0:efccf53eee4c 67 // If we're adding a row of invaders, but we're out of space, it's game over!!
LancasterUniversity 0:efccf53eee4c 68 for (int x=0; x<5; x++)
LancasterUniversity 0:efccf53eee4c 69 if (invaders.getPixelValue(x,4))
LancasterUniversity 0:efccf53eee4c 70 return GAME_OVER;
LancasterUniversity 0:efccf53eee4c 71
LancasterUniversity 0:efccf53eee4c 72 // Otherwise, move down the invaders, and add a new role at the top.
LancasterUniversity 0:efccf53eee4c 73 invaders.shiftDown(1);
LancasterUniversity 0:efccf53eee4c 74
LancasterUniversity 0:efccf53eee4c 75 for (int x=1; x<4; x++)
LancasterUniversity 0:efccf53eee4c 76 invaders.setPixelValue(x,0,255);
LancasterUniversity 0:efccf53eee4c 77
LancasterUniversity 0:efccf53eee4c 78 return GAME_ON;
LancasterUniversity 0:efccf53eee4c 79 }
LancasterUniversity 0:efccf53eee4c 80
LancasterUniversity 0:efccf53eee4c 81 /*
LancasterUniversity 0:efccf53eee4c 82 * Display Game Over and show the player's score.
LancasterUniversity 0:efccf53eee4c 83 */
LancasterUniversity 0:efccf53eee4c 84 void
LancasterUniversity 0:efccf53eee4c 85 gameOver()
LancasterUniversity 0:efccf53eee4c 86 {
LancasterUniversity 0:efccf53eee4c 87 uBit.display.clear();
LancasterUniversity 0:efccf53eee4c 88
LancasterUniversity 0:efccf53eee4c 89 uBit.display.scroll("GAME OVER! SCORE:");
LancasterUniversity 0:efccf53eee4c 90 uBit.display.scroll(score);
LancasterUniversity 0:efccf53eee4c 91 }
LancasterUniversity 0:efccf53eee4c 92
LancasterUniversity 0:efccf53eee4c 93 /*
LancasterUniversity 0:efccf53eee4c 94 * Calculate the speed of an invaders movement, based on the game level
LancasterUniversity 0:efccf53eee4c 95 */
LancasterUniversity 0:efccf53eee4c 96 int
LancasterUniversity 0:efccf53eee4c 97 invaderSpeed()
LancasterUniversity 0:efccf53eee4c 98 {
LancasterUniversity 0:efccf53eee4c 99 return max(INVADER_SPEED - level*50, 50);
LancasterUniversity 0:efccf53eee4c 100 }
LancasterUniversity 0:efccf53eee4c 101
LancasterUniversity 0:efccf53eee4c 102 /*
LancasterUniversity 0:efccf53eee4c 103 * Determine if the are any space invaders in the given column
LancasterUniversity 0:efccf53eee4c 104 */
LancasterUniversity 0:efccf53eee4c 105 bool
LancasterUniversity 0:efccf53eee4c 106 invadersInColumn(int x)
LancasterUniversity 0:efccf53eee4c 107 {
LancasterUniversity 0:efccf53eee4c 108 for (int y = 0; y < 5; y++)
LancasterUniversity 0:efccf53eee4c 109 if (invaders.getPixelValue(x,y))
LancasterUniversity 0:efccf53eee4c 110 return true;
LancasterUniversity 0:efccf53eee4c 111
LancasterUniversity 0:efccf53eee4c 112 return false;
LancasterUniversity 0:efccf53eee4c 113 }
LancasterUniversity 0:efccf53eee4c 114
LancasterUniversity 0:efccf53eee4c 115 /*
LancasterUniversity 0:efccf53eee4c 116 * Determine the number of space invaders currently on screen
LancasterUniversity 0:efccf53eee4c 117 */
LancasterUniversity 0:efccf53eee4c 118 bool
LancasterUniversity 0:efccf53eee4c 119 invaderCount()
LancasterUniversity 0:efccf53eee4c 120 {
LancasterUniversity 0:efccf53eee4c 121 int count = 0;
LancasterUniversity 0:efccf53eee4c 122
LancasterUniversity 0:efccf53eee4c 123 for (int x=0; x<5; x++)
LancasterUniversity 0:efccf53eee4c 124 for (int y=0; y<5; y++)
LancasterUniversity 0:efccf53eee4c 125 if (invaders.getPixelValue(x,y))
LancasterUniversity 0:efccf53eee4c 126 count++;
LancasterUniversity 0:efccf53eee4c 127
LancasterUniversity 0:efccf53eee4c 128 return count;
LancasterUniversity 0:efccf53eee4c 129 }
LancasterUniversity 0:efccf53eee4c 130
LancasterUniversity 0:efccf53eee4c 131 /*
LancasterUniversity 0:efccf53eee4c 132 * Move space invaders on the screen.
LancasterUniversity 0:efccf53eee4c 133 */
LancasterUniversity 0:efccf53eee4c 134 void
LancasterUniversity 0:efccf53eee4c 135 invaderUpdate()
LancasterUniversity 0:efccf53eee4c 136 {
LancasterUniversity 0:efccf53eee4c 137 bool movingRight = true;
LancasterUniversity 0:efccf53eee4c 138
LancasterUniversity 0:efccf53eee4c 139 while(!game_over)
LancasterUniversity 0:efccf53eee4c 140 {
LancasterUniversity 0:efccf53eee4c 141 // Wait for next update;
LancasterUniversity 0:efccf53eee4c 142 uBit.sleep(invaderSpeed());
LancasterUniversity 0:efccf53eee4c 143
LancasterUniversity 0:efccf53eee4c 144 if (movingRight)
LancasterUniversity 0:efccf53eee4c 145 {
LancasterUniversity 0:efccf53eee4c 146 if(invadersInColumn(4))
LancasterUniversity 0:efccf53eee4c 147 {
LancasterUniversity 0:efccf53eee4c 148 movingRight = false;
LancasterUniversity 0:efccf53eee4c 149 if (addRow() == GAME_OVER)
LancasterUniversity 0:efccf53eee4c 150 {
LancasterUniversity 0:efccf53eee4c 151 game_over = true;
LancasterUniversity 0:efccf53eee4c 152 return;
LancasterUniversity 0:efccf53eee4c 153 }
LancasterUniversity 0:efccf53eee4c 154 }
LancasterUniversity 0:efccf53eee4c 155 else
LancasterUniversity 0:efccf53eee4c 156 {
LancasterUniversity 0:efccf53eee4c 157 invaders.shiftRight(1);
LancasterUniversity 0:efccf53eee4c 158 }
LancasterUniversity 0:efccf53eee4c 159 }
LancasterUniversity 0:efccf53eee4c 160 else
LancasterUniversity 0:efccf53eee4c 161 {
LancasterUniversity 0:efccf53eee4c 162 if(invadersInColumn(0))
LancasterUniversity 0:efccf53eee4c 163 {
LancasterUniversity 0:efccf53eee4c 164 movingRight = true;
LancasterUniversity 0:efccf53eee4c 165 if (addRow() == GAME_OVER)
LancasterUniversity 0:efccf53eee4c 166 {
LancasterUniversity 0:efccf53eee4c 167 game_over = true;
LancasterUniversity 0:efccf53eee4c 168 return;
LancasterUniversity 0:efccf53eee4c 169 }
LancasterUniversity 0:efccf53eee4c 170 }
LancasterUniversity 0:efccf53eee4c 171 else
LancasterUniversity 0:efccf53eee4c 172 {
LancasterUniversity 0:efccf53eee4c 173 invaders.shiftLeft(1);
LancasterUniversity 0:efccf53eee4c 174 }
LancasterUniversity 0:efccf53eee4c 175 }
LancasterUniversity 0:efccf53eee4c 176
LancasterUniversity 0:efccf53eee4c 177 if (invaderCount() == 0)
LancasterUniversity 0:efccf53eee4c 178 {
LancasterUniversity 0:efccf53eee4c 179 level++;
LancasterUniversity 0:efccf53eee4c 180 addRow();
LancasterUniversity 0:efccf53eee4c 181 }
LancasterUniversity 0:efccf53eee4c 182 }
LancasterUniversity 0:efccf53eee4c 183 }
LancasterUniversity 0:efccf53eee4c 184
LancasterUniversity 0:efccf53eee4c 185 /*
LancasterUniversity 0:efccf53eee4c 186 * Move the bullet up the screen
LancasterUniversity 0:efccf53eee4c 187 */
LancasterUniversity 0:efccf53eee4c 188 void
LancasterUniversity 0:efccf53eee4c 189 bulletUpdate()
LancasterUniversity 0:efccf53eee4c 190 {
LancasterUniversity 0:efccf53eee4c 191 while (!game_over)
LancasterUniversity 0:efccf53eee4c 192 {
LancasterUniversity 0:efccf53eee4c 193 uBit.sleep(BULLET_SPEED);
LancasterUniversity 0:efccf53eee4c 194 if (bullet.y != -1)
LancasterUniversity 0:efccf53eee4c 195 bullet.y--;
LancasterUniversity 0:efccf53eee4c 196
LancasterUniversity 0:efccf53eee4c 197 if (invaders.getPixelValue(bullet.x, bullet.y) > 0)
LancasterUniversity 0:efccf53eee4c 198 {
LancasterUniversity 0:efccf53eee4c 199 score++;
LancasterUniversity 0:efccf53eee4c 200 invaders.setPixelValue(bullet.x, bullet.y, 0);
LancasterUniversity 0:efccf53eee4c 201 bullet.x = -1;
LancasterUniversity 0:efccf53eee4c 202 bullet.y = -1;
LancasterUniversity 0:efccf53eee4c 203 }
LancasterUniversity 0:efccf53eee4c 204 }
LancasterUniversity 0:efccf53eee4c 205 }
LancasterUniversity 0:efccf53eee4c 206
LancasterUniversity 0:efccf53eee4c 207 /*
LancasterUniversity 0:efccf53eee4c 208 * Move the player across the screen.
LancasterUniversity 0:efccf53eee4c 209 */
LancasterUniversity 0:efccf53eee4c 210 void
LancasterUniversity 0:efccf53eee4c 211 playerUpdate()
LancasterUniversity 0:efccf53eee4c 212 {
LancasterUniversity 0:efccf53eee4c 213 while (!game_over)
LancasterUniversity 0:efccf53eee4c 214 {
LancasterUniversity 0:efccf53eee4c 215 uBit.sleep(PLAYER_SPEED);
LancasterUniversity 0:efccf53eee4c 216
LancasterUniversity 0:efccf53eee4c 217 if(uBit.accelerometer.getX() < -300 && player.x > 0)
LancasterUniversity 0:efccf53eee4c 218 player.x--;
LancasterUniversity 0:efccf53eee4c 219
LancasterUniversity 0:efccf53eee4c 220 if(uBit.accelerometer.getX() > 300 && player.x < 4)
LancasterUniversity 0:efccf53eee4c 221 player.x++;
LancasterUniversity 0:efccf53eee4c 222 }
LancasterUniversity 0:efccf53eee4c 223 }
LancasterUniversity 0:efccf53eee4c 224
LancasterUniversity 0:efccf53eee4c 225 /*
LancasterUniversity 0:efccf53eee4c 226 * Fire a new missile from the player
LancasterUniversity 0:efccf53eee4c 227 */
LancasterUniversity 0:efccf53eee4c 228 void
LancasterUniversity 0:efccf53eee4c 229 fire(MicroBitEvent)
LancasterUniversity 0:efccf53eee4c 230 {
LancasterUniversity 0:efccf53eee4c 231 if (bullet.y == -1)
LancasterUniversity 0:efccf53eee4c 232 {
LancasterUniversity 0:efccf53eee4c 233 bullet.y = 4;
LancasterUniversity 0:efccf53eee4c 234 bullet.x = player.x;
LancasterUniversity 0:efccf53eee4c 235 }
LancasterUniversity 0:efccf53eee4c 236 }
LancasterUniversity 0:efccf53eee4c 237
LancasterUniversity 0:efccf53eee4c 238 /*
LancasterUniversity 0:efccf53eee4c 239 * A simple game of space invaders
LancasterUniversity 0:efccf53eee4c 240 */
LancasterUniversity 0:efccf53eee4c 241 void
LancasterUniversity 0:efccf53eee4c 242 spaceInvaders()
LancasterUniversity 0:efccf53eee4c 243 {
LancasterUniversity 0:efccf53eee4c 244 // Reset all game state.
LancasterUniversity 0:efccf53eee4c 245 game_over = 0;
LancasterUniversity 0:efccf53eee4c 246 level = 0;
LancasterUniversity 0:efccf53eee4c 247 score = 0;
LancasterUniversity 0:efccf53eee4c 248 player.x = 2;
LancasterUniversity 0:efccf53eee4c 249 player.y = 4;
LancasterUniversity 0:efccf53eee4c 250
LancasterUniversity 0:efccf53eee4c 251 bullet.x = -1;
LancasterUniversity 0:efccf53eee4c 252 bullet.y = -1;
LancasterUniversity 0:efccf53eee4c 253
LancasterUniversity 0:efccf53eee4c 254 // Add a single row of invaders at the start.. cannon fodder!
LancasterUniversity 0:efccf53eee4c 255 invaders.clear();
LancasterUniversity 0:efccf53eee4c 256 addRow();
LancasterUniversity 0:efccf53eee4c 257
LancasterUniversity 0:efccf53eee4c 258 // Spawn independent fibers to handle the movement of each player
LancasterUniversity 0:efccf53eee4c 259 create_fiber(invaderUpdate);
LancasterUniversity 0:efccf53eee4c 260 create_fiber(bulletUpdate);
LancasterUniversity 0:efccf53eee4c 261 create_fiber(playerUpdate);
LancasterUniversity 0:efccf53eee4c 262
LancasterUniversity 0:efccf53eee4c 263 // Register event handlers for button presses (either button fires!)
LancasterUniversity 0:efccf53eee4c 264 uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_CLICK, fire);
LancasterUniversity 0:efccf53eee4c 265 uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_CLICK, fire);
LancasterUniversity 0:efccf53eee4c 266
LancasterUniversity 0:efccf53eee4c 267 // Now just keep the screen refreshed.
LancasterUniversity 0:efccf53eee4c 268 while (!game_over)
LancasterUniversity 0:efccf53eee4c 269 {
LancasterUniversity 0:efccf53eee4c 270 uBit.sleep(10);
LancasterUniversity 0:efccf53eee4c 271 uBit.display.image.paste(invaders);
LancasterUniversity 0:efccf53eee4c 272 uBit.display.image.setPixelValue(player.x, player.y, 255);
LancasterUniversity 0:efccf53eee4c 273 uBit.display.image.setPixelValue(bullet.x, bullet.y, 255);
LancasterUniversity 0:efccf53eee4c 274 }
LancasterUniversity 0:efccf53eee4c 275
LancasterUniversity 0:efccf53eee4c 276 // Display GAME OVER and score
LancasterUniversity 0:efccf53eee4c 277 gameOver();
LancasterUniversity 0:efccf53eee4c 278 }
LancasterUniversity 0:efccf53eee4c 279
LancasterUniversity 0:efccf53eee4c 280 int main()
LancasterUniversity 0:efccf53eee4c 281 {
LancasterUniversity 0:efccf53eee4c 282 // Initialise the micro:bit runtime.
LancasterUniversity 0:efccf53eee4c 283 uBit.init();
LancasterUniversity 0:efccf53eee4c 284
LancasterUniversity 0:efccf53eee4c 285 // Welcome message
LancasterUniversity 0:efccf53eee4c 286 uBit.display.scroll("INVADERS!");
LancasterUniversity 0:efccf53eee4c 287
LancasterUniversity 0:efccf53eee4c 288 // Keep playing forever
LancasterUniversity 0:efccf53eee4c 289 while(1)
LancasterUniversity 0:efccf53eee4c 290 spaceInvaders();
LancasterUniversity 0:efccf53eee4c 291 }
LancasterUniversity 0:efccf53eee4c 292