John Bradnam
Published © GPL3+

Maze Runner

An interactive animated 3D Maze puzzle. The game is built around a Nokia 5110 screen and ATtiny3224 microprocessor.

IntermediateFull instructions provided8 hours323
Maze Runner

Things used in this project

Hardware components

Microchip ATtiny3224
×1
Nokia 5110 LCD Screen
×1
Tactile Switch, Top Actuated
Tactile Switch, Top Actuated
9mm shafts and 1 button top
×5
TP4056 LIPO Battery Charger module
×1
MIC5219 LDO 3V3 Regulator
×1
Li-Ion Battary 400mAhr
×1
Other SMD components
1 x 220R 0805 Resistor, 1 x 0.1uF 0805 Capacitor 1 x 470pF 0805 Capacitor, 1 x 2.2uF 1206 Tantalum Capacitor
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

STL Files

Files for 3D printing

Schematics

Schematic

PCB

Eagle files

Schematic and PCB in Eagle format

Code

3D_Maze_V3.ino

Arduino
/*-------------------------------------------------------------------------
 3D Maze V3
 by John Bradnam 2024
 
 Original code by Hari Wiguna, 2016
 Maze Generator by Kei Takagi, 2017

 v0.4 - Draws real maze
 v0.5 - Move forward
 v0.6 - Buttons
 v0.6c - fixing front/back walls, hide what's obscured
 v0.7 - prevent walking through walls
 v0.7b - Animate the walk
 v0.8 - bigger maze
 v0.9 - Animate turning left/right
 v0.10 - Detect Success, play winning song, fixed bugs

 2024-12-09 V2 jbrad2089@gmail.com
    - Rewrote for ATtiny3224 with X-Pad
    - Added random start point in maze
    - Added low power sleep mode
    - Increased maze size
 2024-12-12 V3 jbrad2089@gmail.com
    - Added a maze generator by Kei Takagi
    - The maze size is fixed to 16x15
    - The starting point is now always at the top left
    - The exit point is now always at the bottom right
    - Displays maze and solution before play
    - Displays direction the user is facing when playing
    - Pressing of the FIRE buuton during the opening screens
      will terminate the opening sequence. This allows the
      unit to be put into sleep mode during this time.
    
 -------------------------------------------------------------------------
 Arduino IDE:
 --------------------------------------------------------------------------
  BOARD: ATtiny3224/1614/1604/814/804/414/404/214/204
  Chip: ATtiny3224
  Clock Speed: 20MHz
  millis()/micros(): "Enabled (default timer)"
  Programmer: jtag2updi (megaTinyCore)

  ATTiny3224 Pins mapped to Ardunio Pins
 
              +--------+
          VCC + 1   14 + GND
  (SS)  0 PA4 + 2   13 + PA3 10 (SCK)
        1 PA5 + 3   12 + PA2 9  (MISO)
  (DAC) 2 PA6 + 4   11 + PA1 8  (MOSI)
        3 PA7 + 5   10 + PA0 11 (UPDI)
  (RXD) 4 PB3 + 6    9 + PB0 7  (SCL)
  (TXD) 5 PB2 + 7    8 + PB1 6  (SDA)
              +--------+
  
 **************************************************************************/

//Uncomment to see start location and direction when maze initialises
//#define DEBUG

#define LCD_LED 8   //PA1
#define LCD_CLK 9   //PA2
#define LCD_DIN 7   //PB0
#define LCD_DC 1    //PA5
#define LCD_CE 3    //PA7
#define LCD_RST 5   //PB2
#define SW_DN 0     //PA4
#define SW_UP 2     //PA6
#define SW_RG 4     //PB3
#define SW_LF 6     //PB1
#define SW_FIRE 10  //PA3

#include <avr/sleep.h>

