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