Difference between revisions of "Freeduino Games"

From LVL1
Jump to navigation Jump to search
(Added Truck Lane code)
 
Line 17: Line 17:
  
  
<nowiki>/* Simple Car game for a 16x2 LCD display  
+
<pre>/* Simple Car game for a 16x2 LCD display  
 
   You can use any Hitachi HD44780 compatible LCD.
 
   You can use any Hitachi HD44780 compatible LCD.
 
   Modified for LVL1 Spring Training LCD Activity, originally from  
 
   Modified for LVL1 Spring Training LCD Activity, originally from  
Line 227: Line 227:
 
     lcd.print(line_buff);
 
     lcd.print(line_buff);
 
   }
 
   }
}</nowiki>
+
}</pre>

Revision as of 12:27, 8 March 2012

Freeduino Truck Lane Go from the Freeduino Spring Training LCD activity to a game! Need a Freeduino, a 10K pot, and a 16x2 LCD and a solderless breadboard. Follow all steps in 4th Inning. Now, pull the middle pot pin out of pin 14 of the LCD. Just connect pin 14 to ground. This should give you a high contrast display. We need to use the pot for steering! Connect the middle pot pin instead to Analog Input pin 1 of your Freeduino. Add a speaker on pin 13 if you wish--untested.

Here's the code, cut and paste this into Arduino and install it to your board. Play away. To play again, press the Freeduino's reset button.

It comes from [1] but we've changed the pinouts in the code to match what we did in the Freeduino Spring Training LCD activity.

Can you modify the code to make a game that rewards crashing? For example, scoot around catching falling "coins," and see how many you can collect within a certain time. Then, make them fall faster and faster! This would be a fun way to learn more about what the code is doing.

Coming soon, Freeduino Whack-A-Mole!


/* Simple Car game for a 16x2 LCD display 
   You can use any Hitachi HD44780 compatible LCD.
   Modified for LVL1 Spring Training LCD Activity, originally from 
    @TheRealDod, Nov 25, 2010
   There's a "steering wheel" potentiometer on analog input 1,
   and a Piezo speaker on pin 13 (PWM).
   
   Enjoy,

*/
#include <LiquidCrystal.h>
// LiquidCrystal display
// You can use any Hitachi HD44780 compatible. Wiring explained at
// http://www.arduino.cc/en/Tutorial/LiquidCrystal
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);

// Steering wheel potentiometer
const int POTPIN = 1;
const int MAXPOT = 800; // no need to turn the wheel all the way to 1023 :)

// Piezo speaker
const int SPEAKERPIN = 13;//you can see the led flash when u crash

const int RANDSEEDPIN = 0; // an analog pin that isn't connected to anything

const int MAXSTEPDURATION = 300; // Start slowly, each step is 1 millisec shorter.
const int MINSTEPDURATION = 150; // This is as fast as it gets

const int NGLYPHS = 6;
// the glyphs will be defined starting from 1 (not 0),
// to enable lcd.print() of null-terminated strings
byte glyphs[NGLYPHS][8] = {
  // 1: car up
  { B00000,
    B01110,
    B11111,
    B01010,
    B00000,
    B00000,
    B00000,
    B00000}
  // 2: car down
  ,{B00000,
    B00000,
    B00000,
    B00000,
    B01110,
    B11111,
    B01010,
    B00000}
  // 3: truck up
  ,{B00000,
    B11110,
    B11111,
    B01010,
    B00000,
    B00000,
    B00000,
    B00000}
  // 4: truck down
  ,{B00000,
    B00000,
    B00000,
    B00000,
    B11110,
    B11111,
    B01010,
    B00000}
  // 5: crash up
  ,{B10101,
    B01110,
    B01110,
    B10101,
    B00000,
    B00000,
    B00000,
    B00000}
  // 6: crash down
  ,{B00000,
    B00000,
    B00000,
    B10101,
    B01110,
    B01110,
    B10101,
    B00000}
};

const int NCARPOSITIONS = 4;

