Individální projekty MPOA

Mikroprocesory s architekturou ARM

Uživatelské nástroje

Nástroje pro tento web


2015:2048-game

Toto je starší verze dokumentu!


Hra 2048

Zadání

Realizujte hru 2048 na kitu FRDM-KL25Z. Jednotlivá čísla budou reprezentovány barvou, která bude zobrazena pomocí matice RGB LED. Pro řízení pohybu využijte akcelerometr.


Úvod

Vznik hry

Hra 2048 vznika prakticky za jediný víkend. Devatenáctiletý mladík jménem Gabriele Cirulli naprogramoval tuto hru jako školní projekt. Z tohoto nápadu velmi rychle vznikl fenomén a podobně jako v případě Flappy Bird začaly hříčku 2048 během několika dnů hrát desítky milionů hráčů.

Popis hry

Cílem hry je spojit čísla dohromady (mocniny 2), s cílem dosáhnout konečného čísla '2048 ' na jednom čtverečku. Herní pole je mřížka 4×4 (16 čtverečků), je zobrazena na Obr.1. Na začátku hry máte dva čtverce (také nazývané dlaždice) s číslem 2 uvnitř.Když spojíte dvě dlaždice se stejným číslem, splynou do nové dlaždice s dvojnásobným číslem, než je původní: 2+2 = 4, 4+4 = 8, … 1024 1024 = 2048! Chcete-li přesunout dlaždice na herním poli, stačí si vybrat směr (nahoru, dolů, vpravo nebo vlevo). Všechny dlaždice se přesunou zvoleným směrem - efekt sesypání k jedné straně. Pokud jsou vedle sebe dvě stejné čísla tak se spojí. V jednom kole se ale čísla mohou spojovat pouze jednou. Např. pokud sesypeme řádek 2 2 2 2 smerem doleva, výsledkem bude 4 4 0 0, nikoliv 8 0 0 0. Dalším pravidlem je že se sesypou nejvyšším číslem směrem ke stěně. Např. řádek 4 4 4 0 se změní na 8 4 0 0 nikoliv na 4 8 0 0. Po sesypání se oběví nové číslo 2 na některém s volných políček. Pokud je herní pole naplněno, hra končí.

V počítači, stačí použít pouze 4 šipky na klávesnici. Na mobilním zařízení s dotykovým displejem přejedeme prstem požadovaným směrem.

Implementace pro RGB displej

Mojím záměrem bylo implementovat tuto hru na RGB displej. Na něm ale nejdou zobrazovat čísla, proto budou reprezentovány pomocí různých barev. Řízení směru pohybu je řízeno pomocí náklonu displeje (akcelerometru). Všechny pravidla zůstavají stejná jako u originální hry.

  Obr.1 Ukázka ze hry 2048

Hardware

RGB matice LED je zapojena podle obrázku níže. Společným kontaktem pro každou RGB LED je anoda. Z toho vyplývá, že matice musí být spínána po řádcích tak, že je přivedeno kladné napětí na společnou anodu jednoho řádku a pomocí uzemění jednotlivých katod jsou rozsvěcovány jednotlivé LED.

K řízení RGB displeje nestačil samotný MCU ze dvou důvodů: 1. protože má pouze 3,3V logiku, která nestačí k bezepčnému rozsvícení LED (zejména modré) 2. každý pin omezený výstupní i vstupní proud na 4mA.

Z toho důvodu bylo potřeba vytvořit HW převodník, který převede 3,3V logiku na 5V a současně výkonově posílí výstupní piny. Pro spínání napětí +5V (high switch) bylo použito převodníku, který tvoří jeden NMOS a jeden PMOS. Pro spínání napětí 0V bylo použito tranzistorového pole ULN2803A. Kompletní zapojení převodníku je na Obr.2 níže.

  Obr.2 Schema zapojeni převodníku

Rozměr převodníku byl zvolen přesně podle rozměrů RGB matice LED a rozmístění součástek bylo voleno tak, aby se vešel nad kit FRDM-KL25Z. Deska byla vyráběna na ústavu UREL, proto nejsou použity klasické prokovy, místo nich je použito propojení drátkem. Převodník můžeme vidět na Obr.3 níže a soubory k jeho výrobě jsou v příloze k tohoto dokumentu.

  Obr.3 Osazený převodník

Software

Program byl psán ve vývojovém prostředí www.mbed.org. Celý kód je k dispozici v tomto odkazu https://developer.mbed.org/users/xlizne01/code/2048/

Realizace programu hry pomocí jazyka C++

#include „mbed.h“ #include „MMA8451Q.h“

#define MMA8451_I2C_ADDRESS (0x1d«1) #define MOVE_ANGLE 30 minimalni uhel pro pohyb #define NULL_ANGLE 15 minimalni uhel pro nulovou pozici #define BRIGHTNESS 10 svítivost MMA8451Q acc(PTE25, PTE24, MMA8451_I2C_ADDRESS); void akcelerometr(void); void zobrazeni(void); void barva(int,int); void pohyb(void); void sesypej(int); void pridej(void); int RED, GREEN, BLUE; float xAngle, yAngle; aktualni uhel v ose x a y int p=1;

char naklon; směr pohybu int pole[4][4]={{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}}; aktuální matice int pole2[4][4]={{0,0,0,0}, {0,0,0,0}, {0,0,0,0}, {0,0,0,0}}; kontrolní matice Definice výstupních pinů pro jednotlivé řádky (anody LED) DigitalOut prvni(PTE5); DigitalOut druhy(PTE4); DigitalOut treti(PTE3); DigitalOut ctvrty(PTE2); DigitalOut paty(PTB11); DigitalOut sesty(PTB10); DigitalOut sedmy(PTB9); DigitalOut osmy(PTB8);

Definice výstupních pinů pro jednotlivé sloupce (katody LED) DigitalOut Rled1(PTC9); DigitalOut Rled2(PTC8); DigitalOut Rled3(PTA5); DigitalOut Rled4(PTA4); DigitalOut Rled5(PTA12); DigitalOut Rled6(PTD4); DigitalOut Rled7(PTA1); DigitalOut Rled8(PTA2); DigitalOut Gled1(PTA13); DigitalOut Gled2(PTD5); DigitalOut Gled3(PTD0); DigitalOut Gled4(PTD2); DigitalOut Gled5(PTD3); DigitalOut Gled6(PTD1); DigitalOut Gled7(PTE31); DigitalOut Gled8(PTB0); DigitalOut Bled1(PTC1); DigitalOut Bled2(PTE29); DigitalOut Bled3(PTC2); DigitalOut Bled4(PTB3); DigitalOut Bled5(PTB2); DigitalOut Bled6(PTE21); DigitalOut Bled7(PTE20); DigitalOut Bled8(PTB1); int main() { akcelerometr(); pridej(); pridej(); přidání prvních dvou kostek

  while(1) // nekonečná smyčka pro detekci pohybu a zobrazování aktuální matice
  { 
      akcelerometr();
      pohyb();
      zobrazeni();
  }

}

void pohyb() {

  switch(naklon)
  {
      case 'D': //pohyb smerem dolu
          if(p==0)
          {
              sesypej(1);
              p=1;
          }
          break;
          
      case 'R': // pohyb smerem vpravo
          if(p==0)
          {
              sesypej(2);
              p=1;
          }
          break;
          
      case 'U': // pohyb smerem nahoru
          if(p==0)
          {
              sesypej(3);
              p=1;
          }
          break;
          
      case 'L': // pohyb smerem vlevo
          if(p==0)
          {
              sesypej(4);
              p=1;
          }
          break;
          
      case '0': // detekovana nulova pozice
          p=0;
          break;
          
      default:
          break;  
  }

}

/ void sesypej(int x) { int a,b,c,d; pomocné proměnné pro uložení řádků/sloupců při sesypání

  int same=0; // pomocná proměnná
  
  for(int k=0;k<4;k++)
  {
      for(int l=0;l<4;l++)
      {
          pole2[k][l]=pole[k][l]; //uložení původní matice do pomocné matice
      } 
  }
  
  for(int n=0;n<4;n++)
  {   
      if(x==1) // dolu
      {
          a=pole[n][0];
          b=pole[n][1];
          c=pole[n][2];
          d=pole[n][3];
      }
      
      if(x==2) // vpravo
      {
          a=pole[3][n];
          b=pole[2][n];
          c=pole[1][n];
          d=pole[0][n];
      }
      
      if(x==3) // nahoru
      {
          a=pole[n][3];
          b=pole[n][2];
          c=pole[n][1];
          d=pole[n][0];
      }
      
      if(x==4) // vlevo
      {
          a=pole[0][n];
          b=pole[1][n];
          c=pole[2][n];
          d=pole[3][n];
      }
      
          //sesypani
      if(a==0)
          {a=b; b=c; c=d; d=0;}
      if(a==0)
          {a=b; b=c; c=d; d=0;}
      if(a==0)
          {a=b; b=c; c=d; d=0;}
      if(b==0)
          {b=c; c=d; d=0;}
      if(b==0)
          {b=c; c=d; d=0;}
      if(c==0)
          {c=d; d=0;}
         
         //spojeni 
      if(a==b)
          {a=2*a; b=c; c=d; d=0;}
      if(b==c)
          {b=2*b; c=d; d=0;}
      if(c==d)
          {c=2*c; d=0;}
       
      if(x==1) // dolu
      {   
          pole[n][0]=a;
          pole[n][1]=b;
          pole[n][2]=c;
          pole[n][3]=d;
      }
      
      if(x==2) // vpravo
      {   
          pole[3][n]=a;
          pole[2][n]=b;
          pole[1][n]=c;
          pole[0][n]=d;
      }
      
      if(x==3) // nahoru
      {   
          pole[n][3]=a;
          pole[n][2]=b;
          pole[n][1]=c;
          pole[n][0]=d;
      }
      
      if(x==4) // vlevo
      {   
          pole[0][n]=a;
          pole[1][n]=b;
          pole[2][n]=c;
          pole[3][n]=d;
      }      
  }
  
  for(int q=0;q<4;q++)
  {
      for(int w=0;w<4;w++)
      {
          if (pole2[q][w]!=pole[q][w]) //kontrola, že došlo k nějaké změně v matici
          {
              same=1;
          }
      }
  }
      
  if(same==1)
  { 
      pridej();  
  }
  

}

/ void pridej() { int g=1; pomocná proměnná

  int f;      // nahodne cislo v rozmezi 0-15 sloužící ke generování náhodnách souřadnic
  
  while(g==1)
  { 
      f =(rand()+int(xAngle)+int(yAngle))%16;
      if(pole[f/4][f%4]==0)
      {
          if((rand()+int(xAngle)+int(yAngle))%10==1) // reprezentuje 10% šanci, že přidá číslo 4
          {
              pole[f/4][f%4]=4;
              g=0;
          }
          else // přidání čísla 2
          {
              pole[f/4][f%4]=2;
              g=0;
          }
      }
  }

}

void zobrazeni() { int RledA, RledB, GledA, GledB, BledA, BledB; for(int k=0;k<4;k++) { prvni=0; druhy=0; treti=0; ctvrty=0; paty=0; sesty=0; sedmy=0; osmy=0; wait(0.00005); opatreni proti tzv. duchum

      
      if(k==0)
      {
          prvni=1;
          druhy=1;
      }
  
      if(k==1)
      {
          treti=1;
          ctvrty=1;
      }
  
      if(k==2)
      {
          paty=1;
          sesty=1;
      }
  
      if(k==3)
      {
          sedmy=1;
          osmy=1;
      }
  
      for(int j=0;j<4;j++)
      { 
          barva(j,k);
              
          for(int i=11;i>0;i--)
          {
              if(RED>0)
              {
                  RledA=1;
                  RledB=1;
              }
              else
              {
                  RledA=0;
                  RledB=0;
              }
          
              if(GREEN>0)
              {
                  GledA=1;
                  GledB=1;
              }
              else
              {
                  GledA=0;
                  GledB=0;
              }
                  
              if(BLUE>0)
              {
                  BledA=1;
                  BledB=1;
              }
              else
              {
                  BledA=0;
                  BledB=0;
              }
      
              if(j==0)
              {
                  Rled1=RledA;
                  Rled2=RledB;
                  Gled1=GledA;
                  Gled2=GledB;
                  Bled1=BledA;
                  Bled2=BledB;
              }
              
              if(j==1)
              {
                  Rled3=RledA;
                  Rled4=RledB;
                  Gled3=GledA;
                  Gled4=GledB;
                  Bled3=BledA;
                  Bled4=BledB;
              }
              
              if(j==2)
              {
                  Rled5=RledA;
                  Rled6=RledB;
                  Gled5=GledA;
                  Gled6=GledB;
                  Bled5=BledA;
                  Bled6=BledB;
              }
              
              if(j==3)
              {
                  Rled7=RledA;
                  Rled8=RledB;
                  Gled7=GledA;
                  Gled8=GledB;
                  Bled7=BledA;
                  Bled8=BledB;
              } 
              
              wait(0.00001);
              RED--;
              BLUE--;
              GREEN--;  
          }    
      }
  } 

}

/

void barva(int k , int l) {

  if(pole[k][l]==0)
  {
      RED=0;
      GREEN=0;
      BLUE=0;
  }
  
  if(pole[k][l]==2)
  {
      RED=1;
      GREEN=0;
      BLUE=0;
  }
  
  if(pole[k][l]==4)
  {
      RED=10;
      GREEN=0;
      BLUE=0;
  }
  
  if(pole[k][l]==8)
  {
      RED=0;
      GREEN=0;
      BLUE=2;
  }
  
  if(pole[k][l]==16)
  {
      RED=0;
      GREEN=0;
      BLUE=10;
  }
  
  if(pole[k][l]==32)
  {
      RED=0;
      GREEN=2;
      BLUE=0;
  }
  
  if(pole[k][l]==64)
  {
      RED=0;
      GREEN=10;
      BLUE=0;
  }
  
  if(pole[k][l]==128)
  {
      RED=0;
      GREEN=10;
      BLUE=10;
  }
  
  if(pole[k][l]==256)
  {
      RED=10;
      GREEN=0;
      BLUE=10;
  }
  
  if(pole[k][l]==512)
  {
      RED=10;
      GREEN=10;
      BLUE=0;
  }
  
  if(pole[k][l]==1024)
  {
      RED=2;
      GREEN=2;
      BLUE=2;
  }
  
  if(pole[k][l]==2048)
  {
      RED=10;
      GREEN=10;
      BLUE=10;
  } 
   
  RED=RED*BRIGHTNESS/10;
  GREEN=GREEN*BRIGHTNESS/10;
  BLUE=BLUE*BRIGHTNESS/10;  

}

void akcelerometr() { float ax, ay, az; ax = acc.getAccX(); ay = acc.getAccY(); az = acc.getAccZ(); xAngle = atan( ax / (sqrt1))) * 60; yAngle = atan( ay / (sqrt2))) * 60; if3)<NULL_ANGLE) { naklon = '0'; 0 nula

  }
        
  if(abs(xAngle) >= abs(yAngle))
  {
      if(xAngle >= MOVE_ANGLE)
      {                 
          naklon = 'U';   // +X up
      }
         
      if(xAngle <= -MOVE_ANGLE)
      {
          naklon = 'D';    // -X  down
      }   
  }
  
  else
  {      
      if(yAngle >= MOVE_ANGLE)
      {
          naklon = 'L';   // +Y left
      }
  
      if(yAngle <= -MOVE_ANGLE)
      {
          naklon = 'R';   // -Y right
      }   
  }   

}

Video demostrace hry 2048


Závěr

1)
ay)*(ay) + (az)*(az
2)
ax)*(ax) + (az)*(az
3)
abs(xAngle)+abs(yAngle
2015/2048-game.1452860863.txt.gz · Poslední úprava: 2016/01/15 13:27 autor: Václav Lízner