Components and supplies
Alphanumeric LCD, 16 x 2
Arduino UNO
Breadboard (generic)
Touch sensor
Jumper wires (generic)
Apps and platforms
Arduino IDE
Project description
Code
Arduino code
arduino
1// THE SCREWDRIVER 2// Running Man Game ............. 3 4#include <LiquidCrystal_I2C.h> 5LiquidCrystal_I2C lcd(0x20,20,4); 6 7#define PIN_sensor 2 8#define PIN_AUTOPLAY 1 9#define PIN_READWRITE 10 10#define PIN_CONTRAST 12 11 12#define SPRITE_RUN1 1 13#define SPRITE_RUN2 2 14#define SPRITE_JUMP 3 15#define SPRITE_JUMP_UPPER '.' // Use the '.' character for the head 16#define SPRITE_JUMP_LOWER 4 17#define SPRITE_TERRAIN_EMPTY ' ' // User the ' ' character 18#define SPRITE_TERRAIN_SOLID 5 19#define SPRITE_TERRAIN_SOLID_RIGHT 6 20#define SPRITE_TERRAIN_SOLID_LEFT 7 21 22#define HERO_HORIZONTAL_POSITION 1 // Horizontal position of hero on screen 23 24#define TERRAIN_WIDTH 16 25#define TERRAIN_EMPTY 0 26#define TERRAIN_LOWER_BLOCK 1 27#define TERRAIN_UPPER_BLOCK 2 28 29#define HERO_POSITION_OFF 0 // Hero is invisible 30#define HERO_POSITION_RUN_LOWER_1 1 // Hero is running on lower row (pose 1) 31#define HERO_POSITION_RUN_LOWER_2 2 // (pose 2) 32 33#define HERO_POSITION_JUMP_1 3 // Starting a jump 34#define HERO_POSITION_JUMP_2 4 // Half-way up 35#define HERO_POSITION_JUMP_3 5 // Jump is on upper row 36#define HERO_POSITION_JUMP_4 6 // Jump is on upper row 37#define HERO_POSITION_JUMP_5 7 // Jump is on upper row 38#define HERO_POSITION_JUMP_6 8 // Jump is on upper row 39#define HERO_POSITION_JUMP_7 9 // Half-way down 40#define HERO_POSITION_JUMP_8 10 // About to land 41 42#define HERO_POSITION_RUN_UPPER_1 11 // Hero is running on upper row (pose 1) 43#define HERO_POSITION_RUN_UPPER_2 12 // (pose 2) 44static char terrainUpper[TERRAIN_WIDTH + 1]; 45static char terrainLower[TERRAIN_WIDTH + 1]; 46static bool sensorPushed = false; 47 48void initializeGraphics() { 49 static 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 int i; 115 // Skip using character 0, this allows lcd.print() to be used to 116 // quickly draw multiple characters 117 for (i = 0; i < 7; ++i) { 118 lcd.createChar(i + 1, &graphics[i * 8]); 119 } 120 for (i = 0; i < TERRAIN_WIDTH; ++i) { 121 terrainUpper[i] = SPRITE_TERRAIN_EMPTY; 122 terrainLower[i] = SPRITE_TERRAIN_EMPTY; 123 } 124} 125 126// Slide the terrain to the left in half-character increments 127// 128void advanceTerrain(char* terrain, byte newTerrain) { 129 for (int i = 0; i < TERRAIN_WIDTH; ++i) { 130 char current = terrain[i]; 131 char next = (i == TERRAIN_WIDTH - 1) ? newTerrain : terrain[i + 1]; 132 switch (current) { 133 case SPRITE_TERRAIN_EMPTY: 134 terrain[i] = (next == SPRITE_TERRAIN_SOLID) ? SPRITE_TERRAIN_SOLID_RIGHT : SPRITE_TERRAIN_EMPTY; 135 break; 136 case SPRITE_TERRAIN_SOLID: 137 terrain[i] = (next == SPRITE_TERRAIN_EMPTY) ? SPRITE_TERRAIN_SOLID_LEFT : SPRITE_TERRAIN_SOLID; 138 break; 139 case SPRITE_TERRAIN_SOLID_RIGHT: 140 terrain[i] = SPRITE_TERRAIN_SOLID; 141 break; 142 case SPRITE_TERRAIN_SOLID_LEFT: 143 terrain[i] = SPRITE_TERRAIN_EMPTY; 144 break; 145 } 146 } 147} 148 149bool drawHero(byte position, char* terrainUpper, char* terrainLower, unsigned int score) { 150 bool collide = false; 151 char upperSave = terrainUpper[HERO_HORIZONTAL_POSITION]; 152 char lowerSave = terrainLower[HERO_HORIZONTAL_POSITION]; 153 byte upper, lower; 154 switch (position) { 155 case HERO_POSITION_OFF: 156 upper = lower = SPRITE_TERRAIN_EMPTY; 157 break; 158 case HERO_POSITION_RUN_LOWER_1: 159 upper = SPRITE_TERRAIN_EMPTY; 160 lower = SPRITE_RUN1; 161 break; 162 case HERO_POSITION_RUN_LOWER_2: 163 upper = SPRITE_TERRAIN_EMPTY; 164 lower = SPRITE_RUN2; 165 break; 166 case HERO_POSITION_JUMP_1: 167 case HERO_POSITION_JUMP_8: 168 upper = SPRITE_TERRAIN_EMPTY; 169 lower = SPRITE_JUMP; 170 break; 171 case HERO_POSITION_JUMP_2: 172 case HERO_POSITION_JUMP_7: 173 upper = SPRITE_JUMP_UPPER; 174 lower = SPRITE_JUMP_LOWER; 175 break; 176 case HERO_POSITION_JUMP_3: 177 case HERO_POSITION_JUMP_4: 178 case HERO_POSITION_JUMP_5: 179 case HERO_POSITION_JUMP_6: 180 upper = SPRITE_JUMP; 181 lower = SPRITE_TERRAIN_EMPTY; 182 break; 183 case HERO_POSITION_RUN_UPPER_1: 184 upper = SPRITE_RUN1; 185 lower = SPRITE_TERRAIN_EMPTY; 186 break; 187 case HERO_POSITION_RUN_UPPER_2: 188 upper = SPRITE_RUN2; 189 lower = SPRITE_TERRAIN_EMPTY; 190 break; 191 } 192 if (upper != ' ') { 193 terrainUpper[HERO_HORIZONTAL_POSITION] = upper; 194 collide = (upperSave == SPRITE_TERRAIN_EMPTY) ? false : true; 195 } 196 if (lower != ' ') { 197 terrainLower[HERO_HORIZONTAL_POSITION] = lower; 198 collide |= (lowerSave == SPRITE_TERRAIN_EMPTY) ? false : true; 199 } 200 201 byte digits = (score > 9999) ? 5 : (score > 999) ? 4 : (score > 99) ? 3 : (score > 9) ? 2 : 1; 202 203 // Draw the scene 204 terrainUpper[TERRAIN_WIDTH] = '\\0'; 205 terrainLower[TERRAIN_WIDTH] = '\\0'; 206 char temp = terrainUpper[16 - digits]; 207 terrainUpper[16 - digits] = '\\0'; 208 lcd.setCursor(0, 0); 209 lcd.print(terrainUpper); 210 terrainUpper[16 - digits] = temp; 211 lcd.setCursor(0, 1); 212 lcd.print(terrainLower); 213 214 lcd.setCursor(16 - digits, 0); 215 lcd.print(score); 216 217 terrainUpper[HERO_HORIZONTAL_POSITION] = upperSave; 218 terrainLower[HERO_HORIZONTAL_POSITION] = lowerSave; 219 return collide; 220} 221 222// Handle the sensor touch as an interrupt 223void sensorPush() { 224 sensorPushed = true; 225} 226 227void setup() { 228 pinMode(PIN_READWRITE, OUTPUT); 229 digitalWrite(PIN_READWRITE, LOW); 230 pinMode(PIN_CONTRAST, OUTPUT); 231 digitalWrite(PIN_CONTRAST, LOW); 232 pinMode(PIN_sensor, INPUT); 233 digitalWrite(PIN_sensor, HIGH); 234 pinMode(PIN_AUTOPLAY, OUTPUT); 235 digitalWrite(PIN_AUTOPLAY, HIGH); 236 237 // Digital pin 2 maps to interrupt 0 238 attachInterrupt(0/*PIN_sensor*/, sensorPush, FALLING); 239 240 initializeGraphics(); 241 242 lcd.init(); 243} 244 245void loop() { 246 static byte heroPos = HERO_POSITION_RUN_LOWER_1; 247 static byte newTerrainType = TERRAIN_EMPTY; 248 static byte newTerrainDuration = 1; 249 static bool playing = false; 250 static bool blink = false; 251 static unsigned int distance = 0; 252 253 if (!playing) { 254 drawHero((blink) ? HERO_POSITION_OFF : heroPos, terrainUpper, terrainLower, distance >> 3); 255 if (blink) { 256 lcd.setCursor(0, 0); 257 lcd.print("Touch to Play"); 258 } 259 delay(250); 260 blink = !blink; 261 if (sensorPushed) { 262 initializeGraphics(); 263 heroPos = HERO_POSITION_RUN_LOWER_1; 264 playing = true; 265 sensorPushed = false; 266 distance = 0; 267 } 268 return; 269 } 270 271 // Shift the terrain to the left 272 advanceTerrain(terrainLower, newTerrainType == TERRAIN_LOWER_BLOCK ? SPRITE_TERRAIN_SOLID : SPRITE_TERRAIN_EMPTY); 273 advanceTerrain(terrainUpper, newTerrainType == TERRAIN_UPPER_BLOCK ? SPRITE_TERRAIN_SOLID : SPRITE_TERRAIN_EMPTY); 274 275 // Make new terrain to enter on the right 276 if (--newTerrainDuration == 0) { 277 if (newTerrainType == TERRAIN_EMPTY) { 278 newTerrainType = (random(3) == 0) ? TERRAIN_UPPER_BLOCK : TERRAIN_LOWER_BLOCK; 279 newTerrainDuration = 2 + random(10); 280 } else { 281 newTerrainType = TERRAIN_EMPTY; 282 newTerrainDuration = 10 + random(10); 283 } 284 } 285 286 if (sensorPushed) { 287 if (heroPos <= HERO_POSITION_RUN_LOWER_2) heroPos = HERO_POSITION_JUMP_1; 288 sensorPushed = false; 289 } 290 291 if (drawHero(heroPos, terrainUpper, terrainLower, distance >> 3)) { 292 playing = false; // The hero collided with something. Too bad. 293 } else { 294 if (heroPos == HERO_POSITION_RUN_LOWER_2 || heroPos == HERO_POSITION_JUMP_8) { 295 heroPos = HERO_POSITION_RUN_LOWER_1; 296 } else if ((heroPos >= HERO_POSITION_JUMP_3 && heroPos <= HERO_POSITION_JUMP_5) && terrainLower[HERO_HORIZONTAL_POSITION] != SPRITE_TERRAIN_EMPTY) { 297 heroPos = HERO_POSITION_RUN_UPPER_1; 298 } else if (heroPos >= HERO_POSITION_RUN_UPPER_1 && terrainLower[HERO_HORIZONTAL_POSITION] == SPRITE_TERRAIN_EMPTY) { 299 heroPos = HERO_POSITION_JUMP_5; 300 } else if (heroPos == HERO_POSITION_RUN_UPPER_2) { 301 heroPos = HERO_POSITION_RUN_UPPER_1; 302 } else { 303 ++heroPos; 304 } 305 ++distance; 306 307 digitalWrite(PIN_AUTOPLAY, terrainLower[HERO_HORIZONTAL_POSITION + 2] == SPRITE_TERRAIN_EMPTY ? HIGH : LOW); 308 } 309 delay(85); 310} 311
Downloadable files
Please watch the video
Please watch the video
Please watch the video
Please watch the video
Comments
Only logged in users can leave comments
helloanimesh390
0 Followers
•0 Projects
Table of contents
Intro
6
0