hmkim
Published © CC BY-SA

8x8 Matrix LED Snake Game (Smartphone Motion)

This is the snake game for PHPoC Arduino Shield (P4S-347/348) by a gyro sensor of smartphone.

BeginnerFull instructions provided5 hours13,242
8x8 Matrix LED Snake Game (Smartphone Motion)

Things used in this project

Story

Read more

Schematics

Connections

LED ----- PHPoC Shield
VCC ----- 5V
GND ----- GND
SDA ----- A4(SDA)
SCL ----- A5(SCL)

Code

PHPoC Shield source code

HTML
1. Upload PHPoC Shield source code
Please refert to the manual of PHPoC Debugger below and upload the source code(snake_game_gyro.php).
http://www.phpoc.com/support/manual/phpoc_debugger_manual/contents.php?id=major_upload

- snake_game_gyro.php
<!DOCTYPE html>
<html>
<head>
<title>PHPoC Shield - Snake Game</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7">
<style>
body { font-family: verdana, Helvetica, Arial, sans-serif, gulim; font-weight: bold; text-align: center; }
h1 { font-size: 25pt; }
h2 { font-size: 15pt; }
#remote { margin:0 auto; width: 500px; background: #333; border-radius: 2%; }
.direct { 
	display: inline-block; width: 100px; height: 100px;  
	font-size: 50px; color: white; line-height: 90px;
	background: #eee; margin: 8px; border-radius: 10%;
	text-align: center; font-weight: bold; 
	margin: 10px 60px;
}
</style>
<script>
var ws;
var button;
	
function init()
{	
	if(ws == null)
	{
		ws = new WebSocket("ws://<?echo _SERVER("HTTP_HOST")?>/snake", "text.phpoc");
		document.getElementById("ws_state").innerHTML = "CONNECTING";
		
		ws.onopen = ws_onopen;
		ws.onclose = ws_onclose;
		ws.onmessage = ws_onmessage; 
	}
	else
		ws.close();
}
function connect_onclick()
{
	if(ws == null)
	{
		var ws_host_addr = "<?echo _SERVER("HTTP_HOST")?>";
		//var debug = document.getElementById("debug");

		if((navigator.platform.indexOf("Win") != -1) && (ws_host_addr.charAt(0) == "["))
		{
			// network resource identifier to UNC path name conversion
			ws_host_addr = ws_host_addr.replace(/[\[\]]/g, '');
			ws_host_addr = ws_host_addr.replace(/:/g, "-");
			ws_host_addr += ".ipv6-literal.net";
		}

		//debug.innerHTML = "<br>" + navigator.platform + " " + ws_host_addr;
		ws = new WebSocket("ws://" + ws_host_addr + "/snake", "text.phpoc");

		document.getElementById("ws_state").innerHTML = "CONNECTING";

		ws.onopen = ws_onopen;
		ws.onclose = ws_onclose;
		ws.onmessage = ws_onmessage;
	}
	else
		ws.close();
}
function ws_onopen()
{
	document.getElementById("ws_state").innerHTML = "<font color='blue'>CONNECTED</font>";
	document.getElementById("bt_connect").innerHTML = "Disconnect";
}
function ws_onclose()
{
	document.getElementById("ws_state").innerHTML = "<font color='gray'>CLOSED</font>";
	document.getElementById("bt_connect").innerHTML = "Connect";

	ws.onopen = null;
	ws.onclose = null;
	ws.onmessage = null;
	ws = null;
}
function ws_onmessage(e_msg)
{
	e_msg = e_msg || window.event; // MessageEvent

	alert("msg : " + e_msg.data);
}

var beta = 0;
var gamma = 0;
var resolution = 2;
 
if (window.DeviceOrientationEvent) 
{
    window.addEventListener('deviceorientation', orientationUpdate, true);
}
 
function orientationUpdate(event)
{    

    if(Math.abs((event.beta - beta)) > resolution)
        beta = event.beta;
 
    if(Math.abs((event.gamma - gamma)) > resolution)
        gamma = event.gamma;
    
	//var debug = document.getElementById("debug");
	//debug.innerHTML = beta + "/" + gamma;
	
	for (i=0; i<4; i++)
	{
		button = document.getElementById(i);
		button.style.backgroundColor = "grey";			
	}

	if (beta < 0) // top 
	{		
		button = document.getElementById(0);
		button.style.backgroundColor = "#E9FF26";
    	ws.send("0");
	}
	else if (gamma < -35 && beta < 50) // left
	{		
		button = document.getElementById(1);
		button.style.backgroundColor = "#E9FF26";
   	 	ws.send("1");
	}
    else if (gamma > 35 && beta < 50) // right
    {
		button = document.getElementById(2);
		button.style.backgroundColor = "#E9FF26";
    	ws.send("2");
	}
   	else if (beta > 60) // bottom
   	{
		button = document.getElementById(3);
		button.style.backgroundColor = "#E9FF26";
    	ws.send("3");	
	} 
	
}
window.onload = init;
</script>
</head>

