Advertisement
Villalba2006

POST_44

Nov 25th, 2016
6,167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.38 KB | None | 0 0
  1. /*  TITULO: Juego “Runner Scape” con display LCD 1602 y comunicación I2C.
  2.  
  3.     AUTOR:
  4.    
  5.     MARIANO DEL CAMPO GARCÍA (@2016) --> INGENIERO TÉCNICO INDUSTRIAL ESPECIALIDAD ELECTRÓNICA
  6.     - FACEBOOK: https://www.facebook.com/mariano.delcampogarcia
  7.     - TWITTER: https://twitter.com/MarianoCampoGa
  8.     - CORREO: marianodc83@gmail.com
  9.    
  10.    
  11.     DESCRIPCIÓN DEL PROGRAMA
  12.    
  13.     En este programa vamos a a controlar un personaje mediante un pulsador, para evitar que se
  14.     choque con los obstáculos que le van alcanzando a medida que va corriendo. El personaje salta
  15.     el obstáculo cuando presionamos el pulsador. El juego termina cuando se choca el personaje y
  16.     para reestablecer el juego tenemos que volver a presionar el pulsador. El juego se visualiza
  17.     a través de un LCD 1602 conectado a Arduino mediante comunicación I2C.
  18.    
  19.  
  20.     ESQUEMA DE CONEXION
  21.    
  22.                                       +-----+
  23.          +----[PWR]-------------------| USB |--+
  24.          |                            +-----+  |
  25.          |         GND/RST2  [ ][ ]            |
  26.          |       MOSI2/SCK2  [ ][ ]  A5/SCL[ ] |   SCL del módulo I2C conectado al LCD 1602
  27.          |          5V/MISO2 [ ][ ]  A4/SDA[ ] |   SDA del módulo I2C conectado al LCD 1602
  28.          |                             AREF[ ] |
  29.          |                              GND[ ] |
  30.          | [ ]N/C                    SCK/13[ ] |  
  31.          | [ ]IOREF                 MISO/12[ ] |  
  32.          | [ ]RST                   MOSI/11[ ]~|  
  33.          | [ ]3V3    +---+               10[ ]~|  
  34.          | [ ]5v    -| A |-               9[ ]~|  
  35.          | [ ]GND   -| R |-               8[ ] |  
  36.          | [ ]GND   -| D |-                    |
  37.          | [ ]Vin   -| U |-               7[ ] |  
  38.          |          -| I |-               6[ ]~|  
  39.          | [ ]A0    -| N |-               5[ ]~|  
  40.          | [ ]A1    -| O |-               4[ ] |  
  41.          | [ ]A2     +---+           INT1/3[ ]~|  
  42.          | [ ]A3                     INT0/2[ ] |   PA
  43.          | [ ]A4/SDA  RST SCK MISO     TX>1[ ] |  
  44.          | [ ]A5/SCL  [ ] [ ] [ ]      RX<0[ ] |  
  45.          |            [ ] [ ] [ ]              |
  46.          |  UNO_R3    GND MOSI 5V  ____________/
  47.           \_______________________/
  48.  
  49.   NOTAS:
  50.  
  51.    - La alimentación y la masa del módulo LCM 1602 I2C V1 van directamente conectadas a VCC (+5V) y GND
  52.      respectivamente.
  53.    - Los pulsadores suelen tener dos pines, que vamos a denominar PA y PB (si es de 4 sólo usamos 2 de ellos)
  54.    - Conexión PULL-DOWN del pulsador.
  55.        - PB conectado a VCC.
  56.        - PA conectado a GND a través de una R=10K ohms.  
  57. */
  58.  
  59.   // Importar librerías
  60.   #include <Wire.h> // Librería comunicación I2C
  61.   #include <LiquidCrystal_I2C.h> // Librería LCD I2C
  62.  
  63.   #define PIN_BUTTON 2    // Pin digital 2 para el botón del juego
  64.  
  65.   #define SPRITE_RUN1 1
  66.   #define SPRITE_RUN2 2
  67.   #define SPRITE_JUMP 3
  68.   #define SPRITE_JUMP_UPPER '.'  // Usa el carácter '.' para la cabeza
  69.   #define SPRITE_JUMP_LOWER 4
  70.   #define SPRITE_TERRAIN_EMPTY ' ' // Usa el carácter ' ' para los espacios vacíos
  71.   #define SPRITE_TERRAIN_SOLID 5
  72.   #define SPRITE_TERRAIN_SOLID_RIGHT 6
  73.   #define SPRITE_TERRAIN_SOLID_LEFT 7
  74.  
  75.   #define HERO_HORIZONTAL_POSITION 1    // Posición horizontal del personaje en la pantalla
  76.  
  77.   #define TERRAIN_WIDTH 16
  78.   #define TERRAIN_EMPTY 0
  79.   #define TERRAIN_LOWER_BLOCK 1
  80.   #define TERRAIN_UPPER_BLOCK 2
  81.  
  82.   #define HERO_POSITION_OFF 0          // El personaje es invisible
  83.   #define HERO_POSITION_RUN_LOWER_1 1  // Personaje corriendo en la fila inferior (posición 1)
  84.   #define HERO_POSITION_RUN_LOWER_2 2  // Personaje corriendo en la fila inferior (posición 2)
  85.  
  86.   #define HERO_POSITION_JUMP_1 3       // Comienzo del salto
  87.   #define HERO_POSITION_JUMP_2 4       // Salto en la mitad del trayecto hacia arriba
  88.   #define HERO_POSITION_JUMP_3 5       // Salto en la fila superior
  89.   #define HERO_POSITION_JUMP_4 6       // Salto en la fila superior
  90.   #define HERO_POSITION_JUMP_5 7       // Salto en la fila superior
  91.   #define HERO_POSITION_JUMP_6 8       // Salto en la fila superior
  92.   #define HERO_POSITION_JUMP_7 9       // Salto en la mitad del trayecto hacia abajo
  93.   #define HERO_POSITION_JUMP_8 10      // A punto de aterrizar
  94.  
  95.   #define HERO_POSITION_RUN_UPPER_1 11 // Personaje corriendo en la fila superior (posición 1)
  96.   #define HERO_POSITION_RUN_UPPER_2 12 // Personaje corriendo en la fila superior (posición 2)
  97.  
  98.   // Declaración del objeto
  99.   // Terminales de conexión del LCD
  100.   //                    addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
  101.   LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
  102.  
  103.   static char terrainUpper[TERRAIN_WIDTH + 1];
  104.   static char terrainLower[TERRAIN_WIDTH + 1];
  105.   static bool buttonPushed = false;
  106.  
  107.   void initializeGraphics()
  108.   {
  109.     static byte graphics[] =
  110.     {
  111.       // Corredor en la position 1
  112.       B01100,
  113.       B01100,
  114.       B00000,
  115.       B01110,
  116.       B11100,
  117.       B01100,
  118.       B11010,
  119.       B10011,
  120.       // Corredor en la position 2
  121.       B01100,
  122.       B01100,
  123.       B00000,
  124.       B01100,
  125.       B01100,
  126.       B01100,
  127.       B01100,
  128.       B01110,
  129.       // Salto
  130.       B01100,
  131.       B01100,
  132.       B00000,
  133.       B11110,
  134.       B01101,
  135.       B11111,
  136.       B10000,
  137.       B00000,
  138.       // Salto bajo
  139.       B11110,
  140.       B01101,
  141.       B11111,
  142.       B10000,
  143.       B00000,
  144.       B00000,
  145.       B00000,
  146.       B00000,
  147.       // Suelo
  148.       B11111,
  149.       B11111,
  150.       B11111,
  151.       B11111,
  152.       B11111,
  153.       B11111,
  154.       B11111,
  155.       B11111,
  156.       // Suelo derecho
  157.       B00011,
  158.       B00011,
  159.       B00011,
  160.       B00011,
  161.       B00011,
  162.       B00011,
  163.       B00011,
  164.       B00011,
  165.       // Suelo izquierdo
  166.       B11000,
  167.       B11000,
  168.       B11000,
  169.       B11000,
  170.       B11000,
  171.       B11000,
  172.       B11000,
  173.       B11000,
  174.     };
  175.     int i;
  176.     for (i = 0; i < 7; ++i)
  177.     {
  178.       lcd.createChar(i + 1, &graphics[i * 8]);
  179.     }
  180.     for (i = 0; i < TERRAIN_WIDTH; ++i)
  181.     {
  182.       terrainUpper[i] = SPRITE_TERRAIN_EMPTY;
  183.       terrainLower[i] = SPRITE_TERRAIN_EMPTY;
  184.     }
  185.   }
  186.  
  187.   // Función que desliza el terreno hacia la izquierda en incrementos de medio caracter
  188.   void advanceTerrain(char* terrain, byte newTerrain)
  189.   {
  190.     for (int i = 0; i < TERRAIN_WIDTH; ++i)
  191.     {
  192.       char current = terrain[i];
  193.       char next = (i == TERRAIN_WIDTH-1) ? newTerrain : terrain[i+1];
  194.       switch (current)
  195.       {
  196.         case SPRITE_TERRAIN_EMPTY:
  197.           terrain[i] = (next == SPRITE_TERRAIN_SOLID) ? SPRITE_TERRAIN_SOLID_RIGHT : SPRITE_TERRAIN_EMPTY;
  198.           break;
  199.         case SPRITE_TERRAIN_SOLID:
  200.           terrain[i] = (next == SPRITE_TERRAIN_EMPTY) ? SPRITE_TERRAIN_SOLID_LEFT : SPRITE_TERRAIN_SOLID;
  201.           break;
  202.         case SPRITE_TERRAIN_SOLID_RIGHT:
  203.           terrain[i] = SPRITE_TERRAIN_SOLID;
  204.           break;
  205.         case SPRITE_TERRAIN_SOLID_LEFT:
  206.           terrain[i] = SPRITE_TERRAIN_EMPTY;
  207.           break;
  208.       }
  209.     }
  210.   }
  211.  
  212.   bool drawHero(byte position, char* terrainUpper, char* terrainLower, unsigned int score)
  213.   {
  214.     bool collide = false;
  215.     char upperSave = terrainUpper[HERO_HORIZONTAL_POSITION];
  216.     char lowerSave = terrainLower[HERO_HORIZONTAL_POSITION];
  217.     byte upper, lower;
  218.     switch (position)
  219.     {
  220.       case HERO_POSITION_OFF:
  221.         upper = lower = SPRITE_TERRAIN_EMPTY;
  222.         break;
  223.       case HERO_POSITION_RUN_LOWER_1:
  224.         upper = SPRITE_TERRAIN_EMPTY;
  225.         lower = SPRITE_RUN1;
  226.         break;
  227.       case HERO_POSITION_RUN_LOWER_2:
  228.         upper = SPRITE_TERRAIN_EMPTY;
  229.         lower = SPRITE_RUN2;
  230.         break;
  231.       case HERO_POSITION_JUMP_1:
  232.       case HERO_POSITION_JUMP_8:
  233.         upper = SPRITE_TERRAIN_EMPTY;
  234.         lower = SPRITE_JUMP;
  235.         break;
  236.       case HERO_POSITION_JUMP_2:
  237.       case HERO_POSITION_JUMP_7:
  238.         upper = SPRITE_JUMP_UPPER;
  239.         lower = SPRITE_JUMP_LOWER;
  240.         break;
  241.       case HERO_POSITION_JUMP_3:
  242.       case HERO_POSITION_JUMP_4:
  243.       case HERO_POSITION_JUMP_5:
  244.       case HERO_POSITION_JUMP_6:
  245.         upper = SPRITE_JUMP;
  246.         lower = SPRITE_TERRAIN_EMPTY;
  247.         break;
  248.       case HERO_POSITION_RUN_UPPER_1:
  249.         upper = SPRITE_RUN1;
  250.         lower = SPRITE_TERRAIN_EMPTY;
  251.         break;
  252.       case HERO_POSITION_RUN_UPPER_2:
  253.         upper = SPRITE_RUN2;
  254.         lower = SPRITE_TERRAIN_EMPTY;
  255.         break;
  256.     }
  257.     if (upper != ' ')
  258.     {
  259.       terrainUpper[HERO_HORIZONTAL_POSITION] = upper;
  260.       collide = (upperSave == SPRITE_TERRAIN_EMPTY) ? false : true;
  261.     }
  262.     if (lower != ' ')
  263.     {
  264.       terrainLower[HERO_HORIZONTAL_POSITION] = lower;
  265.       collide |= (lowerSave == SPRITE_TERRAIN_EMPTY) ? false : true;
  266.     }
  267.    
  268.     byte digits = (score > 9999) ? 5 : (score > 999) ? 4 : (score > 99) ? 3 : (score > 9) ? 2 : 1;
  269.    
  270.     // Dibuja la escena
  271.     terrainUpper[TERRAIN_WIDTH] = '\0';
  272.     terrainLower[TERRAIN_WIDTH] = '\0';
  273.     char temp = terrainUpper[16-digits];
  274.     terrainUpper[16-digits] = '\0';
  275.     lcd.setCursor(0,0);
  276.     lcd.print(terrainUpper);
  277.     terrainUpper[16-digits] = temp;  
  278.     lcd.setCursor(0,1);
  279.     lcd.print(terrainLower);
  280.    
  281.     lcd.setCursor(16 - digits,0);
  282.     lcd.print(score);
  283.  
  284.     terrainUpper[HERO_HORIZONTAL_POSITION] = upperSave;
  285.     terrainLower[HERO_HORIZONTAL_POSITION] = lowerSave;
  286.     return collide;
  287.   }
  288.  
  289.   // Función que maneja el pulsador como interrupción
  290.   void buttonPush()
  291.   {
  292.     buttonPushed = true;
  293.   }
  294.  
  295.   void setup()
  296.   {
  297.     pinMode(PIN_BUTTON, INPUT);
  298.     digitalWrite(PIN_BUTTON, HIGH);
  299.    
  300.     // Pin digital 2 mapeado a la interrupción "0"
  301.     attachInterrupt(0, buttonPush, FALLING);
  302.    
  303.     initializeGraphics();
  304.    
  305.     lcd.begin(16, 2); // Comienzo del LCD 1602
  306.     lcd.backlight(); // LED Backlight encendido
  307.   }
  308.  
  309.   void loop()
  310.   {
  311.     static byte heroPos = HERO_POSITION_RUN_LOWER_1;
  312.     static byte newTerrainType = TERRAIN_EMPTY;
  313.     static byte newTerrainDuration = 1;
  314.     static bool playing = false;
  315.     static bool blink = false;
  316.     static unsigned int distance = 0;
  317.    
  318.     if (!playing)
  319.     {
  320.       drawHero((blink) ? HERO_POSITION_OFF : heroPos, terrainUpper, terrainLower, distance >> 3);
  321.       if (blink)
  322.       {
  323.         lcd.setCursor(0,0);
  324.         lcd.print("PULSA AHORA!!!");
  325.       }
  326.       delay(250);
  327.       blink = !blink;
  328.       if (buttonPushed)
  329.       {
  330.         initializeGraphics();
  331.         heroPos = HERO_POSITION_RUN_LOWER_1;
  332.         playing = true;
  333.         buttonPushed = false;
  334.         distance = 0;
  335.       }
  336.       return;
  337.     }
  338.  
  339.     // Desplaza el terreno hacia la izquierda de la pantalla
  340.     advanceTerrain(terrainLower, newTerrainType == TERRAIN_LOWER_BLOCK ? SPRITE_TERRAIN_SOLID : SPRITE_TERRAIN_EMPTY);
  341.     advanceTerrain(terrainUpper, newTerrainType == TERRAIN_UPPER_BLOCK ? SPRITE_TERRAIN_SOLID : SPRITE_TERRAIN_EMPTY);
  342.    
  343.     // Fabrica un nuevo terreno para que entre por la derecha de la pantalla
  344.     if (--newTerrainDuration == 0)
  345.     {
  346.       if (newTerrainType == TERRAIN_EMPTY)
  347.       {
  348.         newTerrainType = (random(3) == 0) ? TERRAIN_UPPER_BLOCK : TERRAIN_LOWER_BLOCK;
  349.         newTerrainDuration = 2 + random(10);
  350.       }
  351.       else
  352.       {
  353.         newTerrainType = TERRAIN_EMPTY;
  354.         newTerrainDuration = 10 + random(10);
  355.       }
  356.     }
  357.      
  358.     if (buttonPushed)
  359.     {
  360.       if (heroPos <= HERO_POSITION_RUN_LOWER_2) heroPos = HERO_POSITION_JUMP_1;
  361.       buttonPushed = false;
  362.     }  
  363.  
  364.     if (drawHero(heroPos, terrainUpper, terrainLower, distance >> 3))
  365.     {
  366.       playing = false; // Cuando el personaje choca con algo
  367.     }
  368.     else
  369.     {
  370.       if (heroPos == HERO_POSITION_RUN_LOWER_2 || heroPos == HERO_POSITION_JUMP_8)
  371.       {
  372.         heroPos = HERO_POSITION_RUN_LOWER_1;
  373.       }
  374.       else if ((heroPos >= HERO_POSITION_JUMP_3 && heroPos <= HERO_POSITION_JUMP_5) && terrainLower[HERO_HORIZONTAL_POSITION] != SPRITE_TERRAIN_EMPTY)
  375.       {
  376.         heroPos = HERO_POSITION_RUN_UPPER_1;
  377.       }
  378.       else if (heroPos >= HERO_POSITION_RUN_UPPER_1 && terrainLower[HERO_HORIZONTAL_POSITION] == SPRITE_TERRAIN_EMPTY)
  379.       {
  380.         heroPos = HERO_POSITION_JUMP_5;
  381.       }
  382.       else if (heroPos == HERO_POSITION_RUN_UPPER_2)
  383.       {
  384.         heroPos = HERO_POSITION_RUN_UPPER_1;
  385.       }
  386.       else
  387.       {
  388.         ++heroPos;
  389.       }
  390.       ++distance;
  391.     }
  392.     delay(100);
  393.   }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement