Snippet - FEZ Medus - Snake Game

I just posted FEZ Medus - Snake Game on Codeshare. Feel free to discuss and make suggestions here.

6 Likes

Looks like I cannot edit this post and correct the title. “Medusa” lost it’s “a” during upload. :frowning:

With all this stuff you do it’s obvious your computer can’t keep up with your typing speed

:slight_smile:

I need to upgrade my computer. :smiley:

Very sweet. Can you please add arduino tag as well?

Done!

Hi @ Architect

I tried your snake game using the latest SDK. As you probably know, some names have changed etc. So adapted it as best as I could, but when I run it my N18 screen just shows black and white specks. Can you perhaps see what I’m doing wrong?

Below is your code that I modified to comply with the latest SDK:


//Copyright (C) 2013 Valentin Ivanov http://www.breakcontinue.com.
//
//This work is licensed under a Creative Commons 
//Attribution-NonCommercial-ShareAlike 3.0 Unported License.
//See http://creativecommons.org/licenses/by-nc-sa/3.0/
//
//All other rights reserved.
//
//THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, 
//EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED 
//WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.



 #include <Wire.h>
 #include <SPI.h>

 #include <Gadgeteering.h>

//Make sure to uncomment the mainboard you are using below.

//#include <Mainboards/FEZMedusaShield3D.h>
//#include <Mainboards/FEZMedusaShield.h>
//#include <Mainboards/FEZMedusaS12.h>
 #include <Mainboards/FEZMedusaMini.h>
 #include <Modules/IO60P16.h>
 #include <Modules/DisplayN18.h>
 #include <Modules/Joystick.h>
 #include <Modules/Button.h>

using namespace gadgeteering;
using namespace gadgeteering::mainboards;
using namespace gadgeteering::modules;



fez_medusa_mini board;

//FEZMedusa board;
display_n18* display;
joystick* joyst;

byte width = 128;
byte height = 160;

short snake_body[256];
short snake_length = 3;
byte SQUARE_SIZE = 3;
byte COLUMNS = 32;
byte ROWS = 40;

byte LEFT = 0;
byte RIGHT = 1;
byte UP = 2;
byte DOWN = 3;

byte snake_direction = LEFT; 

byte bonus_x, bonus_y;

unsigned long loopStartTime = 0;

void setup() {

   Serial.begin(9600);

   display = new display_n18(1);
   joyst = new joystick(3);

   randomSeed(analogRead(0));

   reset_game();
}

void loop() {

   read_joystick();


   if( millis() - loopStartTime > 200 )
   {

      if( move_snake() )
      {
         clear_field();

         reset_game();
         return;
      }

      int headX = snake_body[0]>>8;
      int headY = snake_body[0]&0x00FF;

      if (headX == bonus_x && headY == bonus_y)
      {
         snake_body[snake_length++] = snake_body[snake_length-1];
         snake_body[snake_length++] = snake_body[snake_length-1];

         new_bonus();
      }

      render();
      loopStartTime  = millis();
   }
}


void reset_game()
{
   byte startX = 15;
   byte startY = 20;

   snake_body[0] = startX << 8 | startY;
   snake_body[1] = (startX) << 8 | (startY+1);
   snake_body[2] = (startX) << 8 | (startY+2);
   snake_length = 3;

   new_bonus();

   loopStartTime = 0;

   snake_direction = LEFT;

   render();
}

void new_bonus()
{
   bonus_x = random(COLUMNS);
   bonus_y = random(ROWS);
}

void draw_snake()
{
   byte x, y;
   for( int i = 0; i< snake_length; i++ )
   {
      x= (snake_body[i] >> 8) * (SQUARE_SIZE + 1);
      y= (snake_body[i] & 0x00FF)* (SQUARE_SIZE + 1);
      display->fill_rect( x , y , SQUARE_SIZE, SQUARE_SIZE, display_n18::rgb_to_short(255, 0, 0)); 
   }
}

void draw_bonus()
{
   display->fill_rect( bonus_x*(SQUARE_SIZE+1) , bonus_y*(SQUARE_SIZE+1) , SQUARE_SIZE, SQUARE_SIZE, display_n18::rgb_to_short(0, 0, 255));   
}