//== Screen ==
#include <LCD5110_Graph.h>      //Library for Nokia 5110 display
extern uint8_t SmallFont[];
#define MY_LCD_CONTRAST 60
#define BACKLIGHT_BRIGHTNESS 192 //0=full on, 255 = full off
#define BACKLIGHT_OFF 0
LCD5110 screen(LCD_CLK,LCD_DIN,LCD_DC,LCD_RST,LCD_CE);

uint8_t screenWidth, screenHeight;
uint8_t screenHalfWidth, screenHalfHeight;

#include "Point.h" // Handy way to pass around X and Y as one variable
#include "Maze.h"  // The maze itself and routines to check where the walls are
#include "Buttons.h" // Handles the pushbuttons
#include "Drawing.h" // Magic where the fake 3D happens

void setup(void) 
{
  pinMode(LCD_LED,OUTPUT);
  analogWrite(LCD_LED, BACKLIGHT_BRIGHTNESS);

  randomSeed(analogRead(SW_LF));
  
  screen.InitLCD();
  screen.setContrast(MY_LCD_CONTRAST);
  
  SetupDrawing();     // Get screen size, horiz vs vert ratio
  SetupButtons();     // Setup pushbutton I/O pin modes to input with internal pullup resistor
  
  attachInterrupt(digitalPinToInterrupt(SW_FIRE),switchInterrupt,CHANGE);
  goToSleep();
}

void loop(void) 
{
  CheckEscape();            // Have user reached any of the maze edges?
  if (CheckButtons())       // Handle user pushbuttons
  {
    Animate();              // Compute animation variables
    DrawMaze(dir[youDir]);  // Draw the maze (incorporating the animation parameters)
  }
  else
  {
    //Power down
    goToSleep();
  }
}

//--------------------------------------------------------------------
// Handle pin change interrupt when SWITCH is pressed
//--------------------------------------------------------------------

void switchInterrupt()
{
}

//--------------------------------------------------------------------
// Shut down LCD and put ATtiny to sleep
// Will wake up when FIRE button is pressed
//--------------------------------------------------------------------

void goToSleep() 
{
  screen.clrScr();
  screen.update();
  analogWrite(LCD_LED, BACKLIGHT_OFF);
  while (digitalRead(SW_FIRE) == LOW);  //wait until release
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);  // sleep mode is set here
  sleep_enable();
  sleep_mode();                         // System actually sleeps here
  sleep_disable();                      // System continues execution here when watchdog timed out
  while (digitalRead(SW_FIRE) == LOW);  //wait until release
  analogWrite(LCD_LED, BACKLIGHT_BRIGHTNESS);
  ResetMaze();
}
   

Maze.h

C Header File
//The maze itself and routines to check where the walls are

#define SW_FIRE 10  //PA3

#define HIGHT  15
#define WIDTH  15
uint16_t DotArea[16];   //Where maze is generated
uint16_t DotSolve[16];  //Solution for maze
uint16_t DotMaze[16];   //Final maze to display

#define MAZE_X 5
#define TEXT_X 54
#define ARROW_X 2

#define FacingNorth 0
#define FacingEast 1
#define FacingSouth 2
#define FacingWest 3

int mazeX = MAZE_X;
String dir[4] = {"N","E","S","W"};

int youRow, youCol; // Where you are in the Maze
int youDir = 0; // Facing 0=North, 1=East, 3=South, 3=West
int youRotDir = 0; // Turning -1=Left, 0=none, 1=Right
int youRowDir = 0, youColDir = 0; // Delta when walking

bool hasFrontLeftWall;
bool hasFrontWall;
bool hasFrontRightWall;
bool hasBackLeftWall;
bool hasBackWall;
bool hasBackRightWall;

bool Look(byte row, byte col)
{
  if (row < 0 || row > HIGHT || col < 0 || col >= WIDTH)
    return false;
  else
    return bitRead(DotMaze[row],15 - col);
}

