Maze Generator.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

 

 

public class mazeManager : MonoBehaviour {
public class MazePos
{
public int rowPos;
public int colPos;
public MazePos(int r, int c)
{
rowPos = r;
colPos = c;
}
}

public GameObject mazeCubePrefab;
//public GameObject mazeCubePathPrefab;
public Transform startPrefab;
public GameObject endPrefab;
public Transform mazeParent;

public int mazeRow = 30;
public int mazeCol = 30;
public float scale = 0.5f;
bool isEndPos = false;

List<MazePos> findPosList = new List<MazePos>();
List<List<int>> mazeMapList = new List<List<int>>();

public enum PosType
{
wall = 0,
path = 1,
startPos = 2,
endPos = 3,
}

// Use this for initialization
void Start () {
//inital the maze map list
for(int i = 0; i < mazeRow; i++)
{
mazeMapList.Add(new List<int>());
for(int j = 0; j < mazeCol; j++)
{
mazeMapList[i].Add((int)PosType.wall);
}
}

//start pos
int startPosRow = 0, startPosCol = 0;
startPosRow = UnityEngine.Random.Range(1, mazeRow – 1);
startPosCol = UnityEngine.Random.Range(1, mazeCol – 1);
if (startPosRow % 2 == 0)
{
startPosRow -= 1;
}
if (startPosCol % 2 == 0)
{
startPosCol -= 1;
}
if (startPosRow == 0) startPosRow = 1;
if (startPosCol == 0) startPosCol = 1;
if (startPosRow == mazeRow – 1) startPosRow -= 1;
if (startPosCol == mazeCol – 1) startPosCol -= 1;
int randBorder = UnityEngine.Random.Range(0, 4);
MazePos startPos = new MazePos(0, 0);
if(randBorder == 0)
{
startPos = new MazePos(0, startPosCol);
} else if(randBorder == 1)
{
startPos = new MazePos(mazeRow – 1, startPosCol);
} else if(randBorder == 2)
{
startPos = new MazePos(startPosRow, 0);
} else if (randBorder == 3)
{
startPos = new MazePos(startPosRow, mazeCol – 1);
}

 

mazeMapList[startPos.rowPos][startPos.colPos] = (int)PosType.startPos;
startPrefab.transform.position = new Vector3((startPos.rowPos – (mazeRow / 2)) * scale, (startPos.colPos – (mazeCol / 2)) * scale, 0);

 

findPosList.Add(startPos);

//find path recursively
FindPath(startPos);

//show
ShowMap();
}

void FindPath(MazePos currentPos)
{
if(findPosList.Count >= mazeRow * mazeCol)
{
return;
}

List<MazePos> surroundPos = new List<MazePos>();
FindSurroundPos(surroundPos, currentPos);
while(surroundPos.Count > 0)
{
int randPosIndex = UnityEngine.Random.Range(0, surroundPos.Count);

MazePos nextPos = surroundPos[randPosIndex];
MazePos middlePosBetweenCurAndNext = new MazePos((currentPos.rowPos + nextPos.rowPos) / 2, (currentPos.colPos + nextPos.colPos) / 2);
SetPosHaveFound(middlePosBetweenCurAndNext);
SetPosHaveFound(nextPos);
surroundPos.RemoveAt(randPosIndex);
// keep finding
FindPath(nextPos);

FindSurroundPos(surroundPos, currentPos);
}
}

void FindSurroundPos(List<MazePos> surroundPos, MazePos currentPos)
{
surroundPos.Clear();
//up direction
if(currentPos.rowPos >= 2)
{
if (currentPos.colPos != 0 && currentPos.colPos != mazeCol – 1)
{
AddPosToSurroundPosList(surroundPos, new MazePos(currentPos.rowPos – 2, currentPos.colPos));
}
}
//down direction
if (currentPos.rowPos < mazeRow – 2)
{
if (currentPos.colPos != 0 && currentPos.colPos != mazeCol – 1)
{
AddPosToSurroundPosList(surroundPos, new MazePos(currentPos.rowPos + 2, currentPos.colPos));
}
}
//left direction
if (currentPos.colPos >= 2)
{
if(currentPos.rowPos != 0 && currentPos.rowPos != mazeRow – 1)
{
AddPosToSurroundPosList(surroundPos, new MazePos(currentPos.rowPos, currentPos.colPos – 2));
}
}
//right direction
if (currentPos.colPos < mazeCol – 2)
{
if (currentPos.rowPos != 0 && currentPos.rowPos != mazeRow – 1)
{
AddPosToSurroundPosList(surroundPos, new MazePos(currentPos.rowPos, currentPos.colPos + 2));
}
}
}

void AddPosToSurroundPosList(List<MazePos> surroundPos, MazePos pos)
{
if ((pos.rowPos >= 0 && pos.colPos >= 0) && (pos.rowPos < mazeRow && pos.colPos < mazeCol) && mazeMapList[pos.rowPos][pos.colPos] == (int)PosType.wall)
{
surroundPos.Add(pos);
}
}

void SetPosHaveFound(MazePos pos)
{
mazeMapList[pos.rowPos][pos.colPos] = (int)PosType.path;
findPosList.Add(pos);
}

float addTime = 0;
int addIndex = 0;
List<MazePos> boderList = new List<MazePos>();
int boderIndex = -1;
int rotateAngle = 0;

void ShowMap()
{
for (int i = 0; i < mazeRow; i++)
{
for (int j = 0; j < mazeCol; j++)
{
if(mazeMapList[i][j] == (int)PosType.wall)
{
GameObject Cube2D = (GameObject)Instantiate(mazeCubePrefab, new Vector3((i – (mazeRow / 2)) * scale, (j – (mazeCol / 2)) * scale, 0), Quaternion.identity);
Cube2D.transform.localScale = new Vector3(scale, scale, scale);
Cube2D.transform.parent = mazeParent;
}
}
}

for(int i = 0; i < findPosList.Count; i++)
{
MazePos pos = findPosList[i];
if (i != 0)
{
if (pos.rowPos == 0 || pos.colPos == 0 || pos.rowPos == mazeRow – 1 || pos.colPos == mazeCol – 1)
{
boderList.Add(pos);
}
}
}
while(boderIndex < boderList.Count)
{
if (boderIndex == -1)
{
int randEndIndex = UnityEngine.Random.Range(0, boderList.Count);
MazePos pos = boderList[randEndIndex];
GameObject Cube2D = (GameObject)Instantiate(endPrefab, new Vector3((pos.rowPos – (mazeRow / 2)) * scale, (pos.colPos – (mazeCol / 2)) * scale, 0), Quaternion.identity);
Cube2D.transform.localScale = new Vector3(scale, scale, scale);
Cube2D.transform.parent = mazeParent;
boderList.RemoveAt(randEndIndex);
}
else
{
MazePos pos = boderList[boderIndex];
GameObject Cube2D = (GameObject)Instantiate(mazeCubePrefab, new Vector3((pos.rowPos – (mazeRow / 2)) * scale, (pos.colPos – (mazeCol / 2)) * scale, 0), Quaternion.identity);
Cube2D.transform.localScale = new Vector3(scale, scale, scale);
Cube2D.transform.parent = mazeParent;
}
boderIndex += 1;
}

}

// Update is called once per frame
void Update()
{
mazeParent.rotation = Quaternion.Euler(0, 0, rotateAngle);

if (Input.GetKey(KeyCode.Alpha0)) {
rotateAngle += 5;
mazeParent.rotation = Quaternion.Euler(0, 0, rotateAngle);
}
else if (Input.GetKey(KeyCode.Alpha1)) {
rotateAngle -= 5;
mazeParent.rotation = Quaternion.Euler(0, 0, rotateAngle);
}
}
}

