Midterm Progress: Maze is Finally Done

Maze Game

Idea:

The idea for my game is to have a player cross a maze in which they will have to avoid a number of enemies. The player will have a limit visibility of the maze (delimited by a circle around the player character). The player will be able, however, to see the position of the enemies (at least that is the idea). It is kind of a PacMan inspired game but with a twist, you could say.

Here is a rough sketch of how the game will look (kind of):

I also very recently came up with the idea to set a theme for the game (I am creating my own sprites so I needed inspiration). Up until now, I have settled for a Harry Potter theme (I have a friend who is obsessed with Harry Potter) because I found these sprites on internet while I was looking for examples and they reminded me of it.

These are the sprites:

The following made me think about the dementors in the series.

Progress:

For this week I decided to focus on creating the maze (more specifically, been able to generate random mazes) and on going through the PGraphics library. I went through the documentation some online tutorials to better understand how to use it.

Note: the fact that I wrote that I decided to focus on these things means that I actually took a long time to understand PGraphics and even more on creating the code to generate the maze.

To create the maze, I decided to create a grid with cells. The program starts at the upper left cell. It checks for neighboring cells and selects a non-visited cell (one the program has not gone through) and removes a wall (line of the grid). Then it moves to that cell and checks for neighbor cells: the process repeats until a path has been formed. Then the program fills in the left out non-visited cells and randomly removes a wall from them to make them look like a maze. The program is recursive so the last position will be that at the beginning of the maze.

The following is a description of my thought process along with the written algorithm (taken from Wikipedia , there are a lot of options to choose from there).

I had a lot of problems writing the code.

At the beginning it was ok. I manage to create a grid and to be able to place in a different color the visited cell.

The problem came when we started to check the neighboring cells. The problem was the edges: sometimes the program will run well and would move to the neighbor cell, however, when the current cell was an edge, sometimes it choose a neighboring cell outside the canvas, so I had to write a case for that.

This is how it would look:

It was also quite hard to figure out how to assign the cells to certain variable (there was a lot of sketching and thinking involved behind that and it took a lot of time to figure out just how to show and remove the walls).

In many cases, what generate was something that did kind of look like a maze but that had no solution.

For example:

The problems where almost always associated with logic with what wall I was telling the program to remove. I watched some YouTube videos regarding maze generation to see how they removed the walls (all of them were in other programming languages, but the pseudocode was all I really needed to start fixing this mess).

After much struggling, yesterday I was finally able to generate a maze.

However in the morning, something happened (I think I might have erased something by accident). My code wasn’t working anymore.

After smashing my head against the wall all morning on my birthday because I couldn’t figure what was wrong, Professor Aaron illuminated me by asking with which function the cell was moving. I had accidentally erased the part in which the cell moved to the next to create a new path, and I completely missed it. Perhaps I’ve been staring at this code for so long that my mind was just assuming that it was there, because I swear, the fact that that part of the code was missing just completely went over my head.

I know have a code that works, 7amdullah!

This is the final result (also, yes, I keep switching colors and size because I wasn’t sure about which would look good, but now I decided for the theme of Harry Potter, I settled for this yellow color. Hopefully I won’t change it again).

Code:

Main Tab

int cols, rows;
int cellSize = 50;

ArrayList<Cell> grid = new ArrayList<Cell>();

Cell currentCell;

ArrayList<Cell> stack = new ArrayList<Cell>();

void setup() 
{
  size(900, 900);
  //fullScreen();

  cols = floor(width/cellSize);
  rows = floor(height/cellSize);

  //create Cell objects and add them to array list
  for (int j = 0; j < rows; j++) 
  {
    for (int i = 0; i < cols; i++) 
    {
      Cell newCell = new Cell(i, j);
      grid.add(newCell);
    }
  }
  //start the path at grid 0
  currentCell = grid.get(0);
}