void LookNorth(byte row, byte col)
{
  hasFrontLeftWall = Look(row, col - 1);
  hasFrontWall     = Look(row, col);
  hasFrontRightWall = Look(row, col + 1);
  hasBackLeftWall  = Look(row - 1, col - 1);
  hasBackWall      = Look(row - 1, col);
  hasBackRightWall = Look(row - 1, col + 1);
}

void LookEast(byte row, byte col)
{
  hasFrontLeftWall = Look(row - 1, col);
  hasFrontWall     = Look(row, col);
  hasFrontRightWall = Look(row + 1, col);
  hasBackLeftWall  = Look(row - 1, col + 1);
  hasBackWall      = Look(row,  col + 1);
  hasBackRightWall = Look(row + 1, col + 1);
}

void LookSouth(byte row, byte col)
{
  hasFrontLeftWall = Look(row, col + 1);
  hasFrontWall     = Look(row, col);
  hasFrontRightWall = Look(row, col - 1);
  hasBackLeftWall  = Look(row + 1, col + 1);
  hasBackWall      = Look(row + 1, col);
  hasBackRightWall = Look(row + 1, col - 1);
}

void LookWest(byte row, byte col)
{
  hasFrontLeftWall = Look(row + 1, col);
  hasFrontWall     = Look(row,     col);
  hasFrontRightWall = Look(row - 1, col);
  hasBackLeftWall  = Look(row + 1, col - 1);
  hasBackWall      = Look(row,     col - 1);
  hasBackRightWall = Look(row - 1, col - 1);
}

void setPixel3x3(uint8_t x,uint8_t y,uint16_t maskedVal)
{
  x = x*3;
  y = y*3;
  for (int y1=0;y1<3;y1++)
  {
    for (int x1=0;x1<3;x1++)
    {
      if (maskedVal)
      {
        screen.setPixel(x+x1+mazeX, y+y1);
      }
      else
      {
        screen.clrPixel(x+x1+mazeX, y+y1);
      }
    }
  }
}

void DisplayMaze(uint16_t* p)
{
  uint16_t mask;
  uint16_t value;
  for(int y=0;y<16;y++)
  {
    value = p[y];
    mask = 0x8000;
    for(int x=0;x<16;x++)
    {
      setPixel3x3(x,y,value & mask);
      mask = mask >> 1;
    }
  }
  screen.update();
}

void clearMaze()
{
  //Clear display
  DotArea[0] = DotSolve[0] = 0b0101111111111111;
  for (int i = 1; i < HIGHT-1; i++) 
  {
    DotArea[i] = DotSolve[i] = 0b0100000000000001;
  }
  DotArea[HIGHT-1] = DotSolve[HIGHT-1] = 0b0111111111111101;
}

void makeMaze(bool show)
{
  uint8_t val, mod;
  int8_t  x, y;

  // Maze Make
  mod = 4;
  for (int i = 2; i < HIGHT - 2; i += 2) 
  {
    for (int j = 3; j < WIDTH - 1; j += 2) 
    {
      DotArea[i] |= (0x8000 >> j);
      DotSolve[i] = DotArea[i];
      do {
        //Roll a stick
        val = (uint8_t)(random(256)) % mod;
        x = 0, y = 0;
        if (val == 0) y = 1;
        if (val == 1) x = -1;
        if (val == 2) x = 1;
        if (val == 3) y = -1;
      } while ((DotArea[i + y] & (0x8000 >> (j + x)))); 
      DotArea[i + y] |= (0x8000 >> (j + x));
      DotSolve[i + y] = DotArea[i + y];
    }
    if (show) DisplayMaze(DotArea);
    mod = 3;
  }
}

void solveMaze(bool show)
{
  uint8_t val;
  
  for (int k = 0; k < 30; k++) 
  {
    for (int i = 1; i < HIGHT - 1; i++) 
    {
      for (int j = 2; j < WIDTH; j++) 
      {
        val = 0;
        if (DotSolve[i - 1] & (0x8000 >> j)) val++;
        if (DotSolve[i + 1] & (0x8000 >> j)) val++;
        if (DotSolve[i] & (0x8000 >> (j + 1))) val++;
        if (DotSolve[i] & (0x8000 >> (j - 1))) val++;
        if (3 <= val) DotSolve[i] |= 0x8000 >> j;
      }
    }
    if (show) DisplayMaze(DotSolve);
  }
}