BuildMesh.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BuildMesh : MonoBehaviour
{
public Vector3 leftBottomFront = new Vector3(-0.5f, 0, -0.5f);
public Vector3 rightBottomFront = new Vector3(0, 0, -0.25f);
public Vector3 leftBottomBack = new Vector3(0, 0, 0.5f);
public Vector3 rightBottomBack = new Vector3(0.5f, 0, -0.5f);

public Vector3 leftTopFront = new Vector3(-0.5f, 1, -0.5f);
public Vector3 rightTopFront = new Vector3(0, 1, -0.25f);
public Vector3 leftTopBack = new Vector3(0, 1, 0.5f);
public Vector3 rightTopBack = new Vector3(0.5f, 1, -0.5f);

// Start is called before the first frame update
void Start()
{

MeshFilter mf = GetComponent<MeshFilter>();
Mesh mesh = mf.mesh;

Vector3[] vertices = new Vector3[]
{
//front 0,1,2,3
leftBottomFront,
leftTopFront,
rightTopFront,
rightBottomFront,

//back 4,5,6,7
leftBottomBack,
leftTopBack,
rightTopBack,
rightBottomBack,

//left 8,9,10,11
leftBottomBack,
leftTopBack,
leftTopFront,
leftBottomFront,

//right 12,13,14,15
rightBottomFront,
rightTopFront,
rightTopBack,
rightBottomBack,

//top 16,17,18,19
leftTopFront,
leftTopBack,
rightTopBack,
rightTopFront,

//bottom 20,21,22,23
leftBottomFront,
leftBottomBack,
rightBottomBack,
rightBottomFront
};

int[] triangles = new int[]
{
//front
0,1,2,
2,3,0,

//back
7,6,5,
5,4,7,

//left
8,9,10,
10,11,8,

//right
12,13,14,
14,15,12,

//top
16,17,19,
19,17,18,

//bottom
23,22,21,
21,20,23
};

Vector2[] uvs = new Vector2[]
{
//front
new Vector2(0,1),
new Vector2(0,0),
new Vector2(1,1),
new Vector2(1,0),

new Vector2(0,1),
new Vector2(0,0),
new Vector2(1,1),
new Vector2(1,0),

new Vector2(0,1),
new Vector2(0,0),
new Vector2(1,1),
new Vector2(1,0),

new Vector2(0,1),
new Vector2(0,0),
new Vector2(1,1),
new Vector2(1,0),

new Vector2(0,1),
new Vector2(0,0),
new Vector2(1,1),
new Vector2(1,0),

new Vector2(0,1),
new Vector2(0,0),
new Vector2(1,1),
new Vector2(1,0),
};

mesh.Clear();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.uv = uvs;
mesh.RecalculateNormals();
}

// Update is called once per frame
void Update()
{

}
}