boolean move_snake()
{

   //"Erase" tale here
   display->fill_rect( (snake_body[snake_length - 1] >> 8) * (SQUARE_SIZE + 1) , (snake_body[snake_length - 1] & 0x00FF)* (SQUARE_SIZE + 1) , SQUARE_SIZE, SQUARE_SIZE, display_n18::rgb_to_short(0, 0, 0)); 

   for (int i = snake_length - 1; i > 0; i--)
      snake_body[i] = snake_body[i-1];

   int headX = snake_body[0]>>8;
   int headY = snake_body[0]&0x00FF;

   switch (snake_direction)
   {
   case 0:
      headX -= 1;
      break;
   case 1:
      headX += 1;
      break;
   case 2:
      headY -= 1;
      break;
   case 3:
      headY += 1;
      break;
   }

   if (headX < 0)
      headX = COLUMNS-1;

   if (headX >= COLUMNS )
      headX = 0;

   if (headY < 0)
      headY = ROWS-1;

   if (headY >= ROWS)
      headY = 0;

   snake_body[0] = headX<<8|headY; 

   for (int i = 1; i < snake_length - 1; i++)
   {
      if (headX == (snake_body[i]>>8) && headY == (snake_body[i] & 0x00FF))
         return true;
   }

   return false;  
}

void read_joystick()
{
   int xVal = (int)(joyst->get_x() * 10.0);
   int yVal = (int)(joyst->get_y() * 10.0);

   if( xVal < 2 )
      snake_direction = LEFT;
   else if( xVal > 8 )
      snake_direction = RIGHT;
   else if( yVal > 8 )
      snake_direction = UP;
   else if( yVal < 2 )
      snake_direction = DOWN;

}

void render()
{
   draw_snake();
   draw_bonus();
}

void clear_field()
{
   byte x, y;
   for( int i = 0; i< snake_length; i++ )
   {
      x= (snake_body[i] >> 8) * (SQUARE_SIZE + 1);
      y= (snake_body[i] & 0x00FF)* (SQUARE_SIZE + 1);
      display->fill_rect( x , y , SQUARE_SIZE, SQUARE_SIZE, display_n18::rgb_to_short(0, 0, 0)); 
   }

   display->fill_rect( bonus_x*(SQUARE_SIZE+1) , bonus_y*(SQUARE_SIZE+1) , SQUARE_SIZE, SQUARE_SIZE, display_n18::rgb_to_short(0, 0, 0));     
} 

@ KiwiSaner, those white specs are probably the display showing random data because it was never initialized. That is usually a sign that there is a problem in the code. Since we cannot throw exceptions on the Medusa, we repeatedly print to the serial line when an error occurs. If you ever suspect that, just open the serial window and see if anything is displayed. When I run the code you posted, I see:

ERROR: 13-0
ON: …\Arduino\libraries\Gadgeteering\src\Mainboards\FEZMedusaMini.cpp(357)

When you look at that code, it seems fine on the face of it. And it is. You’ll find the only real way to easily debug is to place Serial.println or system::print statements in the code. After doing that for a bit, I narrowed it down to fill_rect in DisplayN18.cpp. The buffer allocation in there is running out of memory, so it is throwing everything else off and eventually it corrupts the spi channel so you get that exception. The real problem is in DisplayN18.h, around line 27. The #ifdef is incorrect. Since memory is so low on the Medusa, we need to draw in smaller chunks, hence the STEP of 1. But the incorrect #ifdef is giving a step of 12, which tries to allocate 240 bytes and fails. The proper #ifdef on line 27 should read #if (defined ARDUINO_AVR_UNO || defined ARDUINO_AVR_MEDUSA) instead. I did just push the changes to the repository in this commit: https://bitbucket.org/ghi_elect/gadgeteering/commits/00bc8e084139a59dd8040d86ef29ebf2c07e926c if you want to take a look.

@ John - Wow John. That was a very quick response, and after I updated the files from bitbucket actually works now! :clap: Thank you so much for the excellent support. Also well done to Architect for creating it.

This is actually an excellent example program to show off the FEZ Medusa Starter Kit, especially if you have the acrylic enclosure like I do.

@ KiwiSaner - glad you got it running. And thanks to @ John for providing the fix so quickly!

One note about the game. The snake array is of a fixed length. The snake can be bigger than the length of the array, so this part has to be changed if you are a snake master. :smiley:

@ Architect - No worries mate. For me, the value in this demo was more about having a working example for the Fez Mini that uses the N18 display and the joystick. than about playing the game itself. Still… quite impressive that you could do the game in such little code.

Hey Architect,
would you mind uploading the code for the latest sdk for the Fez Medusa S12 Board.