void createFinalMaze()
{
  for(int y=0;y<(HIGHT+1);y++)
  {
    DotMaze[y] = DotArea[y] << 1;
  }
  DotMaze[0] = 0xFFFE;      //Fill in top row
}

void ResetMaze()
{
  clearMaze();
  makeMaze(false);
  solveMaze(false);
  createFinalMaze();
  
  youCol = 1;
  youRow = 1;

  if (!Look(youRow + 1, youCol)) youDir = FacingSouth;
  else if (!Look(youRow, youCol - 1)) youDir = FacingWest;
  else if (!Look(youRow - 1, youCol)) youDir = FacingNorth;
  else youDir = FacingEast;

  screen.setPixel(ARROW_X,0);
  screen.setPixel(ARROW_X,1);
  screen.setPixel(ARROW_X,2);
  screen.setPixel(ARROW_X,3);
  screen.setPixel(ARROW_X,4);
  screen.setPixel(ARROW_X,5);
  screen.setPixel(ARROW_X,6);
  screen.setPixel(ARROW_X-2,4);
  screen.setPixel(ARROW_X+2,4);
  screen.setPixel(ARROW_X-1,5);
  screen.setPixel(ARROW_X+1,5);

  screen.setFont(SmallFont);
  screen.print((char*)"GET", TEXT_X, 16);
  screen.print((char*)"READY", TEXT_X, 24);

  //Display the generated maze and solution
  unsigned long timer;
  DisplayMaze(DotArea);
  for(int j=0;j<5;j++)
  {
    timer = millis() + 1000;
    while (millis() < timer && digitalRead(SW_FIRE)) ;
    DisplayMaze(DotSolve);
    timer = millis() + 500;
    while (millis() < timer && digitalRead(SW_FIRE)) ;
    DisplayMaze(DotArea);
  }

  //Display the final maze
  mazeX = mazeX + 3;
  DisplayMaze(DotMaze);

  //Flash the starting square
  uint16_t youFlash = 0;
  int i = 0;
  while (i < 20 && digitalRead(SW_FIRE))
  {
    youFlash = ~youFlash;
    setPixel3x3(youCol,youRow,youFlash);
    screen.update();
    timer = millis() + 500;
    while (millis() < timer && digitalRead(SW_FIRE)) ;
    i++;
  }
  mazeX = MAZE_X;
}

Buttons.h

C Header File
// Handles the pushbuttons

#define SW_DN 0     //PA4
#define SW_UP 2     //PA6
#define SW_RG 4     //PB3
#define SW_LF 6     //PB1
#define SW_FIRE 10  //PA3

// mS that FIRE button must be held down before sleep mode
#define SHUTDOWN_TIMEOUT 3000

uint8_t hInset;

//== Animation ==
unsigned long timeToMove;
uint8_t zoom = 0;
uint8_t zoomDir = 0;
uint8_t zoomSpeed = 2;
uint8_t hShift = 0;
uint8_t turnSpeed = 16; // higher = faster
int bumpCount;
int vShift = 1;

void SetupButtons() 
{
  pinMode(SW_UP, INPUT_PULLUP);
  pinMode(SW_DN, INPUT_PULLUP);
  pinMode(SW_LF, INPUT_PULLUP);
  pinMode(SW_RG, INPUT_PULLUP);
  pinMode(SW_FIRE, INPUT_PULLUP);
}

void TurnLeft()
{
  youRotDir = -1;
}

void TurnRight()
{
  youRotDir = +1;
}

void Bump()
{
  bumpCount = 3;
  vShift = 1;
}

