Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* TITULO: Juego “Runner Scape” con display LCD 1602 y comunicación I2C.
- AUTOR:
- MARIANO DEL CAMPO GARCÍA (@2016) --> INGENIERO TÉCNICO INDUSTRIAL ESPECIALIDAD ELECTRÓNICA
- - FACEBOOK: https://www.facebook.com/mariano.delcampogarcia
- - TWITTER: https://twitter.com/MarianoCampoGa
- - CORREO: marianodc83@gmail.com
- DESCRIPCIÓN DEL PROGRAMA
- En este programa vamos a a controlar un personaje mediante un pulsador, para evitar que se
- choque con los obstáculos que le van alcanzando a medida que va corriendo. El personaje salta
- el obstáculo cuando presionamos el pulsador. El juego termina cuando se choca el personaje y
- para reestablecer el juego tenemos que volver a presionar el pulsador. El juego se visualiza
- a través de un LCD 1602 conectado a Arduino mediante comunicación I2C.
- ESQUEMA DE CONEXION
- +-----+
- +----[PWR]-------------------| USB |--+
- | +-----+ |
- | GND/RST2 [ ][ ] |
- | MOSI2/SCK2 [ ][ ] A5/SCL[ ] | SCL del módulo I2C conectado al LCD 1602
- | 5V/MISO2 [ ][ ] A4/SDA[ ] | SDA del módulo I2C conectado al LCD 1602
- | AREF[ ] |
- | GND[ ] |
- | [ ]N/C SCK/13[ ] |
- | [ ]IOREF MISO/12[ ] |
- | [ ]RST MOSI/11[ ]~|
- | [ ]3V3 +---+ 10[ ]~|
- | [ ]5v -| A |- 9[ ]~|
- | [ ]GND -| R |- 8[ ] |
- | [ ]GND -| D |- |
- | [ ]Vin -| U |- 7[ ] |
- | -| I |- 6[ ]~|
- | [ ]A0 -| N |- 5[ ]~|
- | [ ]A1 -| O |- 4[ ] |
- | [ ]A2 +---+ INT1/3[ ]~|
- | [ ]A3 INT0/2[ ] | PA
- | [ ]A4/SDA RST SCK MISO TX>1[ ] |
- | [ ]A5/SCL [ ] [ ] [ ] RX<0[ ] |
- | [ ] [ ] [ ] |
- | UNO_R3 GND MOSI 5V ____________/
- \_______________________/
- NOTAS:
- - La alimentación y la masa del módulo LCM 1602 I2C V1 van directamente conectadas a VCC (+5V) y GND
- respectivamente.
- - Los pulsadores suelen tener dos pines, que vamos a denominar PA y PB (si es de 4 sólo usamos 2 de ellos)
- - Conexión PULL-DOWN del pulsador.
- - PB conectado a VCC.
- - PA conectado a GND a través de una R=10K ohms.
- */
- // Importar librerías
- #include <Wire.h> // Librería comunicación I2C
- #include <LiquidCrystal_I2C.h> // Librería LCD I2C
- #define PIN_BUTTON 2 // Pin digital 2 para el botón del juego
- #define SPRITE_RUN1 1
- #define SPRITE_RUN2 2
- #define SPRITE_JUMP 3
- #define SPRITE_JUMP_UPPER '.' // Usa el carácter '.' para la cabeza
- #define SPRITE_JUMP_LOWER 4
- #define SPRITE_TERRAIN_EMPTY ' ' // Usa el carácter ' ' para los espacios vacíos
- #define SPRITE_TERRAIN_SOLID 5
- #define SPRITE_TERRAIN_SOLID_RIGHT 6
- #define SPRITE_TERRAIN_SOLID_LEFT 7
- #define HERO_HORIZONTAL_POSITION 1 // Posición horizontal del personaje en la pantalla
- #define TERRAIN_WIDTH 16
- #define TERRAIN_EMPTY 0
- #define TERRAIN_LOWER_BLOCK 1
- #define TERRAIN_UPPER_BLOCK 2
- #define HERO_POSITION_OFF 0 // El personaje es invisible
- #define HERO_POSITION_RUN_LOWER_1 1 // Personaje corriendo en la fila inferior (posición 1)
- #define HERO_POSITION_RUN_LOWER_2 2 // Personaje corriendo en la fila inferior (posición 2)
- #define HERO_POSITION_JUMP_1 3 // Comienzo del salto
- #define HERO_POSITION_JUMP_2 4 // Salto en la mitad del trayecto hacia arriba
- #define HERO_POSITION_JUMP_3 5 // Salto en la fila superior
- #define HERO_POSITION_JUMP_4 6 // Salto en la fila superior
- #define HERO_POSITION_JUMP_5 7 // Salto en la fila superior
- #define HERO_POSITION_JUMP_6 8 // Salto en la fila superior
- #define HERO_POSITION_JUMP_7 9 // Salto en la mitad del trayecto hacia abajo
- #define HERO_POSITION_JUMP_8 10 // A punto de aterrizar
- #define HERO_POSITION_RUN_UPPER_1 11 // Personaje corriendo en la fila superior (posición 1)
- #define HERO_POSITION_RUN_UPPER_2 12 // Personaje corriendo en la fila superior (posición 2)
- // Declaración del objeto
- // Terminales de conexión del LCD
- // addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
- LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
- static char terrainUpper[TERRAIN_WIDTH + 1];
- static char terrainLower[TERRAIN_WIDTH + 1];
- static bool buttonPushed = false;
- void initializeGraphics()
- {
- static byte graphics[] =
- {
- // Corredor en la position 1
- B01100,
- B01100,
- B00000,
- B01110,
- B11100,
- B01100,
- B11010,
- B10011,
- // Corredor en la position 2
- B01100,
- B01100,
- B00000,
- B01100,
- B01100,
- B01100,
- B01100,
- B01110,
- // Salto
- B01100,
- B01100,
- B00000,
- B11110,
- B01101,
- B11111,
- B10000,
- B00000,
- // Salto bajo
- B11110,
- B01101,
- B11111,
- B10000,
- B00000,
- B00000,
- B00000,
- B00000,
- // Suelo
- B11111,
- B11111,
- B11111,
- B11111,
- B11111,
- B11111,
- B11111,
- B11111,
- // Suelo derecho
- B00011,
- B00011,
- B00011,
- B00011,
- B00011,
- B00011,
- B00011,
- B00011,
- // Suelo izquierdo
- B11000,
- B11000,
- B11000,
- B11000,
- B11000,
- B11000,
- B11000,
- B11000,
- };
- int i;
- for (i = 0; i < 7; ++i)
- {
- lcd.createChar(i + 1, &graphics[i * 8]);
- }
- for (i = 0; i < TERRAIN_WIDTH; ++i)
- {
- terrainUpper[i] = SPRITE_TERRAIN_EMPTY;
- terrainLower[i] = SPRITE_TERRAIN_EMPTY;
- }
- }
- // Función que desliza el terreno hacia la izquierda en incrementos de medio caracter
- void advanceTerrain(char* terrain, byte newTerrain)
- {
- for (int i = 0; i < TERRAIN_WIDTH; ++i)
- {
- char current = terrain[i];
- char next = (i == TERRAIN_WIDTH-1) ? newTerrain : terrain[i+1];
- switch (current)
- {
- case SPRITE_TERRAIN_EMPTY:
- terrain[i] = (next == SPRITE_TERRAIN_SOLID) ? SPRITE_TERRAIN_SOLID_RIGHT : SPRITE_TERRAIN_EMPTY;
- break;
- case SPRITE_TERRAIN_SOLID:
- terrain[i] = (next == SPRITE_TERRAIN_EMPTY) ? SPRITE_TERRAIN_SOLID_LEFT : SPRITE_TERRAIN_SOLID;
- break;
- case SPRITE_TERRAIN_SOLID_RIGHT:
- terrain[i] = SPRITE_TERRAIN_SOLID;
- break;
- case SPRITE_TERRAIN_SOLID_LEFT:
- terrain[i] = SPRITE_TERRAIN_EMPTY;
- break;
- }
- }
- }
- bool drawHero(byte position, char* terrainUpper, char* terrainLower, unsigned int score)
- {
- bool collide = false;
- char upperSave = terrainUpper[HERO_HORIZONTAL_POSITION];
- char lowerSave = terrainLower[HERO_HORIZONTAL_POSITION];
- byte upper, lower;
- switch (position)
- {
- case HERO_POSITION_OFF:
- upper = lower = SPRITE_TERRAIN_EMPTY;
- break;
- case HERO_POSITION_RUN_LOWER_1:
- upper = SPRITE_TERRAIN_EMPTY;
- lower = SPRITE_RUN1;
- break;
- case HERO_POSITION_RUN_LOWER_2:
- upper = SPRITE_TERRAIN_EMPTY;
- lower = SPRITE_RUN2;
- break;
- case HERO_POSITION_JUMP_1:
- case HERO_POSITION_JUMP_8:
- upper = SPRITE_TERRAIN_EMPTY;
- lower = SPRITE_JUMP;
- break;
- case HERO_POSITION_JUMP_2:
- case HERO_POSITION_JUMP_7:
- upper = SPRITE_JUMP_UPPER;
- lower = SPRITE_JUMP_LOWER;
- break;
- case HERO_POSITION_JUMP_3:
- case HERO_POSITION_JUMP_4:
- case HERO_POSITION_JUMP_5:
- case HERO_POSITION_JUMP_6:
- upper = SPRITE_JUMP;
- lower = SPRITE_TERRAIN_EMPTY;
- break;
- case HERO_POSITION_RUN_UPPER_1:
- upper = SPRITE_RUN1;
- lower = SPRITE_TERRAIN_EMPTY;
- break;
- case HERO_POSITION_RUN_UPPER_2:
- upper = SPRITE_RUN2;
- lower = SPRITE_TERRAIN_EMPTY;
- break;
- }
- if (upper != ' ')
- {
- terrainUpper[HERO_HORIZONTAL_POSITION] = upper;
- collide = (upperSave == SPRITE_TERRAIN_EMPTY) ? false : true;
- }
- if (lower != ' ')
- {
- terrainLower[HERO_HORIZONTAL_POSITION] = lower;
- collide |= (lowerSave == SPRITE_TERRAIN_EMPTY) ? false : true;
- }
- byte digits = (score > 9999) ? 5 : (score > 999) ? 4 : (score > 99) ? 3 : (score > 9) ? 2 : 1;
- // Dibuja la escena
- terrainUpper[TERRAIN_WIDTH] = '\0';
- terrainLower[TERRAIN_WIDTH] = '\0';
- char temp = terrainUpper[16-digits];
- terrainUpper[16-digits] = '\0';
- lcd.setCursor(0,0);
- lcd.print(terrainUpper);
- terrainUpper[16-digits] = temp;
- lcd.setCursor(0,1);
- lcd.print(terrainLower);
- lcd.setCursor(16 - digits,0);
- lcd.print(score);
- terrainUpper[HERO_HORIZONTAL_POSITION] = upperSave;
- terrainLower[HERO_HORIZONTAL_POSITION] = lowerSave;
- return collide;
- }
- // Función que maneja el pulsador como interrupción
- void buttonPush()
- {
- buttonPushed = true;
- }
- void setup()
- {
- pinMode(PIN_BUTTON, INPUT);
- digitalWrite(PIN_BUTTON, HIGH);
- // Pin digital 2 mapeado a la interrupción "0"
- attachInterrupt(0, buttonPush, FALLING);
- initializeGraphics();
- lcd.begin(16, 2); // Comienzo del LCD 1602
- lcd.backlight(); // LED Backlight encendido
- }
- void loop()
- {
- static byte heroPos = HERO_POSITION_RUN_LOWER_1;
- static byte newTerrainType = TERRAIN_EMPTY;
- static byte newTerrainDuration = 1;
- static bool playing = false;
- static bool blink = false;
- static unsigned int distance = 0;
- if (!playing)
- {
- drawHero((blink) ? HERO_POSITION_OFF : heroPos, terrainUpper, terrainLower, distance >> 3);
- if (blink)
- {
- lcd.setCursor(0,0);
- lcd.print("PULSA AHORA!!!");
- }
- delay(250);
- blink = !blink;
- if (buttonPushed)
- {
- initializeGraphics();
- heroPos = HERO_POSITION_RUN_LOWER_1;
- playing = true;
- buttonPushed = false;
- distance = 0;
- }
- return;
- }
- // Desplaza el terreno hacia la izquierda de la pantalla
- advanceTerrain(terrainLower, newTerrainType == TERRAIN_LOWER_BLOCK ? SPRITE_TERRAIN_SOLID : SPRITE_TERRAIN_EMPTY);
- advanceTerrain(terrainUpper, newTerrainType == TERRAIN_UPPER_BLOCK ? SPRITE_TERRAIN_SOLID : SPRITE_TERRAIN_EMPTY);
- // Fabrica un nuevo terreno para que entre por la derecha de la pantalla
- if (--newTerrainDuration == 0)
- {
- if (newTerrainType == TERRAIN_EMPTY)
- {
- newTerrainType = (random(3) == 0) ? TERRAIN_UPPER_BLOCK : TERRAIN_LOWER_BLOCK;
- newTerrainDuration = 2 + random(10);
- }
- else
- {
- newTerrainType = TERRAIN_EMPTY;
- newTerrainDuration = 10 + random(10);
- }
- }
- if (buttonPushed)
- {
- if (heroPos <= HERO_POSITION_RUN_LOWER_2) heroPos = HERO_POSITION_JUMP_1;
- buttonPushed = false;
- }
- if (drawHero(heroPos, terrainUpper, terrainLower, distance >> 3))
- {
- playing = false; // Cuando el personaje choca con algo
- }
- else
- {
- if (heroPos == HERO_POSITION_RUN_LOWER_2 || heroPos == HERO_POSITION_JUMP_8)
- {
- heroPos = HERO_POSITION_RUN_LOWER_1;
- }
- else if ((heroPos >= HERO_POSITION_JUMP_3 && heroPos <= HERO_POSITION_JUMP_5) && terrainLower[HERO_HORIZONTAL_POSITION] != SPRITE_TERRAIN_EMPTY)
- {
- heroPos = HERO_POSITION_RUN_UPPER_1;
- }
- else if (heroPos >= HERO_POSITION_RUN_UPPER_1 && terrainLower[HERO_HORIZONTAL_POSITION] == SPRITE_TERRAIN_EMPTY)
- {
- heroPos = HERO_POSITION_JUMP_5;
- }
- else if (heroPos == HERO_POSITION_RUN_UPPER_2)
- {
- heroPos = HERO_POSITION_RUN_UPPER_1;
- }
- else
- {
- ++heroPos;
- }
- ++distance;
- }
- delay(100);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement