Arduino Uno Text Adventure mit 2x16 LCD und Keypad

Hallo,

ich hatte schon beim Arduino Forum gefragt und leider keine (geistreiche) Antwort bekommen…
Ich habe scheinbar bei meinem Code einen Denkfehler.
Wer schon mal was vom Hamster gehört hat, weiß, was ich hier vorhabe. Ich baue ein Spielfeld in einem Array auf und lasse eine Spielfigur hindurch wandern.

Dazu verwende ich ein Arduino Uno, ein LCD Keypad Shield und ein 2x16 LCD weiß auf blau (http://www.komputer.de/zen/index.php?main_page=produ…).

Ich schätze mal, dass der Fehler irgendwie in der Position des Chars im Array zu tun hat.
Ich drücke rechts -> a tree (ist richtig)
Ich drücke nochmal rechts -> nothing -> game over (Hä?)
Nach links kann ich mich eine ganze Weile bewegen, bevor „a tree“ erscheint. Nach oben ist direkt ein Baum, noch ein Baum, ein freies Feld…

Wer mir aus dem Schlammasel hilft, bekommt ein Gummibärchen :wink:

Hier der Code:

/\*

 Little text adventure

 By DarkAngel

 \*technikzumanfassen.forumieren.com\*

 XXXXXXXXXX
 X O X
 X X X X
 X XXX CX X 
//create object to control an LCD. 
//number of lines in display=2
LCD4Bit\_mod lcd = LCD4Bit\_mod(2); 

//Key Reihenfolge: rechts, oben, unten, links, select
int adc\_key\_val[5] ={
 30, 150, 360, 535, 760 };
int NUM\_KEYS = 5;
int adc\_key\_in;
int key=-1;

// Variables for the game
int playerposition[2] = { 5, 4};
int x = playerposition[0]; // giving actual player position to variables
int y = playerposition[1]; // needed for next position and status

int playfield[7][9] = {
 {0,0,0,0,0,0,0,0,0},
 {0,1,2,1,1,1,1,1,0},
 {0,1,1,0,1,1,0,1,0},
 {0,1,0,0,1,1,0,1,0},
 {0,1,1,0,1,1,0,1,0},
 {0,5,1,0,1,1,0,3,0},
 {0,0,9,0,0,0,0,0,0}
 }; // 0=wall, 1=free field, 2=coin, 3=weapon, 5=enemy, 9=exit
int inventory[1];
char messages[10][19] = {
 "a tree... ",
 "moving ",
 "got a coin ",
 "got a weapon ",
 "an enemy ",
 "defended ",
 "enemy dies ",
 "nothing to defend",
 "you die ",
 "GAME OVER "};

void setup() 
{ 
 // (original Code from example)
 pinMode(13, OUTPUT); //we'll use the debug LED to output a heartbeat

 lcd.init();
 //optionally, now set up our application-specific display settings, overriding whatever the lcd did in lcd.init()
 //lcd.commandWrite(0x0F);//cursor on, display on, blink on. (nasty!)
 lcd.clear();
 lcd.printIn("In the woods"); // my Title :wink:
}

void loop() 
{
 lcd.cursorTo(2, 0); //line=2, x=0 (original Code from example)

 if(x==0 && x==0) // if game over, don't do anything
 {
 delay(5000);
 }
 else
 { 
 adc\_key\_in = analogRead(0); // read the value from the sensor (original Code from example)
 digitalWrite(13, HIGH);

 key = get\_key(adc\_key\_in); // convert into key press (original Code from example)
 delay(50); // wait for debounce time (original Code from example)
 adc\_key\_in = analogRead(0); // read the value from the sensor (original Code from example)
 key = get\_key(adc\_key\_in); // convert into key press (original Code from example)

 digitalWrite(13, LOW); // (original Code from example)

 if (key \>=0) // if pressed any key
 {
 delay(50);
 int z = get\_point(key); // sending the pressed key to function get\_point
 delay(100);
 key=-1;

 if(z==0) // if standing in front of a tree, tell them
 {
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[z]);
 lcd.cursorTo(2, 0);
 } // End x==0

 if(z==1 || z==2) // if found a coin or free field, move
 {
 playerposition[0] = x;
 playerposition[1] = y;
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[z]);
 lcd.cursorTo(2, 0);
 } // End x==1, x==2
 if(z==3) // if found a weapon, equip it and move
 {
 inventory[0] = 3;
 playerposition[0] = x;
 playerposition[1] = y;
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[z]);
 lcd.cursorTo(2, 0);
 } // End x==3
 if(z==4) // if found an enemy, search weapon
 {
 if(inventory[0]==3) // if weapon is found,
 {
 delay(100);
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[5]); // destroy enemy
 delay(50);
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[6]); // and win game
 lcd.cursorTo(2, 0);
 }
 else
 {
 delay(100);
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[7]); // else you will be destroyed by enemy
 delay(100);
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[8]); // and loose game
 lcd.cursorTo(2, 0);
 z = 9;
 }
 if(z==9) // if game is lost or won, show game over
 {
 playerposition[0] = 0;
 playerposition[1] = 0;
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[9]);
 delay(5000);
 } 
 } 
 }
 }
}