<body>
<h1>Snake Game</h1>
<br /><br />
<div id="remote">
	<div class="direct" id="0"></div><br />
	<div class="direct" id="1"></div>
	<div class="direct" id="2"></div><br />
	<div class="direct" id="3"></div>
</div>
<br /><br />
<h2>WebSocket <font id="ws_state" color="gray">CLOSED</font></h2>
<button id="bt_connect" type="button" onclick="connect_onclick();">Connect</button>
<span id="debug"></span>
</body>
</html>

Arduino Source code

Arduino
2. Upload Arduino source code
- Add Arduino library
Please add releted libraries from [Sketch] > [Include Library] > [Manager Libraries...]
Adafruit_LEDBackpack library, Adafruit-GFX-Library, PHPoC Library
(Learn more : https://learn.adafruit.com/adafruit-led-backpack/bi-color-8x8-matrix)

- Upload Arduino sketch
/*************************************************** 
  This is a library for our I2C LED Backpacks

  Designed specifically to work with the Adafruit LED Matrix backpacks 
  ----> http://www.adafruit.com/products/872
  ----> http://www.adafruit.com/products/871
  ----> http://www.adafruit.com/products/870

  These displays use I2C to communicate, 2 pins are required to 
  interface. There are multiple selectable I2C addresses. For backpacks
  with 2 Address Select pins: 0x70, 0x71, 0x72 or 0x73. For backpacks
  with 3 Address Select pins: 0x70 thru 0x77

  Adafruit invests time and resources providing this open source code, 
  please support Adafruit and open-source hardware by purchasing 
  products from Adafruit!

  Written by Limor Fried/Ladyada for Adafruit Industries.  
  BSD license, all text above must be included in any redistribution
 ****************************************************/

// Snake on 8x8Matrix 
// 2013-06-15 JorgVisch (http://fritzing.org/projects/snake-8x8-led-matrix-ada-fruit)
// 2017-04-12 Amy Kim

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_LEDBackpack.h>
#include "SPI.h"
#include "Phpoc.h"

PhpocServer server(80);

// LED face
static const uint8_t PROGMEM
  smile_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10100101,
    B10011001,
    B01000010,
    B00111100 },
  frown_bmp[] =
  { B00111100,
    B01000010,
    B10100101,
    B10000001,
    B10011001,
    B10100101,
    B01000010,
    B00111100 };
    
// direction
const int TOP    = 0;
const int RIGHT  = 1;
const int BOTTOM = 2;
const int LEFT   = 3;

// Snake
const int MAX_SNAKE_LENGTH = 15;

// Variables
Adafruit_BicolorMatrix matrix = Adafruit_BicolorMatrix();   // Display
int direction = TOP;                               // direction of movement
int snakeX[MAX_SNAKE_LENGTH];                      // X-coordinates of snake
int snakeY[MAX_SNAKE_LENGTH];                      // Y-coordinates of snake
int snakeLength = 1;                               // nr of parts of snake
unsigned long prevTime = 0;                        // for gamedelay (ms)
unsigned long delayTime = 500;                     // Game step in ms

int fruitX, fruitY;
unsigned long fruitPrevTime = 0;
unsigned long fruitBlinkTime = 1000/250;
int fruitLed = LED_RED;
int matrixColor;
  
void setup(){
  Serial.begin(9600);
  while(!Serial)
    ;

  Phpoc.begin(PF_LOG_SPI | PF_LOG_NET);
  server.beginWebSocket("snake");
 
  Serial.print("WebSocket server address : ");
  Serial.println(Phpoc.localIP());  

  Serial.println("Game is started.");
  randomSeed(analogRead(0));
  
  // Init led matrix  
  matrix.begin(0x70);  
  matrix.setRotation(3); 
  
  // init snake
  snakeX[0] = 4;
  snakeY[0] = 7;
  for(int i=1; i<MAX_SNAKE_LENGTH; i++)
    snakeX[i] = snakeY[i] = -1;
  
  makeFruit();
 
  printString("S");
}

void loop(){
    checkButtons();
    
    unsigned long currentTime = millis();
    if(currentTime - prevTime >= delayTime)
    {
      nextstep(); 
      prevTime = currentTime;
    }
    
    draw();      
}