void MoveForward()
{
  if (youDir == 0 && youRow > 0              && !Look(youRow - 1, youCol)) youRowDir = -1; // Facing North
  if (youDir == 1 && youCol < (WIDTH - 1) && !Look(youRow, youCol + 1)) youColDir = +1; // Facing East
  if (youDir == 2 && youRow < HIGHT && !Look(youRow + 1, youCol)) youRowDir = +1; // Facing South
  if (youDir == 3 && youCol > 0              && !Look(youRow, youCol - 1)) youColDir = -1; // Facing West
  if (youRowDir == 0 && youColDir == 0)
    Bump();
  else 
  {
    zoom = 0;
    zoomDir = +zoomSpeed;
  }
}

void MoveBackward()
{
  if (youDir == 0 && youRow < HIGHT && !Look(youRow + 1, youCol)) youRowDir = +1; // Facing North
  if (youDir == 1 && youCol > 0              && !Look(youRow, youCol - 1)) youColDir = -1; // Facing East
  if (youDir == 2 && youRow > 0              && !Look(youRow - 1, youCol)) youRowDir = -1; // Facing South
  if (youDir == 3 && youCol < (WIDTH - 1) && !Look(youRow, youCol + 1)) youColDir = +1; // Facing West
  if (youRowDir == 0 && youColDir == 0)
    Bump();
  else 
  {
    zoom = hInset;
    zoomDir = -zoomSpeed;
  }
}

void AnimateTurningLeftRight()
{
  if (youRotDir != 0 && millis() > timeToMove) 
  {
    hShift += turnSpeed;
    if ((hShift <= 0) || (hShift >= screenWidth))
    {
      hShift = 0;
      youDir += youRotDir;
      if (youDir < 0) youDir = 3;
      if (youDir > 3) youDir = 0;
      youRotDir = 0;
    }
    timeToMove = millis() + 30;
  }
}

void AnimateWalkingForwardBackward()
{
  if (zoomDir != 0 && millis() > timeToMove) 
  {
    zoom += zoomDir;
    if (zoom >= hInset || zoom <= 0)
    {
      zoom = 0;
      zoomDir = 0;
      youRow += youRowDir;
      youCol += youColDir;
      youRowDir = youColDir = 0;
    }
    timeToMove = millis() + 30;
  }
}

void AnimateBumpingIntoWall()
{
  if (bumpCount > 0  && millis() > timeToMove) 
  {
    if (--bumpCount == 0) {
      vShift = 0;
    }
    else
      vShift = 1 - vShift;
    timeToMove = millis() + 50;
  }
}

void Animate()
{
  AnimateTurningLeftRight();
  AnimateWalkingForwardBackward();
  AnimateBumpingIntoWall();
}

bool DebounceButton(uint8_t pin, bool waitForRelease)
{
  delay(20);
  if (!digitalRead(pin))
  {
    while (!digitalRead(pin) && waitForRelease)
    {
      yield();
    }
    return true;
  }
  return false;
}

bool CheckButtons()
{
  if (youRowDir == 0 && youColDir == 0 && youRotDir == 0) 
  { 
    // Only allow movement if we're not moving/rotating 
    if (!digitalRead(SW_LF)) { if (DebounceButton(SW_LF,true)); TurnLeft(); };
    if (!digitalRead(SW_RG)) { if (DebounceButton(SW_RG,true)); TurnRight(); };
    if (!digitalRead(SW_UP)) { if (DebounceButton(SW_UP,false)); MoveForward(); };
    if (!digitalRead(SW_DN)) { if (DebounceButton(SW_UP,false));  MoveBackward(); };
    
    if (!digitalRead(SW_FIRE))
    {
      long pressed = millis();
      while (!digitalRead(SW_FIRE) && (millis() - pressed) < SHUTDOWN_TIMEOUT)
      {
        yield();
      }
      pressed = millis() - pressed;
      if (pressed >= SHUTDOWN_TIMEOUT)
      {
        return false;
      }
      else if (pressed > 10)
      {
        //Reset the maze
        screen.clrScr();
        ResetMaze();
      }
    }
  }
  return true;
}