// Convert ADC value to key number (original Code from example)
int get\_key(unsigned int input)
{
 int k;

 for (k = 0; k = NUM\_KEYS)
 k = -1; // No valid key pressed

 return k;
}

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* Get point on playfield \*
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
int get\_point(unsigned int key)
{
 lcd.cursorTo(2, 0);
 int point;

 if(key==0) // show direction where you wanted to go
 {
 x++;
 lcd.printIn("right ");
 lcd.cursorTo(2, 0);
 delay(100);
 }
 if(key==1)
 {
 y--;
 lcd.printIn("up ");
 lcd.cursorTo(2, 0);
 delay(100);
 }
 if(key==2)
 {
 y++;
 lcd.printIn("down ");
 lcd.cursorTo(2, 0);
 delay(100);
 }
 if(key==3)
 {
 x--;
 lcd.printIn("left ");
 lcd.cursorTo(2, 0);
 delay(100);
 }
 if(key==4) // if select key was pressed, show inventory
 {
 if(inventory[0]==3)
 {
 lcd.printIn("weapon ");
 lcd.cursorTo(2, 0);
 delay(500);
 }
 else
 {
 lcd.printIn("nothing ");
 lcd.cursorTo(2, 0);
 delay(500);
 }
 }

 point = playfield[x][y]; // get point of playfield where you wanted to go

 switch(point)
 {
 case 0: 
 return 0; // point is a wall (tree)?
 break; 
 case 1: 
 return 1; // point is a free field?
 break; 
 case 2: 
 return 2; // point is a coin (and actually a free field)?
 break;
 case 3: 
 return 3; // point is a weapon?
 break; 
 case 5: 
 return 5; // point is the enemy?
 break;
 case 9: 
 return 9; // point is the exit?
 break;

 }
}

LG

DA

Hallo,

ich kann mir den Code gerne später noch mal in ruhe ansehen, aber diese Zeile z.b. verstehe ich nicht so recht:

if(x==0 && x==0) // if game over, don’t do anything

Sollte es nicht besser heißen:

if(x==0 && y==0) // if game over, don’t do anything

Grüße

godam

Hi,

vielen Dank für die Antwort. Ja, das war auch ein Fehler. Ich hatte noch einige andere entdeckt, nachdem ich das Projekt einfach ein paar Tage hatte ruhen lassen. Ich hätte es vielleicht eher unter C++ ins Forum schreiben sollen…

Es waren zwei Hauptprobleme im Code

  • Ich hatte vergessen, die aktuelle Position zu aktualisieren, weshalb man auch durch Bäume durchgehen konnte

  • Egal warum, das Spielfeld war um 90° gedreht und gleichzeitig horizontal gespiegelt (habs mit Paint nachgebaut *lol*)

Das einzige, was ich jetzt noch erledigen muss, ist den Coin aus dem Spiel zu nehmen, nachdem er aufgesammelt wurde (und vielleicht eine Funktion für ihn einbauen).

Wenn noch jemand am Code interesse hat (vielleicht ein Student, der mit dem Hamster Schwierigkeiten hat), hier der „neue“ Code:

/\*

 Little text adventure
 
 By DarkAngel
 
 \*technikzumanfassen.forumieren.com\*
 
 XXXXXXXXXX
 X O X
 X X X X
 X XXX X X
 X X CX X 
//create object to control an LCD. // (original Code from example)
//number of lines in display=2
LCD4Bit\_mod lcd = LCD4Bit\_mod(2); 

//Key sequence: right, up, down, left, select
int adc\_key\_val[5] ={
 30, 150, 360, 535, 760 };
int NUM\_KEYS = 5; // there are 5 keys
int adc\_key\_in;
int key=-1;
int last\_key=-1; // needed to go back to last position

// Variables for the game
int playerposition[2] = { 
 4, 5};
int x = playerposition[0]; // giving actual player position to variables
int y = playerposition[1]; // needed for next position and status

int playfield[9][7] = {
 { 0,0,0,0,0,0,0 }
 ,
 { 0,1,1,1,1,5,0 }
 ,
 { 0,2,1,0,1,1,9 }
 ,
 { 0,1,0,0,0,0,0 }
 ,
 { 0,1,1,1,1,1,0 }
 ,
 { 0,1,1,1,1,1,0 }
 ,
 { 0,1,0,0,0,0,0 }
 ,
 { 0,1,1,1,1,3,0 }
 ,
 { 0,0,0,0,0,0,0 }
}; // 0=wall, 1=free field, 2=coin, 3=weapon, 5=enemy, 9=exit
 // and I really don't know why this has to be rotated right by 90° and horizontally flipped...
int inventory[1]; //only to say the player if he has a weapon
char messages[10][19] = {
 "a tree... ",
 "moving ",
 "got a coin ",
 "got a weapon ",
 "an enemy ",
 "defended ",
 "enemy dies ",
 "nothing to defend",
 "you die ",
 "GAME OVER "};