ReadMe

README for Random Maze

Lujia Wang
02/01/2019
– Scene is created automatically, and the scene is different each time the program is
ran.
– The entire scene rotates and the model within the scene remains in the same position
relative to the maze. Hit “1” will rotate the maze clockwise, “0” rotate anticlockwise.
– The model (arrow) is constructed using a Mesh in a script.
– The arrow’s motion is affected based on the scene and arrow can rotate on its own
axis. Gamer can control the arrow object by “W / Up” (forward), “A / Left” (left),
“S / Down” (backward), and “D / Right” (right). The arrow will rotate towards the
direction it goes.
– The numbers of the cube could be changed under maze inspector – Maze Manager
(Script) – Maze Row and Maze Col.
– The shape of the mesh (default as an arrow) could be changed under MeshArrow
inspector – Build Mesh (Script).
– Gamer can use “C” to switch perspective. The camera will follow the arrow you
control.
– When the gamer controls the arrow to the green cube at the exit, a page shows
“YOU WIN!” will pop up and the arrow can only rotate but no longer move.

Collision.cs

using System.Collections.Generic;
using MarioGame.Entities;
using MarioGame.Interfaces;
using Microsoft.Xna.Framework;

namespace MarioGame.Collision
{
public abstract class Collision : ICollision
{
public float FirstContact { get; set; }
private List<Entity> CollidedList;
private Entity min;
private Entity two;
private Entity third;
public Entity CurrentEntity { get; set; }
private const float Delay = 200f;//show for 2 seconds
private int _elapsed = 0;
public Sprite CurrentSprite
{
get { return CurrentEntity.Sprite; }
set { CurrentEntity.Sprite = value; }
}

public Vector2 FutureLocation
{
get { return CurrentEntity.SpritePosition + CurrentEntity.SpriteVelocity; }
}
public Rectangle FutureBox
{
get { return CurrentSprite.FutureBox(FutureLocation);}
}
public Rectangle Intersection { get; set; }
protected Collision(Entity entity)
{
CurrentEntity = entity;
CollidedList = new List<Entity>();
}
public virtual void Detection(GameTime gameTime, ICollision collideObject) //detect IF it will collide.
{
if (FutureBox.Intersects(collideObject.CurrentEntity.BoundBox)&&!collideObject.CurrentEntity.Dead)
{
third = two;
two = min;
collideObject.FirstContact = gameTime.ElapsedGameTime.Milliseconds;
min = collideObject.CurrentEntity;
CollidedList.Add(min);
Intersection = Rectangle.Intersect(FutureBox, collideObject.CurrentSprite.BoundBox);
}

_elapsed += gameTime.ElapsedGameTime.Milliseconds;
if (_elapsed >= Delay)//To show a black color for collision response.
{
CurrentSprite.CollisionResponse(false);
collideObject.CurrentSprite.CollisionResponse(false);
_elapsed = 0;
}
}

public void AfterAllDetection()
{
if (CollidedList.Count > 0)
{
foreach (Entity one in CollidedList)
{
Intersection = Rectangle.Intersect(FutureBox, one.BoundBox);
if (one.EntityCollision.FirstContact < min.EntityCollision.FirstContact)
{
third = two;
two = min;
min = one;
}
one.EntityCollision.Response(this);
CurrentSprite.CollisionResponse(true);//tint sprite
one.Sprite.CollisionResponse(true);//tint sprite
}
Intersection = Rectangle.Intersect(FutureBox, min.BoundBox);
Response(min.EntityCollision);
if (two != null && FutureBox.Intersects(two.BoundBox) && two!=min)
{
Intersection = Rectangle.Intersect(FutureBox, two.BoundBox);
Response(two.EntityCollision);
}
if (third != null && FutureBox.Intersects(third.BoundBox) && third!=two&&third!=min)
{
Intersection = Rectangle.Intersect(FutureBox, third.BoundBox);
Response(third.EntityCollision);
}
CollidedList.Clear();
}
}
public virtual bool MarioState() { return false; }

public virtual void Response(ICollision collided){}//base response is to do nothing.

//when currentSprite hit the top of collided object
public bool TopCollision(ICollision collided) //currentSprite on top.
{
return Intersection.Bottom < collided.FutureBox.Bottom && Intersection.Top > FutureBox.Top
&&CurrentEntity.SpriteVelocity.Y>0;
}

//when currentSprite hit the bottom of collided object
public bool BottomCollision(ICollision collided)
{
return Intersection.Top > collided.FutureBox.Top && Intersection.Bottom <= FutureBox.Bottom&&CurrentEntity.SpriteVelocity.Y<0;
}

public bool SideCollision(ICollision collided) //current sprite moving L or R.
{
return Intersection.Width < Intersection.Height && (int)CurrentSprite.Velocity.X!=0;
}
}
}