void CheckEscape()
{
  // Only check escape when user is not moving
  if (zoomDir == 0) 
  {
    // Has he reached one of the maze outside edges?
    if (youRow == 0 || youRow == HIGHT || youCol == 0 || youCol == (WIDTH - 1))
    {
      screen.setFont(SmallFont);
      screen.print((char*)"You found", CENTER, 16);
      screen.print((char*)"the EXIT!", CENTER, 24);
      screen.update();
      for (int i=0; i<5; i++)
      {
        delay(500);
        screen.invert(true);
        delay(500);
        screen.invert(false);
      }
      //PlayWinningSong();
      screen.clrScr();
      ResetMaze();
    }
  }
}

Drawing.h

C Header File
// Magic where the fake 3D happens

#define SCREEN_WIDTH 84
#define SCREEN_HEIGHT 48

float ratio;
uint8_t shift;
uint8_t x0, y0;
bool blocked;

void SetupDrawing()
{
  //u8g.setRot180();  // flip screen
  screenWidth = SCREEN_WIDTH;
  screenHeight = SCREEN_HEIGHT;
  x0 = screenHalfWidth = screenWidth / 2;
  y0 = screenHalfHeight = screenHeight / 2;
  hInset = screenWidth / 7;
  ratio = 1.0 * screenHalfHeight / screenHalfWidth;
}

void XToCorners(uint8_t x, Point* points) 
{
  uint8_t y = (uint8_t)(1.0 * x * ratio);
  points[0].Set(x0 - x, y0 - y); // 0 = top left
  points[1].Set(x0 + x, y0 - y); // 1 = top right
  points[2].Set(x0 + x, y0 + y); // 2 = bottom right
  points[3].Set(x0 - x, y0 + y); // 3 = bottom left
}

void DrawFrontLeftWall(Point* outs, Point* ins)
{
  screen.drawLine(outs[0].X, outs[0].Y, ins[0].X, ins[0].Y);
  screen.drawLine(ins[0].X, ins[0].Y, ins[3].X, ins[3].Y);
  screen.drawLine(ins[3].X, ins[3].Y, outs[3].X, outs[3].Y);
}

void DrawFrontRightWall(Point* outs, Point* ins)
{
  screen.drawLine(outs[1].X, outs[1].Y, ins[1].X, ins[1].Y);
  screen.drawLine(ins[1].X, ins[1].Y, ins[2].X, ins[2].Y);
  screen.drawLine(ins[2].X, ins[2].Y, outs[2].X, outs[2].Y);
}

void DrawBackLeftWall(Point* outs, Point* ins)
{
  screen.drawLine(outs[0].X, ins[0].Y, ins[0].X, ins[0].Y);
  screen.drawLine(ins[0].X, ins[0].Y, ins[3].X, ins[3].Y);
  screen.drawLine(ins[3].X, ins[3].Y, outs[3].X, ins[3].Y);
}

void DrawBackRightWall(Point* outs, Point* ins)
{
  screen.drawLine(outs[1].X, ins[1].Y, ins[1].X, ins[1].Y);
  screen.drawLine(ins[1].X, ins[1].Y, ins[2].X, ins[2].Y);
  screen.drawLine(ins[2].X, ins[2].Y, outs[2].X, ins[2].Y);
}

void DrawFrontWall(Point* outs, Point* ins)
{
  screen.drawLine(outs[0].X, outs[0].Y, outs[1].X, outs[1].Y);
  screen.drawLine(outs[1].X, outs[1].Y, outs[2].X, outs[2].Y);
  screen.drawLine(outs[2].X, outs[2].Y, outs[3].X, outs[3].Y);
  screen.drawLine(outs[3].X, outs[3].Y, outs[0].X, outs[0].Y);
}

