micro:drop - A simple game for the BBC micro:bit Fruits falling from the sky. Use buttons A & B to control the player and catch them all. Drop speed increases every 10 catches. How much can you get? After game over press AB to restart.
main.cpp
00001 /* 00002 MIT License 00003 00004 Copyright (c) 2018 Alexander Dölz 00005 00006 Permission is hereby granted, free of charge, to any person obtaining a copy 00007 of this software and associated documentation files (the "Software"), to deal 00008 in the Software without restriction, including without limitation the rights 00009 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 00010 copies of the Software, and to permit persons to whom the Software is 00011 furnished to do so, subject to the following conditions: 00012 00013 The above copyright notice and this permission notice shall be included in all 00014 copies or substantial portions of the Software. 00015 00016 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00017 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00018 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 00019 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00020 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00021 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00022 SOFTWARE. 00023 */ 00024 00025 /* 00026 micro:drop - A simple game for the BBC micro:bit 00027 00028 Fruits falling from the sky. Use buttons A & B to control the player 00029 and catch them all. 00030 00031 Drop speed increases every 10 catches. How much can you get? 00032 00033 After game over press AB to restart. 00034 */ 00035 #include "MicroBit.h" 00036 00037 struct Sprite { 00038 int x; 00039 int y; 00040 }; 00041 00042 const MicroBitImage imageCross("255,0,0,0,255\n0,255,0,255,0\n0,0,255,0,0\n0,255,0,255,0\n255,0,0,0,255\n"); 00043 const MicroBitImage imageFlash("255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n255,255,255,255,255\n"); 00044 00045 MicroBit uBit; 00046 Sprite player; 00047 Sprite fruit; 00048 00049 int game_over; 00050 int paused; 00051 int life; 00052 int score; 00053 int level; 00054 int game_speed; 00055 int high_score; 00056 int new_high_score; 00057 00058 /* Move player sprite to the left */ 00059 void onButtonA(MicroBitEvent e) 00060 { 00061 if (player.x > 0 && !paused && !game_over) { 00062 uBit.display.image.setPixelValue(player.x, player.y, 0); 00063 player.x--; 00064 uBit.display.image.setPixelValue(player.x, player.y, 255); 00065 } 00066 } 00067 00068 /* Move player sprite to the right */ 00069 void onButtonB(MicroBitEvent e) 00070 { 00071 if (player.x < 4 && !paused && !game_over) { 00072 uBit.display.image.setPixelValue(player.x, player.y, 0); 00073 player.x++; 00074 uBit.display.image.setPixelValue(player.x, player.y, 255); 00075 } 00076 } 00077 00078 /* Move fruit down and check for missed fruits */ 00079 void dropFruit() 00080 { 00081 while(!game_over) { 00082 if(!paused) { 00083 uBit.display.image.setPixelValue(fruit.x, fruit.y, 0); 00084 fruit.y++; 00085 // When the fruit is moved below the screen, it's a miss 00086 if (fruit.y > 4) { 00087 // Create a new fruit 00088 fruit.x=uBit.random(5); 00089 fruit.y=0; 00090 00091 // Show a cross to indicate the miss 00092 uBit.display.print(imageCross); 00093 uBit.sleep(25); 00094 uBit.display.clear(); 00095 00096 // Reduce life 00097 life--; 00098 00099 // No more lifes means game over 00100 if (life == 0) game_over = true; 00101 } 00102 uBit.display.image.setPixelValue(fruit.x, fruit.y, 255); 00103 } 00104 // Wait some time to give the human a chance 00105 uBit.sleep(game_speed); 00106 } 00107 } 00108 00109 /* Update player sprite and check for catched fruits*/ 00110 void updatePlayer() 00111 { 00112 while(!game_over) { 00113 uBit.display.image.setPixelValue(player.x, player.y, 255); 00114 // Check if the player catched the fruit 00115 if (player.x==fruit.x && player.y==fruit.y) { 00116 // Create a new fruit above the screen; dropFruit will do the rest 00117 fruit.x=uBit.random(5); 00118 fruit.y=-1; 00119 00120 // Flash all LEDs to indicate the catch 00121 uBit.display.print(imageFlash); 00122 uBit.sleep(25); 00123 uBit.display.clear(); 00124 00125 // Score a point 00126 score++; 00127 00128 // Level and speed will be incressed every 10 points 00129 if (score % 10 == 0) { 00130 // Pause the game during the "Next Level" message 00131 paused = true; 00132 level++; 00133 if (game_speed > 50) game_speed -= 50; 00134 uBit.display.clear(); 00135 uBit.display.scroll("LEVEL:"); 00136 uBit.display.scroll(level); 00137 // Bring Play back to the initial position 00138 uBit.display.image.setPixelValue(player.x, player.y, 0); 00139 player.x = 2; 00140 uBit.display.image.setPixelValue(player.x, player.y, 255); 00141 // Resume the game 00142 paused = false; 00143 } 00144 } 00145 // Give the CPU a rest 00146 uBit.sleep(25); 00147 } 00148 } 00149 /* Game over message */ 00150 void gameOver() 00151 { 00152 // Concatenate everthiny to ensure it will be in the right order at async 00153 // output 00154 const int cScore = score; 00155 ManagedString msGameOver = ManagedString("GAME OVER! SCORE: ") + ManagedString(cScore); 00156 if (new_high_score) msGameOver = msGameOver + ManagedString(" NEW HIGH SCORE!"); 00157 00158 uBit.display.scrollAsync(msGameOver); 00159 } 00160 00161 /* The Game */ 00162 void dropGame() 00163 { 00164 // Show current high score 00165 if (high_score > 0) { 00166 uBit.display.scroll("HIGH SCORE:"); 00167 uBit.display.scroll(high_score); 00168 } 00169 uBit.display.scroll("LEVEL: 1"); 00170 00171 // Initialize player sprite 00172 player.x=2; 00173 player.y=4; 00174 uBit.display.image.setPixelValue(player.x, player.y, 255); 00175 00176 // Initialize fruit sprite above the screen; dropFruit will do the rest 00177 fruit.x=uBit.random(5); 00178 fruit.y=-1; 00179 00180 // Reset game state 00181 paused = false; 00182 game_speed = 400; 00183 level = 1; 00184 score = 0; 00185 life = 3; 00186 new_high_score = false; 00187 game_over = false; 00188 00189 //Create background tasks for player and fruit update 00190 create_fiber(updatePlayer); 00191 create_fiber(dropFruit); 00192 00193 // Game logik is in fibers updatePlayer and dropFruit 00194 // So, while playing do nothing 00195 while(!game_over) 00196 uBit.sleep(200); 00197 00198 // Check for new high score 00199 if (score > high_score) { 00200 high_score = score; 00201 // Maker it persistent 00202 uBit.storage.put("high_score", (uint8_t *)&high_score, sizeof(int)); 00203 new_high_score = true; 00204 } 00205 00206 // Show "Game Over" screen and score until A&B ist pressed together 00207 uBit.display.clear(); 00208 00209 while(!uBit.buttonAB.isPressed()) { 00210 gameOver(); 00211 uBit.sleep(200); 00212 } 00213 uBit.display.stopAnimation(); 00214 } 00215 00216 int main(void) 00217 { 00218 // Initialize the micro:bit runtime 00219 uBit.init(); 00220 00221 // Game titel 00222 uBit.display.scroll("MICRO:DROP"); 00223 00224 // Get current high score from storage 00225 KeyValuePair* stroredHighScore = uBit.storage.get("high_score"); 00226 if(stroredHighScore == NULL) { 00227 high_score = 0; // Seems to be the first boot; there is no high score 00228 } else { 00229 // Copy high score from key value pair into int var 00230 memcpy(&high_score, stroredHighScore->value, sizeof(int)); 00231 delete stroredHighScore; 00232 } 00233 00234 //Disable buttons & background tasks at startup 00235 game_over = true; 00236 00237 //Register functions to buttons A & B 00238 uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_BUTTON_EVT_DOWN, onButtonA); 00239 uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_BUTTON_EVT_DOWN, onButtonB); 00240 00241 // Play forever ;-) 00242 while(1) { 00243 dropGame(); 00244 } 00245 }
Generated on Tue Jul 12 2022 20:10:14 by 1.7.2