Sprite.cs

using System;
using System.Timers;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MarioGame.CommandHandling;

namespace MarioGame
{
public class Sprite : ISprite
{
public Texture2D Texture { get; set; }
public Texture2D Rectangle { get; set; }
public Rectangle BoundBox { get; set; }
protected int Rows { get; set; }
protected int Columns { get; set; }
public int Width
{
get { return Texture.Width / Columns; }
}

public int Height
{
get { return Texture.Height / Rows; }
}
public int CurrentFrame { get; set; }
protected int TotalFrames { get; set; }
public float TimePerFrame { get; set; }
protected float TotalElapsed { get; set; }
protected bool SeriesPicture { get; set; }
public bool IsToggle { get; set; }
protected Color Box { get; set; }//this controls the color of the Bounding box
protected Color Tint { get; set; }//this controls the collision response color
public int Scale { get; set; }
public bool Dead { get; set; }

public Vector2 Position { get; set; }
public Vector2 Velocity { get; set; }

public Sprite(Texture2D texture, bool animated, int row, int column, Vector2 loc)
{
SeriesPicture = animated;
Rows = row;
Columns = column;
CurrentFrame = 0;
TotalFrames = Rows * Columns;
Texture = texture;
Position = loc;
Velocity = Vector2.Zero;
Scale = 1;
Tint = Color.White;
Box = Color.Beige;
TimePerFrame = 0.2f;
TotalElapsed = 0;
Dead = false;
BoundBox = new Rectangle((int)Position.X, (int)Position.Y, Width, Height);
}

public virtual void Update(GameTime gametime, Vector2 velocity, GraphicsDeviceManager graphic)
{
WhiteBox(graphic);
TotalElapsed += gametime.ElapsedGameTime.Milliseconds;
if (SeriesPicture&&TotalElapsed>TimePerFrame)
{
CurrentFrame = (int)(gametime.TotalGameTime.TotalSeconds / TimePerFrame);
CurrentFrame++;
CurrentFrame = CurrentFrame % TotalFrames;

//if (CurrentFrame == TotalFrames)
// CurrentFrame = 0;
TotalElapsed -= TimePerFrame;
}
Velocity = velocity;
Position += Velocity;//if static then velocity is 0;
BoundBox = new Rectangle((int)Position.X, (int)Position.Y, Scale * Width, Scale * Height);
}
public virtual void Draw(SpriteBatch spriteBatch)
{
int row = CurrentFrame / Columns;
int column = CurrentFrame % Columns;

Rectangle sourceRectangle = new Rectangle(Width * column, Height * row, Width, Height);
Rectangle destinationRectangle = new Rectangle((int)Position.X, (int)Position.Y, Scale * Width, Scale * Height);
if (IsToggle)
{
spriteBatch.Draw(Rectangle, BoundBox, Box); //draw rectangle as background for sprite
}
spriteBatch.Draw(Texture, destinationRectangle, sourceRectangle, Tint);
}

public virtual Rectangle FutureBox(Vector2 Location)
{
return new Rectangle((int)Location.X, (int)Location.Y, BoundBox.Width, BoundBox.Height);
}

public virtual void CollisionResponse(bool hit)
{
//if (hit)
//{
// Tint = Color.Black;
//}
//else
//{
Tint = Color.White;
//}
}
public void WhiteBox(GraphicsDeviceManager graphic) //this is to give Boundbox a texture to be drawn
{
if (Rectangle == null)
{
Rectangle = new Texture2D(graphic.GraphicsDevice, 1, 1);
Rectangle.SetData(new[] { Color.White });
}
}
//public object Clone()
//{
// return this.MemberwiseClone();
//}
}
}

