KIT INCLUDES:
- Arduino Nano with USB Cable – 1
- LCD 16*2 Display – 1 (yellow)
- Arduino Joystick module – 1
- Jumper Wire (Male to Male) – 40 pieces
- Jumper Wire (Male to Female) – 40 pieces
- Potentiometer 10k – 1
- Breadboard 400 points – 1
Introduction
In today’s tutorial, we will make a Snake maze game using a 16*2 LCD display and Ps2 Joystick module with Arduino Nano. This is one of the most popular game of our childhood. This project is based on 16*2 LCD which gives a little room for a snake.
HARDWARE REQUIRED
- Arduino Nano with USB Cable – 1
- LCD 16*2 Display – 1Â (yellow)
- Arduino Joystick module – 1
- Jumper Wire (Male to Male) – 40 pieces
- Jumper Wire (Male to Female) – 40 pieces
- Potentiometer 10k – 1
- Breadboard 400 points – 1
SOFTWARE REQUIRED
Arduino IDE 1.8.5 (programmable platform for Arduino)
Click To Download:Â https://www.arduino.cc/en/Main/Software
SPECIFICATIONS
Joystick Module
- 5V/3.3V Compatible
- Analog Output
Arduino Nano
16*2 LCD Display
- 5V power supply ( Also available for +3V)
- Negative voltage optional for +3V power supply
CIRCUIT CONNECTION
***ARDUINO to JOYSTICK***
ARDUINO Nano | JOYSTICK |
A0 | VRx |
A1 | VRy |
A2 | SW |
5v | 5v |
Gnd | Gnd |
***ARDUINO to LCD***
ARDUINO Nano | LCD |
Gnd | Vss |
5v | Vdd |
Middle pin of 10k potentiometer (Connect First pin of pot with Gnd and 3rd pin to VCC) | V0 |
Digital Pin 12 | RS |
GND | R/W |
Digital Pin 11 | E |
Digital Pin 5 | DB4 |
Digital Pin 4 | DB5 |
Digital Pin 3 | DB6 |
Digital Pin 2 | DB7 |
5v | LED+ |
GND | LED- |
To connect multiple GND and 5V wires soldering may be required or you can use a breadboard.
CODE
Run the code given below and play the game.
https://drive.google.com/open?id=1k-uWJC3eXr3v3cIpWMKx0mhjfi8y-rfG
#include <LiquidCrystal.h>
#define    JOYSTICK_X_PIN         A0
#define    JOYSTICK_Y_PIN         A1
#define    JOYSTICK_Z_PIN         A2
#define    NUM_KEYS            5
#define    JOYSTICK_RELEASED        0
#define    JOYSTICK_UP_          1
#define    JOYSTICK_DOWN_         2
#define    JOYSTICK_LEFT_         3
#define    JOYSTICK_RIGHT_         4
#define    ROWS              2
// number of indicator rows
#define    levels             4
// difficulty levels
#define    MAX_SNAKE_LENGTH        25
// maximum length of snake
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
unsigned long time, timeNow;
int gameSpeed;
boolean skip, gameOver, gameStarted;
int olddir;
int selectedLevel;
byte key=0;
byte oldkey=0;
byte Field[8*ROWS*16];
struct partdef
{
 int row,column,dir;
 struct partdef *next;
};
typedef partdef part;
part *head, *tail;
int collected;
unsigned int pc,pr;
//———————————————-
// display on the screen
void drawMatrix()
{
 boolean levelz[levels][4][16] = {
{{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false},
{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false},
{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false},
{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false}},
{{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true},
{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true},
{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true},
{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true}},
{{true,false,false,false,true,false,false,false,false,false,false,true,false,false,false,true},
{true,false,false,false,false,false,false,false,true,false,false,false,false,false,false,true},
{true,false,false,false,true,false,false,false,false,false,false,true,false,false,false,true},
{true,false,false,false,false,false,false,false,true,false,false,false,false,false,false,true}},
{{true,false,true,false,false,false,false,false,false,true,false,false,false,true,false,false},
{false,false,false,false,true,false,false,true,false,false,false,true,false,false,false,true},
{true,false,true,false,false,false,false,false,false,true,false,false,false,true,false,false},
{false,false,false,false,true,false,false,true,false,false,false,true,false,false,false,true}}
};
 byte myChar[8];
 boolean special;
 int cc=0;
Â
 if (!gameOver)
 {
 ChangeDot(pr, pc, true);
Â
 for(int r=0;r<ROWS;r++)
 {  Â
  for(int c=0;c<16;c++)
  {
   special = false;
   for(int i=0;i<8;i++)
   {
    byte b=B00000;
    if ((Field[16 * (r*8+i) + (c*5+0)/5] & (1 << ((c*5+0) % 5))) >> ((c*5+0) % 5)) {b+=B10000; special = true;}
    if ((Field[16 * (r*8+i) + (c*5+1)/5] & (1 << ((c*5+1) % 5))) >> ((c*5+1) % 5)) {b+=B01000; special = true;}
    if ((Field[16 * (r*8+i) + (c*5+2)/5] & (1 << ((c*5+2) % 5))) >> ((c*5+2) % 5)) {b+=B00100; special = true;}
    if ((Field[16 * (r*8+i) + (c*5+3)/5] & (1 << ((c*5+3) % 5))) >> ((c*5+3) % 5)) {b+=B00010; special = true;}
    if ((Field[16 * (r*8+i) + (c*5+4)/5] & (1 << ((c*5+4) % 5))) >> ((c*5+4) % 5)) {b+=B00001; special = true;}    Â
Â
    myChar[i] = b;
   }
   if (special)
   {
    lcd.createChar(cc, myChar);
    lcd.setCursor(c,r);
    lcd.write(byte(cc));
 cc++;
   }
   else
   {
    lcd.setCursor(c,r);
    if (levelz[selectedLevel][r][c]) lcd.write(255);
    else lcd.write(128);
   }
  }
 }
 }
}
//———————————-
void freeList()
{
 part *p,*q;
 p = tail;
 while (p!=NULL)
 {
  q = p;
  p = p->next;
  free(q);
 }
 head = tail = NULL;
}
//———————————-
void gameOverFunction()
{
 delay(1000);
 lcd.clear();
 freeList();
 lcd.setCursor(3,0);
 lcd.print(“Game Over!”);
 lcd.setCursor(4,1);
 lcd.print(“Score: “);
 lcd.print(collected);
 delay(15000);
}
//———————————-
void growSnake()
{
 part *p;
 p = (part*)malloc(sizeof(part));
 p->row = tail->row;
 p->column = tail->column;
 p->dir = tail->dir;
 p->next = tail;
 tail = p;
}
//———————————-
// a new dot on the screen
void newPoint()
{
 boolean levelz[levels][4][16] = {
{{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false},
{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false},
{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false},
{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false}},
{{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true},
{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true},
{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true},
{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true}},
{{true,false,false,false,true,false,false,false,false,false,false,true,false,false,false,true},
{true,false,false,false,false,false,false,false,true,false,false,false,false,false,false,true},
{true,false,false,false,true,false,false,false,false,false,false,true,false,false,false,true},
{true,false,false,false,false,false,false,false,true,false,false,false,false,false,false,true}},
{{true,false,true,false,false,false,false,false,false,true,false,false,false,true,false,false},
{false,false,false,false,true,false,false,true,false,false,false,true,false,false,false,true},
{true,false,true,false,false,false,false,false,false,true,false,false,false,true,false,false},
{false,false,false,false,true,false,false,true,false,false,false,true,false,false,false,true}}
};
Â
 part *p;
 p = tail;
 boolean newp = true;
 while (newp)
 {
  pr = random(8*ROWS);
  pc = random(80);
  newp = false;
  if (levelz[selectedLevel][pr / 8][pc / 5]) newp=true;
  while (p->next != NULL && !newp)
  {
   if (p->row == pr && p->column == pc) newp = true;
   p = p->next;
  }
 }
Â
 if (collected < MAX_SNAKE_LENGTH && gameStarted) growSnake();
}
//———————————-
// head movement
void moveHead()
{
 boolean levelz[levels][4][16] = {
{{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false},
{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false},
{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false},
{false,false,false,false,false,false,false,false,false,false,false,false,false,false,false,false}},
{{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true},
{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true},
{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true},
{true,false,false,false,false,false,false,false,false,false,false,false,false,false,false,true}},
{{true,false,false,false,true,false,false,false,false,false,false,true,false,false,false,true},
{true,false,false,false,false,false,false,false,true,false,false,false,false,false,false,true},
{true,false,false,false,true,false,false,false,false,false,false,true,false,false,false,true},
{true,false,false,false,false,false,false,false,true,false,false,false,false,false,false,true}},
{{true,false,true,false,false,false,false,false,false,true,false,false,false,true,false,false},
{false,false,false,false,true,false,false,true,false,false,false,true,false,false,false,true},
{true,false,true,false,false,false,false,false,false,true,false,false,false,true,false,false},
{false,false,false,false,true,false,false,true,false,false,false,true,false,false,false,true}}
};
Â
Â
 switch(head->dir) // 1 step in direction
 {
  case 0: head->row–; break;
  case 1: head->row++; break;
  case 2: head->column++; break;
  case 3: head->column–; break;
  default : break;
 }
 if (head->column >= 80) head->column = 0;
 if (head->column < 0) head->column = 79;
 if (head->row >= (8*ROWS)) head->row = 0;
 if (head->row < 0) head->row = (8*ROWS – 1);
Â
 if (levelz[selectedLevel][head->row / 8][head->column / 5]) gameOver = true; // wall collision check
Â
 part *p;
 p = tail;
 while (p != head && !gameOver) // self collision
 {
  if (p->row == head->row && p->column == head->column) gameOver = true;
  p = p->next;
 }
 if (gameOver)
  gameOverFunction();
 else
 {
 ChangeDot(head->row, head->column, true);
Â
 if (head->row == pr && head->column == pc) // point pickup check
 {
  collected++;
  if (gameSpeed < 25) gameSpeed+=3;
  newPoint();
 }
 }
}
//———————————-
// funny move
void moveAll()
{
 part *p;
 p = tail;
 ChangeDot(p->row, p->column, false);
Â
 while (p->next != NULL)
 {
  p->row = p->next->row;
  p->column = p->next->column;
  p->dir = p->next->dir;
  p = p->next;
 }
 moveHead();
}
//———————————-
// create a snake
void createSnake(int n) // n = size of snake
{
 for (unsigned int i=0;i<(8*ROWS*16);i++)
  Field[i] = 0;
 Â
 part *p, *q;
 tail = (part*)malloc(sizeof(part));
 tail->row = 7;
 tail->column = 39 + n/2;
 tail->dir = 3;
 q = tail;
Â
 ChangeDot(tail->row, tail->column, true);
Â
 for (int i = 0; i < n-1; i++) // build snake from tail to head
 {
  p = (part*)malloc(sizeof(part));
  p->row = q->row;
  p->column = q->column – 1; //initial snake id placed horizoltally
 Â
  ChangeDot(p->row, p->column, true);
 Â
  p->dir = q->dir;
  q->next = p;
  q = p;
 }
 if (n>1)
 {
  p->next = NULL;
  head  = p;
 }
 else
 {
  tail->next = NULL;
  head = tail;
 }
}
void startF()
{
 byte mySnake[8][8] =
{
{ B00000,
 B00000,
 B00011,
 B00110,
 B01100,
 B11000,
 B00000,
},
{ B00000,
 B11000,
 B11110,
 B00011,
 B00001,
 B00000,
 B00000,
},
{ B00000,
 B00000,
 B00000,
 B00000,
 B00000,
 B11111,
 B01110,
},
{ B00000,
 B00000,
 B00011,
 B01111,
 B11000,
 B00000,
 B00000,
},
{ B00000,
 B11100,
 B11111,
 B00001,
 B00000,
 B00000,
 B00000,
},
{ B00000,
 B00000,
 B00000,
 B11000,
 B01101,
 B00111,
 B00000,
},
{ B00000,
 B00000,
 B01110,
 B11011,
 B11111,
 B01110,
 B00000,
},
{ B00000,
 B00000,
 B00000,
 B01000,
 B10000,
 B01000,
 B00000,
}
};
Â
 gameOver = false;
 gameStarted = false;
 selectedLevel = 1;
Â
 lcd.clear();
 lcd.setCursor(0,0);
 lcd.print(“Select level: 1”);
 for(int i=0;i<8;i++)
 {
  lcd.createChar(i,mySnake[i]);
  lcd.setCursor(i+4,1);
  lcd.write(byte(i));
 }
 lcd.setCursor(2,1);
 lcd.print(“Rees52 PYTHON”);
 delay(15000);
Â
 collected = 0;
 gameSpeed = 8;
 createSnake(3);
 time = 0;
}
//———————————-
void setup()
{
 digitalWrite(JOYSTICK_Z_PIN, HIGH);
 Â
 lcd.begin(16, ROWS);
 startF();
}
//———————————-
void loop()
{
 if (!gameOver && !gameStarted)
// if the game does not start
 {
  key = ScanJoyStick();
// check the joystick
  if (key != oldkey)  Â
  {
   delay(50); Â
   key = ScanJoyStick();
   if (key != oldkey)  Â
   { Â
    oldkey = key;
    if (key > 0)
    {
     olddir = head->dir;
     if (key==JOYSTICK_UP_ && selectedLevel<levels) selectedLevel++; // increase the selectable level
     else if (key==JOYSTICK_DOWN_ && selectedLevel>1) selectedLevel–;
// decrease the selectable level
    }
   }
  }
  else if (digitalRead(JOYSTICK_Z_PIN))
// if the joystick button is pressed, the beginning of the game
  {
   lcd.clear();
   selectedLevel–;
   newPoint();
   gameStarted = true;
  }
  else
// otherwise continue the display of the level of the game
  {
   lcd.setCursor(14,0);
   lcd.print(selectedLevel);
  }
 }
Â
 else if (!gameOver && gameStarted)
// if there is a game
 {
  skip = false;
 Â
  key = ScanJoyStick(); // check the joystick
  if (key != oldkey) Â
  {
   delay(50); Â
   key = ScanJoyStick();
   if (key != oldkey)  Â
   { Â
    oldkey = key;
    if (key > 0)
    {
    Â
// select the direction of movement of the snake depending on the position of the joystick
     olddir = head->dir;
     if (key==JOYSTICK_RIGHT_ && head->dir!=3) head->dir = 2;
     else if (key==JOYSTICK_UP_   && head->dir!=1) head->dir = 0;
     else if (key==JOYSTICK_DOWN_  && head->dir!=0) head->dir = 1;
     else if (key==JOYSTICK_LEFT_  && head->dir!=2) head->dir = 3;
    Â
     if (olddir != head->dir)
     {
      skip = true;
      delay(1000/gameSpeed);
      moveAll();
      drawMatrix();
     }
    }
   }
  }
  if (!skip)
  {
   timeNow = millis();
   if (timeNow – time > 1000 / gameSpeed)
   {
    moveAll();
    drawMatrix();
    time = millis();
   }
  }
 }
Â
 if(gameOver) // if the game is over
 {
  key = ScanJoyStick();// check the joystick
  if (key != oldkey) Â
  {
   delay(50); Â
   key = ScanJoyStick();
   if (key != oldkey)  Â
   { Â
    oldkey = key;
    if (key > 0)// start the game when you move the joystick in any direction
    {
     startF();
    }
   }
  }
 Â
 }
}
//———————————–
// check the joystick
byte ScanJoyStick()
{
 byte Direction = JOYSTICK_RELEASED;
 unsigned int X_Val = analogRead(JOYSTICK_X_PIN);
 unsigned int Y_Val = analogRead(JOYSTICK_Y_PIN);
Â
 if ((Y_Val >= 900) && (X_Val >= 400))
 {
  Direction = JOYSTICK_DOWN_;
 }
 else if ((Y_Val <= 400) && (X_Val >= 400))
 {
  Direction = JOYSTICK_UP_;
 }
 else if ((Y_Val >= 400) && (X_Val >= 900))
  {
  Direction = JOYSTICK_RIGHT_;
  }
 else if ((Y_Val >= 400) && (X_Val <= 400))
 {
  Direction = JOYSTICK_LEFT_;
 }
Â
 return Direction;
}
//—————————————————–
// making changes to matrix of points on eran
void ChangeDot(unsigned int RowVal, unsigned int ColVal, boolean NewVal)
{
 Field[16 * RowVal + ColVal/5] &= ~(1 << (ColVal % 5));
 if (NewVal)
  Field[16 * RowVal + ColVal/5] |= 1 << (ColVal % 5);
}
WORKING AND OUTPUT
Welcome to the Arduino based project.
After uploading the code you will see a Level 1 Python Content.now start to play. It has 4 levels in the code you can change the level of the game and if the tail and the moth of the snake will touch then the game will be over but if you complete the level then you will be automatically redirected to the next level.
Click to watch the tutorial
For more tutorials subscribe our channel REES52 on YouTube
Reviews
There are no reviews yet.