void draw() 
{
  background(51);

  //check that the grid displays correctly
  for (int i = 0; i < grid.size(); i++) 
  {
    //I made the mistake of writing grid.length() instead of grid.size()
    grid.get(i).show();
  }

  currentCell.visited = true;
  currentCell.highlight();
  //currentCell.checkAdjacentCells();

  // STEP 1
  Cell nextCell = currentCell.checkAdjacentCells();
  if (nextCell != null) 
  {
    nextCell.visited = true;

    // STEP 2
    stack.add(currentCell);

    //STEP 3: remove the walls
    removeWalls(currentCell, nextCell);

    // STEP 4
    currentCell = nextCell;
  } 

  //this is what corrected the problem with the null value
  else if (stack.size() > 0) 
  {
    currentCell = stack.remove(stack.size()-1);
  }
}

void removeWalls(Cell current, Cell next) 
{

  int x = current.i - next.i;

  if (x == 1) 
  {
    //remove left wall
    current.walls[3] = false;
    //remove right wall
    next.walls[1] = false;
  } else if (x == -1) 
  {
    //remove left wall
    current.walls[1] = false;
    //remove right wall
    next.walls[3] = false;
  }

  int y = current.j - next.j;

  if (y == 1) 
  {
    //remove bottom wall
    current.walls[0] = false;
    //remove top wall
    next.walls[2] = false;
  } else if (y == -1) 
  {
    //remove top wall
    current.walls[2] = false;
    //remove bottom wall
    next.walls[0] = false;
  }
}

Cell Object

class Cell {
  int i, j;

  //order of the walls is top, right, bottom, left
  //this will allow us to remove walls in the grid
  boolean[] walls = {true, true, true, true};
  boolean visited = false;

  Cell(int indexI, int indexJ) {
    i = indexI;
    j = indexJ;
  }

  int index(int i, int j) 
  {
    //return 0 for edge cases
    if (i < 0 || j < 0 || i > cols-1 || j > rows-1)
    {
      return 0;
    }

    //formula to calculate index (same as the one to calculate pixels)
    int index = i + j * cols;
    return index;
  }
  Cell checkAdjacentCells() {
    ArrayList<Cell> adjacentCells = new ArrayList<Cell>();

    //get the cells adjacent to the cell the program is currently at
    Cell top    = grid.get(index(i, j-1));
    Cell right  = grid.get(index(i+1, j));
    Cell bottom = grid.get(index(i, j+1));
    Cell left   = grid.get(index(i-1, j));

    if (top != null && !top.visited) {
      adjacentCells.add(top);
    }
    if (right != null && !right.visited) {
      adjacentCells.add(right);
    }
    if (bottom != null && !bottom.visited) {
      adjacentCells.add(bottom);
    }
    if (left != null && !left.visited) {
      adjacentCells.add(left);
    }

    if (adjacentCells.size() > 0) {
      int r = floor(random(0, adjacentCells.size()));
      return adjacentCells.get(r);
    } else
    {
      return null;
    }
  }

  void highlight() {
    int x = i*cellSize;
    int y = j*cellSize;
    noStroke();
    fill(0, 255, 0);
    rect(x, y, cellSize, cellSize);
  }


  void show() {
    int x = i*cellSize;
    int y = j*cellSize;
    stroke(255);

    //if the walls are defined
    if (walls[0]) 
    {
      line(x, y, x + cellSize, y);
    }
    if (walls[1]) 
    {
      line(x + cellSize, y, x + cellSize, y + cellSize);
    }
    if (walls[2]) 
    {
      line(x + cellSize, y + cellSize, x, y + cellSize);
    }
    if (walls[3]) 
    {
      line(x, y + cellSize, x, y);
    }

    //line(x           , y           , x + cellSize, y);
    //line(x + cellSize, y           , x + cellSize, y + cellSize);
    //line(x + cellSize, y + cellSize, x           , y + cellSize);
    //line(x           , y           , x+ cellSize , y);

    //noFill();
    //rect(x, y, cellSize, cellSize);

    //change color of a cell if it has been visited
    if (visited) 
    {
      noStroke();
      fill(255, 204, 102, 150);
      rect(x, y, cellSize, cellSize);
    }
  }
}

 

Leave a Reply