void DrawBackWall(Point* outs, Point* ins)
{
  screen.drawLine(ins[0].X, ins[0].Y, ins[1].X, ins[1].Y);
  screen.drawLine(ins[1].X, ins[1].Y, ins[2].X, ins[2].Y);
  screen.drawLine(ins[2].X, ins[2].Y, ins[3].X, ins[3].Y);
  screen.drawLine(ins[3].X, ins[3].Y, ins[0].X, ins[0].Y);
}

void TurnRightAnimation(Point* outs, Point* ins)
{
  for (byte i = 0; i < 4; i++) 
  {
    outs[i].X = max(0, outs[i].X -   hShift);
    ins[i].X = max(0,ins[i].X -   hShift);
  }
}

void TurnLeftAnimation(Point* outs, Point* ins)
{
  for (byte i = 0; i < 4; i++) 
  {
    outs[i].X = min(screenWidth,outs[i].X + hShift);
    ins[i].X = min(screenWidth,ins[i].X +  hShift);
  }
}

void BumpAnimation(byte depth, Point* outs, Point* ins)
{
  //if (depth==0) Buzz();
  int offset = vShift==0 ? -2 : +2;
  for (byte i = 0; i < 4; i++) 
  {
    outs[i].X = min(screenWidth-1,max(0,outs[i].X - offset));
    ins[i].X = min(screenWidth-1,max(0,ins[i].X -  offset));
  }
//  for (byte i = 0; i < 4; i++) {
//    outs[i].Y = min(screenHeight-1,max(0,outs[i].Y - offset));
//    ins[i].Y = min(screenHeight-1,max(0,ins[i].Y -  offset));
//  }
}

void DrawWalls(byte depth, byte col, byte row)
{
  Point outs[4], ins[4];
  XToCorners(screenHalfWidth - hInset * depth       + (depth == 0 ? 0 : zoom), outs);
  XToCorners(screenHalfWidth - hInset * (depth + 1) + zoom, ins);

  if (youRotDir > 0) TurnRightAnimation(outs, ins);
  if (youRotDir < 0) TurnLeftAnimation(outs, ins);
  if (bumpCount > 0) BumpAnimation(depth,outs,ins);

  if (youDir == 0) LookNorth(row - depth, col);
  if (youDir == 1) LookEast(row, col + depth);
  if (youDir == 2) LookSouth(row + depth, col);
  if (youDir == 3) LookWest(row, col - depth);
  //DebugWalls(depth,row,col);

  if (hasFrontWall)
    DrawFrontWall(outs, ins);
  else
  {
    if (hasBackWall) DrawBackWall(outs, ins);

    if (hasFrontLeftWall) DrawFrontLeftWall(outs, ins);
    else if (hasBackLeftWall) DrawBackLeftWall(outs, ins);

    if (hasFrontRightWall) DrawFrontRightWall(outs, ins);
    else if (hasBackRightWall) DrawBackRightWall(outs, ins);
  }
}

void DrawMaze(String d)
{
  screen.clrScr();
  screen.drawRect(0, 0, screenWidth-1, screenHeight-1);
  screen.setFont(SmallFont);
  screen.print(d, CENTER, 38);

  blocked = false; // Assume there's nothing in front of us
  for (byte depth = 0; depth < 3; depth++)
  {
    if (!blocked) 
    {
      DrawWalls(depth, youCol, youRow);
      blocked = hasFrontWall || hasBackWall;
    }
  }
  screen.update();
}

Point.h

C Header File
#pragma once

#include <arduino.h>

class Point
{
  public:
    void Set(uint8_t x, uint8_t y);
    uint8_t X;
    uint8_t Y;
};

Point.cpp

C/C++
// Handy way to pass around X and Y as one variable

#include "Point.h"

void Point::Set(uint8_t x, uint8_t y)
{
  X = x;
  Y = y;
}

Credits

John Bradnam
151 projects • 195 followers
Contact
Thanks to Hari Wiguna and Kei Takagi.

Comments

Please log in or sign up to comment.