void setup() 
{ 
 // (original Code from example)
 pinMode(13, OUTPUT); //we'll use the debug LED to output a heartbeat

 lcd.init();
 //optionally, now set up our application-specific display settings, overriding whatever the lcd did in lcd.init()
 //lcd.commandWrite(0x0F);//cursor on, display on, blink on. (nasty!)
 lcd.clear();
 lcd.printIn("In the woods"); // my Title :wink:
 Serial.begin(9600);
}

void loop() 
{
 lcd.cursorTo(2, 0); //line=2, x=0 (original Code from example)

 if(x==0 && y==0) // if game over, don't do anything
 {
 delay(5000);
 }
 else
 { 
 adc\_key\_in = analogRead(0); // read the value from the sensor (original Code from example)
 digitalWrite(13, HIGH);

 key = get\_key(adc\_key\_in); // convert into key press (original Code from example)
 delay(50); // wait for debounce time (original Code from example)
 adc\_key\_in = analogRead(0); // read the value from the sensor (original Code from example)
 key = get\_key(adc\_key\_in); // convert into key press (original Code from example)

 digitalWrite(13, LOW); // (original Code from example)

 if (key \>=0) // if pressed any key
 {
 delay(50);
 int z = get\_point(key); // sending the pressed key to function get\_point
 delay(100);
 key=-1;

 if(z==0) // if standing in front of a tree, tell them
 {
 switch(last\_key)
 {
 case 0: 
 x--;
 break;
 case 1: 
 y++;
 break;
 case 2: 
 y--;
 break;
 case 3: 
 x++;
 break;
 default: 
 last\_key = -1;
 break;
 }
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[z]);
 lcd.cursorTo(2, 0);
 } // End z==0

 if(z==1 || z==2) // if found a coin or free field, move
 {
 playerposition[0] = x;
 playerposition[1] = y;
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[z]); // the coin has no use (yet)
 lcd.cursorTo(2, 0); // hier den Coin entfernen
 } // End z==1, z==2
 if(z==3) // if found a weapon, equip it and move
 {
 inventory[0] = 3;
 playerposition[0] = x;
 playerposition[1] = y;
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[z]);
 lcd.cursorTo(2, 0);
 } // End z==3
 if(z==5) // if found an enemy, search weapon
 {
 playerposition[0] = x;
 playerposition[1] = y;
 playfield[x][y] = '1'; // remove enemy from map

 if(inventory[0]==3) // if weapon is found,
 {
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[5]); // destroy enemy
 delay(500);
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[6]); // and win game
 lcd.cursorTo(2, 0);
 delay(1500);
 z = 9;
 }
 else
 {
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[7]); // else you will be destroyed by enemy
 delay(500);
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[8]); // Game Over
 lcd.cursorTo(2, 0);
 z = 9;
 }
 }//end z==5
 if(z==9) // if game is lost or won, show game over
 {
 x=0;
 y=0;
 lcd.cursorTo(2, 0);
 lcd.printIn(messages[9]);
 delay(5000);
 }//end z==9 
 }//end key\>=0 
 }//end else
}


// Convert ADC value to key number (original Code from example)
int get\_key(unsigned int input)
{
 int k;

 for (k = 0; k = NUM\_KEYS)
 k = -1; // No valid key pressed

 return k;
}

/\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
 \* Get point on playfield \*
 \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*/
int get\_point(unsigned int key)
{
 lcd.cursorTo(2, 0);
 int point;

 if(key==0) // show direction where you wanted to go
 {
 x++;
 last\_key=0;
 lcd.printIn("right ");
 lcd.cursorTo(2, 0);
 delay(100);
 }
 if(key==1)
 {
 y--;
 last\_key=1;
 lcd.printIn("up ");
 lcd.cursorTo(2, 0);
 delay(100);
 }
 if(key==2)
 {
 y++;
 last\_key=2;
 lcd.printIn("down ");
 lcd.cursorTo(2, 0);
 delay(100);
 }
 if(key==3)
 {
 x--;
 last\_key=3;
 lcd.printIn("left ");
 lcd.cursorTo(2, 0);
 delay(100);
 }
 if(key==4) // if select key was pressed, show inventory
 {
 if(inventory[0]==3)
 {
 lcd.printIn("weapon ");
 lcd.cursorTo(2, 0);
 delay(500);
 }
 else
 {
 lcd.printIn("nothing ");
 lcd.cursorTo(2, 0);
 delay(500);
 }
 }

 point = playfield[x][y]; // get point of playfield where you wanted to go

 switch(point)
 {
 case 0: 
 return 0; // point is a wall (tree)?
 break; 
 case 1: 
 return 1; // point is a free field?
 break; 
 case 2: 
 return 2; // point is a coin (and actually a free field)?
 break;
 case 3: 
 return 3; // point is a weapon?
 break; 
 case 5: 
 return 5; // point is the enemy?
 break;
 case 9: 
 return 9; // point is the exit?
 break;

 }
}

LG

DA

Hallo,

dann hast du ja alles im Griff …

Schick mir doch mal 'ne Mail, wenn du den Code fertig hast. Wäre doch etwas für unsere Website (sofern du nichts dagegen hast).

Grüße und viel Erfolg

godam