Components and supplies
1
Single Turn Potentiometer- 10k ohms
1
Arduino UNO
1
Resistor 220 ohm
1
Alphanumeric LCD, 16 x 2
1
Switch Actuator, Head for spring return push-button
Tools and machines
1
10 Pc. Jumper Wire Kit, 5 cm Long
1
Prototyping Kit, Breadboard
Project description
Code
LCD_videogame[1].ino
arduino
1#include <LiquidCrystal.h> 2 3#define PIN_BUTTON 2 4 5#define SPRITE_RUN1 1 6#define SPRITE_RUN2 2 7#define SPRITE_JUMP 3 8#define SPRITE_JUMP_UPPER '.' // Use the '.' character for the head 9#define SPRITE_JUMP_LOWER 4 10#define SPRITE_TERRAIN_EMPTY ' ' // User the ' ' character 11#define SPRITE_TERRAIN_SOLID 5 12#define SPRITE_TERRAIN_SOLID_RIGHT 6 13#define SPRITE_TERRAIN_SOLID_LEFT 7 14 15#define HERO_HORIZONTAL_POSITION 1 // Horizontal position of hero on screen 16 17#define TERRAIN_WIDTH 16 18#define TERRAIN_EMPTY 0 19#define TERRAIN_LOWER_BLOCK 1 20#define TERRAIN_UPPER_BLOCK 2 21 22#define HERO_POSITION_OFF 0 // Hero is invisible 23#define HERO_POSITION_RUN_LOWER_1 1 // Hero is running on lower row (pose 1) 24#define HERO_POSITION_RUN_LOWER_2 2 // (pose 2) 25 26#define HERO_POSITION_JUMP_1 3 // Starting a jump 27#define HERO_POSITION_JUMP_2 4 // Half-way up 28#define HERO_POSITION_JUMP_3 5 // Jump is on upper row 29#define HERO_POSITION_JUMP_4 6 // Jump is on upper row 30#define HERO_POSITION_JUMP_5 7 // Jump is on upper row 31#define HERO_POSITION_JUMP_6 8 // Jump is on upper row 32#define HERO_POSITION_JUMP_7 9 // Half-way down 33#define HERO_POSITION_JUMP_8 10 // About to land 34 35#define HERO_POSITION_RUN_UPPER_1 11 // Hero is running on upper row (pose 1) 36#define HERO_POSITION_RUN_UPPER_2 12 // (pose 2) 37 38 //DB7 39 40LiquidCrystal lcd(7, 8, 9, 10, 11, 12);// Configura pines de salida para el LCD 41 42 43 44char terrainUpper[TERRAIN_WIDTH + 1]; 45char terrainLower[TERRAIN_WIDTH + 1]; 46volatile boolean buttonPushed = false; 47 48void initializeGraphics() { 49 byte graphics[] = { 50 // Run position 1 51 B01100, 52 B01100, 53 B00000, 54 B01110, 55 B11100, 56 B01100, 57 B11010, 58 B10011, 59 // Run position 2 60 B01100, 61 B01100, 62 B00000, 63 B01100, 64 B01100, 65 B01100, 66 B01100, 67 B01110, 68 // Jump 69 B01100, 70 B01100, 71 B00000, 72 B11110, 73 B01101, 74 B11111, 75 B10000, 76 B00000, 77 // Jump lower 78 B11110, 79 B01101, 80 B11111, 81 B10000, 82 B00000, 83 B00000, 84 B00000, 85 B00000, 86 // Ground 87 B11111, 88 B11111, 89 B11111, 90 B11111, 91 B11111, 92 B11111, 93 B11111, 94 B11111, 95 // Ground right 96 B00011, 97 B00011, 98 B00011, 99 B00011, 100 B00011, 101 B00011, 102 B00011, 103 B00011, 104 // Ground left 105 B11000, 106 B11000, 107 B11000, 108 B11000, 109 B11000, 110 B11000, 111 B11000, 112 B11000, 113 }; 114 115 int i; 116 117 // Skip using character 0, this allows lcd.print() to be used to 118 // quickly draw multiple characters 119 for (i = 0; i < 7; ++i) { 120 lcd.createChar(i + 1, &graphics[i * 8]); 121 } 122 123 for (i = 0; i < TERRAIN_WIDTH; ++i) { 124 terrainUpper[i] = SPRITE_TERRAIN_EMPTY; 125 terrainLower[i] = SPRITE_TERRAIN_EMPTY; 126 } 127} 128 129// Slide the terrain to the left in half-character increments 130void advanceTerrain(char* terrain, byte newTerrain) { 131 for (int i = 0; i < TERRAIN_WIDTH; ++i) { 132 char current = terrain[i]; 133 char next = (i == TERRAIN_WIDTH-1) ? newTerrain : terrain[i+1]; 134 135 switch (current) { 136 case SPRITE_TERRAIN_EMPTY: 137 terrain[i] = (next == SPRITE_TERRAIN_SOLID) ? SPRITE_TERRAIN_SOLID_RIGHT : SPRITE_TERRAIN_EMPTY; 138 break; 139 140 case SPRITE_TERRAIN_SOLID: 141 terrain[i] = (next == SPRITE_TERRAIN_EMPTY) ? SPRITE_TERRAIN_SOLID_LEFT : SPRITE_TERRAIN_SOLID; 142 break; 143 144 case SPRITE_TERRAIN_SOLID_RIGHT: 145 terrain[i] = SPRITE_TERRAIN_SOLID; 146 break; 147 148 case SPRITE_TERRAIN_SOLID_LEFT: 149 terrain[i] = SPRITE_TERRAIN_EMPTY; 150 break; 151 } 152 } 153} 154 155boolean drawHero(byte position, char* terrainUpper, char* terrainLower, unsigned int score) { 156 boolean collide = false; 157 char upperSave = terrainUpper[HERO_HORIZONTAL_POSITION]; 158 char lowerSave = terrainLower[HERO_HORIZONTAL_POSITION]; 159 byte upper, lower; 160 161 switch (position) { 162 case HERO_POSITION_OFF: 163 upper = lower = SPRITE_TERRAIN_EMPTY; 164 break; 165 166 case HERO_POSITION_RUN_LOWER_1: 167 upper = SPRITE_TERRAIN_EMPTY; 168 lower = SPRITE_RUN1; 169 break; 170 171 case HERO_POSITION_RUN_LOWER_2: 172 upper = SPRITE_TERRAIN_EMPTY; 173 lower = SPRITE_RUN2; 174 break; 175 176 case HERO_POSITION_JUMP_1: 177 178 case HERO_POSITION_JUMP_8: 179 upper = SPRITE_TERRAIN_EMPTY; 180 lower = SPRITE_JUMP; 181 break; 182 183 case HERO_POSITION_JUMP_2: 184 185 case HERO_POSITION_JUMP_7: 186 upper = SPRITE_JUMP_UPPER; 187 lower = SPRITE_JUMP_LOWER; 188 break; 189 190 case HERO_POSITION_JUMP_3: 191 192 case HERO_POSITION_JUMP_4: 193 194 case HERO_POSITION_JUMP_5: 195 196 case HERO_POSITION_JUMP_6: 197 upper = SPRITE_JUMP; 198 lower = SPRITE_TERRAIN_EMPTY; 199 break; 200 201 case HERO_POSITION_RUN_UPPER_1: 202 upper = SPRITE_RUN1; 203 lower = SPRITE_TERRAIN_EMPTY; 204 break; 205 206 case HERO_POSITION_RUN_UPPER_2: 207 upper = SPRITE_RUN2; 208 lower = SPRITE_TERRAIN_EMPTY; 209 break; 210 } 211 212 if (upper != ' ') { 213 terrainUpper[HERO_HORIZONTAL_POSITION] = upper; 214 collide = (upperSave == SPRITE_TERRAIN_EMPTY) ? false : true; 215 } 216 217 if (lower != ' ') { 218 terrainLower[HERO_HORIZONTAL_POSITION] = lower; 219 collide |= (lowerSave == SPRITE_TERRAIN_EMPTY) ? false : true; 220 } 221 222 byte digits = (score > 9999) ? 5 : (score > 999) ? 4 : (score > 99) ? 3 : (score > 9) ? 2 : 1; 223 224 // Draw the scene 225 terrainUpper[TERRAIN_WIDTH] = '\\0'; 226 terrainLower[TERRAIN_WIDTH] = '\\0'; 227 char temp = terrainUpper[16-digits]; 228 terrainUpper[16-digits] = '\\0'; 229 lcd.setCursor(0,0); 230 lcd.print(terrainUpper); 231 terrainUpper[16-digits] = temp; 232 lcd.setCursor(0,1); 233 lcd.print(terrainLower); 234 235 lcd.setCursor(16 - digits,0); 236 lcd.print(score); 237 238 terrainUpper[HERO_HORIZONTAL_POSITION] = upperSave; 239 terrainLower[HERO_HORIZONTAL_POSITION] = lowerSave; 240 241 return collide; 242} 243 244// Handle the button push as an interrupt 245void buttonPush() { 246 buttonPushed = true; 247} 248 249void setup() { 250 pinMode(PIN_BUTTON, INPUT_PULLUP); 251 252 // Digital pin 2 maps to interrupt 0 253 attachInterrupt(0, buttonPush, FALLING); 254 255 initializeGraphics(); 256 257 lcd.begin(16, 2); 258} 259 260void loop(){ 261 static byte heroPos = HERO_POSITION_RUN_LOWER_1; 262 static byte newTerrainType = TERRAIN_EMPTY; 263 static byte newTerrainDuration = 1; 264 static boolean playing = false; 265 static boolean blink = false; 266 static unsigned int distance = 0; 267 268 if (!playing) { 269 drawHero((blink) ? HERO_POSITION_OFF : heroPos, terrainUpper, terrainLower, distance >> 3); 270 271 if (blink) { 272 lcd.setCursor(0,0); 273 lcd.print("Press Start"); 274 } 275 276 delay(250); 277 blink = !blink; 278 279 if (buttonPushed) { 280 initializeGraphics(); 281 heroPos = HERO_POSITION_RUN_LOWER_1; 282 playing = true; 283 buttonPushed = false; 284 distance = 0; 285 } 286 287 return; 288 } 289 290 // Shift the terrain to the left 291 advanceTerrain(terrainLower, newTerrainType == TERRAIN_LOWER_BLOCK ? SPRITE_TERRAIN_SOLID : SPRITE_TERRAIN_EMPTY); 292 advanceTerrain(terrainUpper, newTerrainType == TERRAIN_UPPER_BLOCK ? SPRITE_TERRAIN_SOLID : SPRITE_TERRAIN_EMPTY); 293 294 // Make new terrain to enter on the right 295 if (--newTerrainDuration == 0) { 296 if (newTerrainType == TERRAIN_EMPTY) { 297 newTerrainType = (random(3) == 0) ? TERRAIN_UPPER_BLOCK : TERRAIN_LOWER_BLOCK; 298 newTerrainDuration = 2 + random(10); 299 } else { 300 newTerrainType = TERRAIN_EMPTY; 301 newTerrainDuration = 10 + random(10); 302 } 303 } 304 305 if (buttonPushed) { 306 if (heroPos <= HERO_POSITION_RUN_LOWER_2) 307 heroPos = HERO_POSITION_JUMP_1; 308 309 buttonPushed = false; 310 } 311 312 if (drawHero(heroPos, terrainUpper, terrainLower, distance >> 3)) { 313 playing = false; // The hero collided with something. Too bad. 314 } else { 315 if (heroPos == HERO_POSITION_RUN_LOWER_2 || heroPos == HERO_POSITION_JUMP_8) { 316 heroPos = HERO_POSITION_RUN_LOWER_1; 317 } else if ((heroPos >= HERO_POSITION_JUMP_3 && heroPos <= HERO_POSITION_JUMP_5) && terrainLower[HERO_HORIZONTAL_POSITION] != SPRITE_TERRAIN_EMPTY) { 318 heroPos = HERO_POSITION_RUN_UPPER_1; 319 } else if (heroPos >= HERO_POSITION_RUN_UPPER_1 && terrainLower[HERO_HORIZONTAL_POSITION] == SPRITE_TERRAIN_EMPTY) { 320 heroPos = HERO_POSITION_JUMP_5; 321 } else if (heroPos == HERO_POSITION_RUN_UPPER_2) { 322 heroPos = HERO_POSITION_RUN_UPPER_1; 323 } else { 324 ++heroPos; 325 } 326 327 ++distance; 328 } 329 330 delay(100); 331} 332
LCD_videogame[1].ino
arduino
1#include <LiquidCrystal.h> 2 3#define PIN_BUTTON 2 4 5#define 6 SPRITE_RUN1 1 7#define SPRITE_RUN2 2 8#define SPRITE_JUMP 3 9#define SPRITE_JUMP_UPPER 10 '.' // Use the '.' character for the head 11#define SPRITE_JUMP_LOWER 4 12#define 13 SPRITE_TERRAIN_EMPTY ' ' // User the ' ' character 14#define SPRITE_TERRAIN_SOLID 15 5 16#define SPRITE_TERRAIN_SOLID_RIGHT 6 17#define SPRITE_TERRAIN_SOLID_LEFT 7 18 19 20#define HERO_HORIZONTAL_POSITION 1 // Horizontal position of hero on screen 21 22 23#define TERRAIN_WIDTH 16 24#define TERRAIN_EMPTY 0 25#define TERRAIN_LOWER_BLOCK 26 1 27#define TERRAIN_UPPER_BLOCK 2 28 29#define HERO_POSITION_OFF 0 // 30 Hero is invisible 31#define HERO_POSITION_RUN_LOWER_1 1 // Hero is running on 32 lower row (pose 1) 33#define HERO_POSITION_RUN_LOWER_2 2 // (pose 34 2) 35 36#define HERO_POSITION_JUMP_1 3 // Starting a jump 37#define HERO_POSITION_JUMP_2 38 4 // Half-way up 39#define HERO_POSITION_JUMP_3 5 // Jump is on upper 40 row 41#define HERO_POSITION_JUMP_4 6 // Jump is on upper row 42#define HERO_POSITION_JUMP_5 43 7 // Jump is on upper row 44#define HERO_POSITION_JUMP_6 8 // Jump 45 is on upper row 46#define HERO_POSITION_JUMP_7 9 // Half-way down 47#define 48 HERO_POSITION_JUMP_8 10 // About to land 49 50#define HERO_POSITION_RUN_UPPER_1 51 11 // Hero is running on upper row (pose 1) 52#define HERO_POSITION_RUN_UPPER_2 53 12 // (pose 2) 54 55 //DB7 56 57LiquidCrystal 58 lcd(7, 8, 9, 10, 11, 12);// Configura pines de salida para el LCD 59 60 61 62 63char terrainUpper[TERRAIN_WIDTH + 1]; 64char terrainLower[TERRAIN_WIDTH + 1]; 65volatile 66 boolean buttonPushed = false; 67 68void initializeGraphics() { 69 byte graphics[] 70 = { 71 // Run position 1 72 B01100, 73 B01100, 74 B00000, 75 76 B01110, 77 B11100, 78 B01100, 79 B11010, 80 B10011, 81 82 // Run position 2 83 B01100, 84 B01100, 85 B00000, 86 87 B01100, 88 B01100, 89 B01100, 90 B01100, 91 B01110, 92 93 // Jump 94 B01100, 95 B01100, 96 B00000, 97 B11110, 98 99 B01101, 100 B11111, 101 B10000, 102 B00000, 103 // 104 Jump lower 105 B11110, 106 B01101, 107 B11111, 108 B10000, 109 110 B00000, 111 B00000, 112 B00000, 113 B00000, 114 // 115 Ground 116 B11111, 117 B11111, 118 B11111, 119 B11111, 120 121 B11111, 122 B11111, 123 B11111, 124 B11111, 125 // 126 Ground right 127 B00011, 128 B00011, 129 B00011, 130 B00011, 131 132 B00011, 133 B00011, 134 B00011, 135 B00011, 136 // 137 Ground left 138 B11000, 139 B11000, 140 B11000, 141 B11000, 142 143 B11000, 144 B11000, 145 B11000, 146 B11000, 147 }; 148 149 150 int i; 151 152 // Skip using character 0, this allows lcd.print() to 153 be used to 154 // quickly draw multiple characters 155 for (i = 0; i < 7; 156 ++i) { 157 lcd.createChar(i + 1, &graphics[i * 8]); 158 } 159 160 for 161 (i = 0; i < TERRAIN_WIDTH; ++i) { 162 terrainUpper[i] = SPRITE_TERRAIN_EMPTY; 163 164 terrainLower[i] = SPRITE_TERRAIN_EMPTY; 165 } 166} 167 168// Slide the 169 terrain to the left in half-character increments 170void advanceTerrain(char* terrain, 171 byte newTerrain) { 172 for (int i = 0; i < TERRAIN_WIDTH; ++i) { 173 char 174 current = terrain[i]; 175 char next = (i == TERRAIN_WIDTH-1) ? newTerrain 176 : terrain[i+1]; 177 178 switch (current) { 179 case SPRITE_TERRAIN_EMPTY: 180 181 terrain[i] = (next == SPRITE_TERRAIN_SOLID) ? SPRITE_TERRAIN_SOLID_RIGHT 182 : SPRITE_TERRAIN_EMPTY; 183 break; 184 185 case SPRITE_TERRAIN_SOLID: 186 187 terrain[i] = (next == SPRITE_TERRAIN_EMPTY) ? SPRITE_TERRAIN_SOLID_LEFT 188 : SPRITE_TERRAIN_SOLID; 189 break; 190 191 case SPRITE_TERRAIN_SOLID_RIGHT: 192 193 terrain[i] = SPRITE_TERRAIN_SOLID; 194 break; 195 196 197 case SPRITE_TERRAIN_SOLID_LEFT: 198 terrain[i] = SPRITE_TERRAIN_EMPTY; 199 200 break; 201 } 202 } 203} 204 205boolean drawHero(byte position, 206 char* terrainUpper, char* terrainLower, unsigned int score) { 207 boolean collide 208 = false; 209 char upperSave = terrainUpper[HERO_HORIZONTAL_POSITION]; 210 char 211 lowerSave = terrainLower[HERO_HORIZONTAL_POSITION]; 212 byte upper, lower; 213 214 215 switch (position) { 216 case HERO_POSITION_OFF: 217 upper 218 = lower = SPRITE_TERRAIN_EMPTY; 219 break; 220 221 case HERO_POSITION_RUN_LOWER_1: 222 223 upper = SPRITE_TERRAIN_EMPTY; 224 lower = SPRITE_RUN1; 225 226 break; 227 228 case HERO_POSITION_RUN_LOWER_2: 229 upper 230 = SPRITE_TERRAIN_EMPTY; 231 lower = SPRITE_RUN2; 232 break; 233 234 235 case HERO_POSITION_JUMP_1: 236 237 case HERO_POSITION_JUMP_8: 238 239 upper = SPRITE_TERRAIN_EMPTY; 240 lower = SPRITE_JUMP; 241 242 break; 243 244 case HERO_POSITION_JUMP_2: 245 246 case HERO_POSITION_JUMP_7: 247 248 upper = SPRITE_JUMP_UPPER; 249 lower = SPRITE_JUMP_LOWER; 250 251 break; 252 253 case HERO_POSITION_JUMP_3: 254 255 case HERO_POSITION_JUMP_4: 256 257 258 case HERO_POSITION_JUMP_5: 259 260 case HERO_POSITION_JUMP_6: 261 262 upper = SPRITE_JUMP; 263 lower = SPRITE_TERRAIN_EMPTY; 264 265 break; 266 267 case HERO_POSITION_RUN_UPPER_1: 268 upper 269 = SPRITE_RUN1; 270 lower = SPRITE_TERRAIN_EMPTY; 271 break; 272 273 274 case HERO_POSITION_RUN_UPPER_2: 275 upper = SPRITE_RUN2; 276 277 lower = SPRITE_TERRAIN_EMPTY; 278 break; 279 } 280 281 if 282 (upper != ' ') { 283 terrainUpper[HERO_HORIZONTAL_POSITION] = upper; 284 285 collide = (upperSave == SPRITE_TERRAIN_EMPTY) ? false : true; 286 } 287 288 289 if (lower != ' ') { 290 terrainLower[HERO_HORIZONTAL_POSITION] = 291 lower; 292 collide |= (lowerSave == SPRITE_TERRAIN_EMPTY) ? false : true; 293 294 } 295 296 byte digits = (score > 9999) ? 5 : (score > 999) ? 4 : (score 297 > 99) ? 3 : (score > 9) ? 2 : 1; 298 299 // Draw the scene 300 terrainUpper[TERRAIN_WIDTH] 301 = '\\0'; 302 terrainLower[TERRAIN_WIDTH] = '\\0'; 303 char temp = terrainUpper[16-digits]; 304 305 terrainUpper[16-digits] = '\\0'; 306 lcd.setCursor(0,0); 307 lcd.print(terrainUpper); 308 309 terrainUpper[16-digits] = temp; 310 lcd.setCursor(0,1); 311 lcd.print(terrainLower); 312 313 314 lcd.setCursor(16 - digits,0); 315 lcd.print(score); 316 317 terrainUpper[HERO_HORIZONTAL_POSITION] 318 = upperSave; 319 terrainLower[HERO_HORIZONTAL_POSITION] = lowerSave; 320 321 322 return collide; 323} 324 325// Handle the button push as an interrupt 326void 327 buttonPush() { 328 buttonPushed = true; 329} 330 331void setup() { 332 pinMode(PIN_BUTTON, 333 INPUT_PULLUP); 334 335 // Digital pin 2 maps to interrupt 0 336 attachInterrupt(0, 337 buttonPush, FALLING); 338 339 initializeGraphics(); 340 341 lcd.begin(16, 342 2); 343} 344 345void loop(){ 346 static byte heroPos = HERO_POSITION_RUN_LOWER_1; 347 348 static byte newTerrainType = TERRAIN_EMPTY; 349 static byte newTerrainDuration 350 = 1; 351 static boolean playing = false; 352 static boolean blink = false; 353 354 static unsigned int distance = 0; 355 356 if (!playing) { 357 drawHero((blink) 358 ? HERO_POSITION_OFF : heroPos, terrainUpper, terrainLower, distance >> 3); 359 360 361 if (blink) { 362 lcd.setCursor(0,0); 363 lcd.print("Press 364 Start"); 365 } 366 367 delay(250); 368 blink = !blink; 369 370 371 if (buttonPushed) { 372 initializeGraphics(); 373 heroPos 374 = HERO_POSITION_RUN_LOWER_1; 375 playing = true; 376 buttonPushed 377 = false; 378 distance = 0; 379 } 380 381 return; 382 } 383 384 385 // Shift the terrain to the left 386 advanceTerrain(terrainLower, newTerrainType 387 == TERRAIN_LOWER_BLOCK ? SPRITE_TERRAIN_SOLID : SPRITE_TERRAIN_EMPTY); 388 advanceTerrain(terrainUpper, 389 newTerrainType == TERRAIN_UPPER_BLOCK ? SPRITE_TERRAIN_SOLID : SPRITE_TERRAIN_EMPTY); 390 391 392 // Make new terrain to enter on the right 393 if (--newTerrainDuration 394 == 0) { 395 if (newTerrainType == TERRAIN_EMPTY) { 396 newTerrainType 397 = (random(3) == 0) ? TERRAIN_UPPER_BLOCK : TERRAIN_LOWER_BLOCK; 398 newTerrainDuration 399 = 2 + random(10); 400 } else { 401 newTerrainType = TERRAIN_EMPTY; 402 403 newTerrainDuration = 10 + random(10); 404 } 405 } 406 407 408 if (buttonPushed) { 409 if (heroPos <= HERO_POSITION_RUN_LOWER_2) 410 411 heroPos = HERO_POSITION_JUMP_1; 412 413 buttonPushed = false; 414 415 } 416 417 if (drawHero(heroPos, terrainUpper, terrainLower, distance >> 418 3)) { 419 playing = false; // The hero collided with something. Too bad. 420 421 } else { 422 if (heroPos == HERO_POSITION_RUN_LOWER_2 || heroPos == HERO_POSITION_JUMP_8) 423 { 424 heroPos = HERO_POSITION_RUN_LOWER_1; 425 } else if ((heroPos 426 >= HERO_POSITION_JUMP_3 && heroPos <= HERO_POSITION_JUMP_5) && terrainLower[HERO_HORIZONTAL_POSITION] 427 != SPRITE_TERRAIN_EMPTY) { 428 heroPos = HERO_POSITION_RUN_UPPER_1; 429 430 } else if (heroPos >= HERO_POSITION_RUN_UPPER_1 && terrainLower[HERO_HORIZONTAL_POSITION] 431 == SPRITE_TERRAIN_EMPTY) { 432 heroPos = HERO_POSITION_JUMP_5; 433 } 434 else if (heroPos == HERO_POSITION_RUN_UPPER_2) { 435 heroPos = HERO_POSITION_RUN_UPPER_1; 436 437 } else { 438 ++heroPos; 439 } 440 441 ++distance; 442 443 } 444 445 delay(100); 446} 447
Downloadable files
Esquematico
Esquematico

Comments
Only logged in users can leave comments