// Each position is mapped to a column of 2 glyphs
// Used to make sense when I had a 5th position
// where car or crash was drawn as 2 glyphs
// (can't do that since 0 terminates strings),
// so it's kinda silly now, but it ain't broke :)
const char BLANK=32;
char car2glyphs[NCARPOSITIONS][2] = {
  {1,BLANK},{2,BLANK},{BLANK,1},{BLANK,2}
};
char truck2glyphs[NCARPOSITIONS][2] = {
  {3,BLANK},{4,BLANK},{BLANK,3},{BLANK,4}
};
char crash2glyphs[NCARPOSITIONS][2] = {
  {5,BLANK},{6,BLANK},{BLANK,5},{BLANK,6}
};

const int ROADLEN = 15; // LCD width (not counting our car)
int road[ROADLEN]; // positions of other cars
char line_buff[2+ROADLEN]; // aux string for drawRoad()
int road_index;
int car_pos;
// Off-the-grid position means empty column, so MAXROADPOS
// determines the probability of a car in a column
// e.g. 3*NCARPOSITIONS gives p=1/3
const int MAXROADPOS = 3*NCARPOSITIONS;
int step_duration;

int crash; // true if crashed
unsigned int crashtime; // millis() when crashed
const int CRASHSOUNDDURATION = 250;

const char *INTRO1="Trucks ahead,";
const char *INTRO2="Drive carefully";
const int INTRODELAY = 2000;

void setup()
{
  crash = crashtime = road_index = 0;
  step_duration = MAXSTEPDURATION;
  line_buff[1+ROADLEN] = '\0'; // null terminate it
  randomSeed(analogRead(RANDSEEDPIN));
  for (int i=0; i<NGLYPHS; i++) {
    lcd.createChar(i+1,glyphs[i]);
  }
  for (int i=0; i<ROADLEN; i++) {
    road[i]=-1;
  }
  pinMode(SPEAKERPIN,OUTPUT);
  analogWrite(SPEAKERPIN,0); // to be on the safe side
  lcd.begin(16,2);
  getSteeringWheel();
  drawRoad();
  lcd.setCursor(1,0);
  lcd.print(INTRO1);
  lcd.setCursor(1,1);
  lcd.print(INTRO2);
  delay(INTRODELAY);
}

void loop() {
  unsigned long now = millis()-INTRODELAY;
  if (!crash) {
    getSteeringWheel();
    crash = (car_pos==road[road_index]);
  }
  if (crash) {
    if (!crashtime) {
      crashtime=now;
      drawRoad();
      // Game over text
      // (keep first 2 "crash" columns intact)
      lcd.setCursor(2,0);
      lcd.print("Crashed after");
      lcd.setCursor(2,1);
      lcd.print(now/1000);
      lcd.print(" seconds.");
    }
    if ((now-crashtime)<CRASHSOUNDDURATION) {
      analogWrite(SPEAKERPIN,random(255)); // white noise
    } 
    else {
      analogWrite(SPEAKERPIN,0); // dramatic post-crush silence :)   
    }
    delay(10); // Wait a bit between writes
  } 
  else {

    int prev_pos = road[(road_index-1)%ROADLEN];
    int this_pos = random(MAXROADPOS);
    while (abs(this_pos-prev_pos)<2) { // don't jam the road
      this_pos = random(MAXROADPOS);
    }
    road[road_index] = this_pos;
    road_index = (road_index+1)%ROADLEN;
    drawRoad();
    delay(step_duration);
    if (step_duration>MINSTEPDURATION) {
      step_duration--; // go faster
    }
  }
}
void getSteeringWheel() {
  car_pos = map(analogRead(POTPIN),0,1024,0,NCARPOSITIONS);
}

void drawRoad() {
  for (int i=0; i<2; i++) {
    if (crash) {
      line_buff[0]=crash2glyphs[car_pos][i];
    } 
    else {
      line_buff[0]=car2glyphs[car_pos][i];
    }
    for (int j=0; j<ROADLEN; j++) {
      int pos = road[(j+road_index)%ROADLEN];
      line_buff[j+1] = pos>=0 && pos<NCARPOSITIONS ? truck2glyphs[pos][i] : BLANK;
    }
    lcd.setCursor(0,i);
    lcd.print(line_buff);
  }
}