⬆️ ⬇️

Writing a Labyrinth on XNA 4.0 C #

image

Today I will share my experience of the game "Maze". In this game, the DFS algorithm is implemented. The other day I was assigned to do coursework on Algorithms, namely on DFS in the mazes. It was impossible to refuse. He came home, drank a cup of strong coffee and began to create.



Before I opened Visual Studio, I decided to look for ready-made mazes. As I thought, I found a bunch of stuff. All labyrinths (I was looking only for different and interesting ones) were written in different languages, platforms, but they had something in common, namely, they were all C-like.



It was hard to decide between a number of platforms on which such an idea could be developed (for a freshman). All below listed platforms have their own advantages and disadvantages.



Windows Form



I opened the studio, threw a button on the panel and thought: “Where will I draw my labyrinth and how will it look?”. Having found the necessary material on the Internet, I realized that there must be some kind of matrix that stores the coordinates of the cells and their types.



In WF, I decided to go the lame way and created a grid of components. Then he began to create (dynamically) ordinary panels. At first everything was cool, until I ran into a problem: with a large expansion of the maze, the program just hung. Then I decided to retreat from my idea and find a new platform.

')

WPF



WPF I always liked its functionality. WPF provided a bunch of ways to draw a maze - do not try everything. I decided to draw an array of cells using Path. But ran into a rake: the project again turned out to be costly in resources. And I did not find a way to refer to the drawn cell. Time was running out, and there was no way to find a drawing platform.



Direct x



Direct X technology is incredibly huge, and I would 100% have found a way to create your own maze and the algorithm for creating it. But learning that

Mostly with DX you will work with the language with ++, I was very distressed. I have not had the opportunity to work and create programs in the C ++ language, so I rejected this idea.



XNA



A classmate told me about XNA technology and presented his created snake. And then I realized: this is what I need. After watching a couple of lessons on how to work with XNA, I began to create my own game! Having come across this article , I decided to go according to the mersinvald plan.



Sketching a plan, I rushed into battle!