void checkButtons(){

  // wait for a new client:
  PhpocClient client = server.available();
  
  if (client) 
  {
    if (client.available() > 0) 
    {
      // read the bytes incoming from the client:
      char thisChar = client.read();
      
      if(thisChar == '0')
        direction = TOP;
      if(thisChar == '1')
        direction = LEFT;
      if(thisChar == '2')
        direction = RIGHT;
      if(thisChar == '3')
        direction = BOTTOM;   
    }
  }
}

void draw(){
  matrix.clear();
  drawSnake();
  drawFruit();
  matrix.writeDisplay();
}

void drawSnake(){
  for(int i=0; i<snakeLength; i++)
    matrix.drawPixel(snakeX[i], snakeY[i], LED_GREEN);  
}

void drawFruit(){
  if(inPlayField(fruitX, fruitY)){
    unsigned long currenttime = millis();
    if(currenttime - fruitPrevTime >= fruitBlinkTime)
    {
      fruitLed = (fruitLed == LED_RED) ? LED_OFF : LED_RED;
      fruitPrevTime = currenttime;
    }
    matrix.drawPixel(fruitX, fruitY, fruitLed);
  }
}

boolean inPlayField(int x, int y){
  return (x>=0) && (x<8) && (y>=0) && (y<8);
}

void nextstep(){  
  for(int i = snakeLength; i > 0; i--)
  {
    if((direction == RIGHT) && (snakeX[0]-snakeLength == 7))
      snakeX[0] = -1;
    else if((direction == LEFT) && (snakeX[0]+ snakeLength == 0))
      snakeX[0] = 8;
    else 
      snakeX[i] = snakeX[i-1];
    
    if((direction == TOP) && (snakeY[0]+snakeLength == 0))
      snakeY[0] = 8;
    else if((direction == BOTTOM) && (snakeY[0]-snakeLength == 7))
      snakeY[0] = -1;
    else 
      snakeY[i] = snakeY[i-1];      
  }
  
  switch(direction)
  {
    case TOP:
      snakeY[0] = snakeY[0]-1;
      break;
    case RIGHT:
      snakeX[0] = snakeX[0]+1;
      break;
    case BOTTOM:
      snakeY[0] = snakeY[0]+1;
      break;
    case LEFT:
      snakeX[0]=snakeX[0]-1;
      break;
  }
  
  if((snakeX[0] == fruitX) && (snakeY[0] == fruitY))
  {
    snakeLength++;
    if(snakeLength < MAX_SNAKE_LENGTH)
      makeFruit();
    else 
      fruitX = fruitY = -1;
   
  }
  snakeCheck();  
}

void makeFruit(){
  int x, y;
  x = random(0, 8);
  y = random(0, 8);
  while(isPartOfSnake(x, y)){
    x = random(0, 8);
    y = random(0, 8);
  }
  fruitX = x;
  fruitY = y;
}

boolean isPartOfSnake(int x, int y){
  for(int i=0; i<snakeLength-1; i++)
  {
    if((x == snakeX[i]) && (y == snakeY[i]))
      return true;
  }
  return false;
}

void snakeCheck(){  
    for(int i=1; i<snakeLength; i++)
    {
      // snake touches itself
      if((snakeX[0] == snakeX[i]) && (snakeY[0] == snakeY[i])) 
        userLose();
    }
    if (snakeLength == MAX_SNAKE_LENGTH)
      userWin();
}

void userLose(){
  Serial.println("Game Over");
  printString("O");
  
  matrix.clear();
  matrix.drawBitmap(0, 0, frown_bmp, 8, 8, LED_RED);
  matrix.writeDisplay();
  delay(1000);

  snakeLength = 1;
  setup();
  loop();
}

void userWin(){
  Serial.println("You Win");
  printString("W");
  
  matrix.clear();
  matrix.drawBitmap(0, 0, smile_bmp, 8, 8, LED_GREEN);
  matrix.writeDisplay();
  delay(1000);  
    
  snakeLength = 1;
  setup();
  loop();
}

void printString(String str){
  String matrixComment;

  matrix.setTextWrap(false);  // we dont want text to wrap so it scrolls nicely
  matrix.setTextSize(1);

  if (str == "O")
  {
    matrixComment = "Game Over!";
    matrixColor = LED_RED;
  }
  else if (str == "W")
  {
    matrixComment = "You Win!";
    matrixColor = LED_GREEN;  
  }
  else if (str == "S")
  {
    matrixComment = "Go!";
    matrixColor = LED_YELLOW;  
  }
  else 
    matrixColor = LED_YELLOW;
  
  matrix.setTextColor(matrixColor);
  
  for (int8_t x=7; x>=-60; x--) 
  {
    matrix.clear();
    matrix.setCursor(x,0);
    matrix.print(matrixComment);
    matrix.writeDisplay();
    delay(70);
  }  
}

Credits

hmkim

hmkim

1 project • 24 followers

Comments