MenuState.cs

using MarioGame.Interfaces;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MarioGame.GameStates
{
public class MenuState : IGameState
{
Button button1;
Button button2;
Button button3;

Texture2D cover;

GraphicsDeviceManager graphics;
Level level;
public static int Difficulty;

public MenuState(GraphicsDeviceManager graphics, Level level)
{
this.graphics = graphics;
this.level = level;
//currentState = state;
button1 = new Button(Game1.ContentLoad.Load<Texture2D>(“Mode/Easy”), new Vector2(350, 230));
button2 = new Button(Game1.ContentLoad.Load<Texture2D>(“Mode/Normal”), new Vector2(350, 260));
button3 = new Button(Game1.ContentLoad.Load<Texture2D>(“Mode/Hard”), new Vector2(350, 290));
cover = Game1.ContentLoad.Load<Texture2D>(“background/cover”);
}
public void Update()
{
MouseState mouse = Mouse.GetState();
if (button1.clicked)
{
Game1.menuState = false;
level.DifficultyMode(1);
Difficulty = 1;
//currentState.setState(currentState.getPlayingState(1));
}
else if (button2.clicked)
{
Game1.menuState = false;
level.DifficultyMode(2);
Difficulty = 2;
// currentState.setState(currentState.getPlayingState(2));
}
else if (button3.clicked)
{
Game1.menuState = false;
level.DifficultyMode(3);
Difficulty = 3;
// currentState.setState(currentState.getPlayingState(3));

}
button1.Update(mouse);
button2.Update(mouse);
button3.Update(mouse);

}
public void Draw(SpriteBatch spriteBatch)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Draw(cover, new Vector2(312, 80), Color.White);
button1.Draw(spriteBatch);
button2.Draw(spriteBatch);
button3.Draw(spriteBatch);
}
}
}