I selected creation of a matrix in a separate class.
class Matrix { private struct Size //      -          . public int Width { get; set; } public int Height { get; set; } } readonly Size _size; //   readonly Texture2D[,] _maze; //     public Matrix(Maze.Cells size , Texture2D[,] cell2D) { _maze = cell2D; _size.Width = size.X; _size.Height = size.Y; } public void Draw(SpriteBatch spriteBatch) //     { for (var i = 0; i < _size.Height; i++) { for (var j = 0; j < _size.Width; j++) { if ((i % 2 != 0 && j % 2 != 0) && (i < _size.Height - 1 && j < _size.Width - 1)) //    x  y,       { spriteBatch.Draw(_maze[i, j], new Rectangle(i * 10, j * 10, 10, 10), Color.White); //    } else { spriteBatch.Draw(_maze[i, j], new Rectangle(i * 10, j * 10, 10, 10), Color.White); //      } } } } } 




The matrix is ​​generated, or rather an array of cells is created. Now each cell (wall and floor) must have its own texture. Go to the main class and create all the necessary variables.

Start of the main project
  public struct Cells { public int X; public int Y; public Cells(int newX, int newY) { X = newX; Y = newY; } } private SpriteBatch _spriteBatch; private readonly Texture2D[,] _maze; //   private Cells _size; //   private readonly Cells _start; private readonly Cells _finish; private int _cell; //  private int _wall; //  private int _visited; //   private readonly List<Cells> _neighbours; //   private readonly Stack<Cells> _path; //    private int _status; //    public Maze(List<Cells> neighbours, Stack<Cells> path) { _neighbours = neighbours; _path = path; var graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; var winWidth = graphics.PreferredBackBufferWidth = 210; var winHeight = graphics.PreferredBackBufferHeight = 210; _size = new Cells(winWidth/10, winHeight/10); _start = new Cells(1, 1); _finish = new Cells(_size.X - 2, _size.Y - 2); _maze = new Texture2D[_size.X, _size.Y]; _path.Push(_start); IsMouseVisible = true; } 




Texture loading
  protected override void LoadContent() { _spriteBatch = new SpriteBatch(GraphicsDevice); for (var i = 0; i < _size.Y; i++) { for (var j = 0; j < _size.X; j++) { if ((i%2 != 0 && j%2 != 0) && (i < _size.Y - 1 && j < _size.X - 1)) //     .     x  y,       { _maze[i, j] = Content.Load<Texture2D>("flat"); //   _cell = _maze[i, j].GetHashCode(); //     . } else { _maze[i, j] = Content.Load<Texture2D>("wall");//   _wall = _maze[i, j].GetHashCode(); } } } } 


Not finding a way to recognize the type of cell and switched to cunning. Loaded into the Hash Code variable of cell resources.

 _wall = _maze[i, j].GetHashCode(); _cell = _maze[i, j].GetHashCode(); 




Our matrix is ​​ready and displayed on the screen. Now it's small, creating branches of the maze. Create 3 VOIDs:



private void DrawMaze ()
  private void DrawMaze() { if (_path.Count != 0) //     ,    { GetNeighbours(_path.Peek()); //     ,   if (_neighbours.Count != 0) //    ,   () { var a = _neighbours[new Random().Next(0, _neighbours.Count)]; //    RemoteWall(_path.Peek(), a); //        _path.Push(a); //          _neighbours.Clear(); //    } else { _path.Pop(); //    ,     } } else //        { MainPoint(); //      _status = 1; //     } } 




private void GetNeighbours ()
  private void GetNeighbours(Cells localcell) //     { var x = localcell.X; var y = localcell.Y; const int distance = 2; var d = new[] //     { new Cells(x, y - distance), // Up new Cells(x + distance, y), // Right new Cells(x, y + distance), // Down new Cells(x - distance, y) // Left }; for (var i = 0; i < 4; i++) //   4  { var s = d[i]; if (sX <= 0 || sX >= _size.X || sY <= 0 || sY >= _size.Y) continue; //        if (_maze[sX, sY].GetHashCode() == _wall || _maze[sX, sY].GetHashCode() == _visited) continue; //         _neighbours.Add(s); //      } } 




private void RemoteWall ()
  private void RemoteWall(Cells first, Cells second) //    2  { var xDiff = second.X - first.X; var yDiff = second.Y - first.Y; Cells target; Cells newCells; var addX = (xDiff != 0) ? xDiff/Math.Abs(xDiff) : 0; //     var addY = (yDiff != 0) ? yDiff/Math.Abs(yDiff) : 0; target.X = first.X + addX; //    target.Y = first.Y + addY; _maze[target.X, target.Y] = Content.Load<Texture2D>("visited"); //      -   _maze[_path.Peek().X, _path.Peek().Y] = Content.Load<Texture2D>("visited"); //     -   _visited = _maze[target.X, target.Y].GetHashCode(); //  Hash Code   newCells.X = first.X + 2*addX; newCells.Y = first.Y + 2*addY; _path.Push(newCells); //      _maze[_path.Peek().X, _path.Peek().Y] = Content.Load<Texture2D>("visited"); //     -   } 




Well, the code for drawing the starting points:

  private void MainPoint() { _maze[_start.X, _start.Y] = Content.Load<Texture2D>("start"); _starter = _maze[1, 1].GetHashCode(); _maze[_finish.X, _finish.Y] = Content.Load<Texture2D>("finish"); _finisher = _maze[_finish.X, _finish.Y].GetHashCode(); } 


Dowload

Generation works, now it’s small: to find a way out in such a labyrinth. We draw a way out in the same way as we drew a maze. But everything is simplified, since it is not necessary to remove the walls. That's all I have, in the next article will be described a way to find a way out.

Source: https://habr.com/ru/post/265307/



All Articles