Advertisement
DXPower

Another Map Generator

Jun 21st, 2016
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 9.45 KB | None | 0 0
  1. using System;
  2. using UnityEngine;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6.  
  7. public class MapGenerator {
  8.     public Room[,] rooms;
  9.  
  10.     public List<Room> path = new List<Room>();
  11.  
  12.     private float[] entranceNumberChances = { .40f, .35f, .25f, .20f }; // 50% chance for 1 door, 25% chance for 2 doors, 15% chance for 3 doors, 10% chance for 4 doors
  13.  
  14.     private readonly int[] size;
  15.  
  16.     enum directions {
  17.         UP,
  18.         DOWN,
  19.         LEFT,
  20.         RIGHT
  21.     }
  22.  
  23.     private System.Random random = new System.Random();
  24.  
  25.     public MapGenerator(int[] size, int[] roomSize) {
  26.         rooms = new Room[size[0], size[1]];
  27.         this.size = size;
  28.  
  29.         for (int i = 0; i < size[0]; i++) {
  30.             for (int j = 0; j < size[1]; j++) {
  31.                 Room room = new Room(roomSize, new int[] { i, j });
  32.                 rooms[i, j] = room;
  33.             }
  34.         }
  35.  
  36.         DepthFirstSearch(ref rooms[0, 0]);
  37.        
  38.         foreach (Room r in rooms) {
  39.             r.visited = false;
  40.         }
  41.  
  42.         Room startRoom = rooms[0, 0];
  43.         Room endRoom = rooms[size[0] - 1, size[1] - 1];
  44.  
  45.         SolveMaze(ref startRoom, ref endRoom);
  46.         SetPathIDs(ref startRoom, ref endRoom);
  47.         ClearRooms();
  48.  
  49.         for (int i = 0; i < size[0]; i++) {
  50.             for (int j = 0; j < size[1]; j++) {
  51.                 GenerateWallSValues(rooms[i, j]);
  52.             }
  53.         }
  54.     }
  55.  
  56.     // 1f = wall, 0f = wood, .5f = nothing
  57.     public void GenerateWallSValues(Room room) {
  58.         float[,] sValuesWalls = new float[room.size[0], room.size[1]]; // sValues = Special Values
  59.  
  60.         for (int i = 0; i < room.size[0]; i++) {
  61.             for (int j = 0; j < room.size[1]; j++) {
  62.                 // Edge
  63.                 if (room.solution) {
  64.                     if (i == 0 || j == 0 || i == room.size[0] - 1 || j == room.size[1] - 1) {
  65.                         sValuesWalls[i, j] = 1f;
  66.  
  67.                         if (i == 0 && room.entranceArray[3]) {
  68.                             if (j != 0 && j != room.size[1] - 1) sValuesWalls[i, j] = 0f;
  69.                             else if (j == 0 && room.entranceArray[2]) sValuesWalls[i, j] = 0f;
  70.                             else if (j == room.size[1] - 1 && room.entranceArray[0]) sValuesWalls[i, j] = 0f;
  71.                         }
  72.                         if (i == room.size[0] - 1 && room.entranceArray[1]) {
  73.                             if (j != 0 && j != room.size[1] - 1) sValuesWalls[i, j] = 0f;
  74.                             else if (j == 0 && room.entranceArray[2]) sValuesWalls[i, j] = 0f;
  75.                             else if (j == room.size[1] - 1 && room.entranceArray[0]) sValuesWalls[i, j] = 0f;
  76.                         }
  77.                         if (j == 0 && room.entranceArray[2]) {
  78.                             if (i != 0 && i != room.size[0] - 1) sValuesWalls[i, j] = 0f;
  79.                         }
  80.                         if (j == room.size[1] - 1 && room.entranceArray[0]) {
  81.                             if (i != 0 && i != room.size[0] - 1) sValuesWalls[i, j] = 0f;
  82.                         }
  83.                     } else {
  84.                         sValuesWalls[i, j] = 0f;
  85.                     }
  86.                 } else {
  87.                     sValuesWalls[i, j] = .5f;
  88.                 }
  89.             }
  90.         }
  91.  
  92.         #region Entrances
  93.         /*
  94.         float e = UnityEngine.Random.Range(0f, 1f);
  95.         int entrances = 0;
  96.  
  97.         for (int i = entranceNumberChances.Length - 1; i >= 0; i--) {
  98.            
  99.             if (e <= entranceNumberChances[i] || i == 0) {
  100.                 entrances = i + 1;
  101.                 break;
  102.             }
  103.         }
  104.  
  105.         Room[] aRooms = GetAdjacentRooms(room);
  106.  
  107.         for (int i = 0; i < aRooms.Length; i++) {
  108.             if (aRooms[i] == null) continue;
  109.  
  110.             bool entrance = aRooms[i].entranceArray[GetOppositeDirection(i)];
  111.  
  112.             if (aRooms[i].entrances > 0 && entrance) {
  113.                 Debug.Log(i + " " + GetOppositeDirection(i));
  114.                 room.entranceArray[i] = true;
  115.                 room.entrances = Math.Min(4, room.entrances + 1);
  116.             }
  117.         }
  118.  
  119.         entrances = Math.Min(4, entrances + room.entrances);
  120.    
  121.         for (int i = 0; i < entrances - room.entrances; i++) {
  122.             directions dir;
  123.  
  124.             do {
  125.                 dir = RandomDirection();
  126.             } while (room.entranceArray[IntFromDirection(dir)] != false);
  127.  
  128.             room.entranceArray[IntFromDirection(dir)] = true;
  129.             room.entrances++;
  130.         }
  131.    
  132.         // Empty out parts of the walls to form entrances
  133.         for (int i = 0; i < room.entranceArray.Length; i++) {
  134.             if (room.entranceArray[i] == true) {
  135.                 switch (i) {
  136.                     case 0:
  137.                         sValuesWalls[(int) (room.size[0] / 2), 0] = 0f;
  138.                         break;
  139.                     case 1:
  140.                         sValuesWalls[0, (int) room.size[1] / 2] = 0f;
  141.                         break;
  142.                     case 2:
  143.                         sValuesWalls[(int) (room.size[0] / 2), room.size[1] - 1] = 0f;
  144.                         break;
  145.                     case 3:
  146.                         sValuesWalls[room.size[0] - 1, (int) (room.size[1] / 2)] = 0f;
  147.                         break;
  148.                     default:
  149.                         break;
  150.                 }
  151.             }
  152.         }/*/
  153.         #endregion
  154.         FillWalls(room, sValuesWalls);
  155.     }
  156.  
  157.     // A recersive Depth First Search. Basically it randomly goes as far as it can go, and once it can't go any further it goes a node back and branches out from there.
  158.     // This function produces the initial maze that is then simplified down to the simplest path.
  159.     public void DepthFirstSearch(ref Room node) {
  160.         if (node.visited) return;
  161.         List<Room> aRooms = GetAdjacentRoomsList(node);
  162.         node.visited = true;
  163.  
  164.         foreach (int i in Enumerable.Range(0, aRooms.Count).OrderBy(x => random.Next())) {
  165.             Room child = aRooms[i];
  166.             if (!child.visited) {
  167.                 int dir = IntFromDirection(GetDirection(node, child));
  168.  
  169.                 node.entranceArray[dir] = true;
  170.                 child.entranceArray[GetOppositeDirection(dir)] = true;
  171.                 DepthFirstSearch(ref child);
  172.             }
  173.         }
  174.     }
  175.  
  176.     public bool SolveMaze(ref Room node, ref Room goal) {
  177.         if (node.visited) return false;
  178.         node.visited = true;
  179.  
  180.         for (int i = 0; i < node.entranceArray.Length; i++) {
  181.             if (node.entranceArray[i]) {
  182.                 Room child = GetRoom(node, DirectionFromInt(i));
  183.                 if (child.visited) continue;
  184.                 if (child == goal || SolveMaze(ref child, ref goal)) {
  185.                     node.entranceArray = new bool[] { false, false, false, false };
  186.                     node.entranceArray[i] = true;
  187.                     node.pathNext = child;
  188.                     child.pathPrevious = node;
  189.                     child.entranceArray[GetOppositeDirection(i)] = true;
  190.                     node.solution = true;
  191.                     child.solution = true;
  192.                     return true;
  193.                 }
  194.             }
  195.         }
  196.  
  197.         return false;
  198.     }
  199.  
  200.     public void ClearRooms() {
  201.         foreach (Room currentRoom in path) {
  202.             List<Room> aRooms = GetAdjacentRoomsList(currentRoom);
  203.  
  204.             foreach (Room room in aRooms) {
  205.                 int diff = Math.Abs(room.pathId - currentRoom.pathId);
  206.                 if (room.solution && !room.cleared && diff > 1 && diff <= 5) {
  207.                     directions dir = GetDirection(room, currentRoom);
  208.  
  209.                     room.entranceArray[IntFromDirection(dir)] = true;
  210.                     currentRoom.entranceArray[GetOppositeDirection(IntFromDirection(dir))] = true;
  211.                     currentRoom.cleared = true;
  212.                     Debug.Log(String.Format("({0}, {1}) ({2}, {3})", room.position[0], room.position[1], currentRoom.position[0], currentRoom.position[1]));
  213.                 }
  214.             }
  215.         }
  216.     }
  217.  
  218.     public void SetPathIDs(ref Room start, ref Room finish) {
  219.         int pathId = 0;
  220.  
  221.         Room currentRoom = start;
  222.  
  223.         do {
  224.             currentRoom.pathId = pathId++;
  225.             path.Add(currentRoom);
  226.             currentRoom = currentRoom.pathNext;
  227.         } while (currentRoom.pathNext != null);
  228.     }
  229.  
  230.     public void FillWalls(Room room, float[,] sValues) {
  231.         for (int i = 0; i < room.size[0]; i++) {
  232.             for (int j = 0; j < room.size[1]; j++) {
  233.                 if (sValues[i, j] == 1f) {
  234.                     Board.AddTile(Board.self.wallPrefab, new int[] { i + (room.position[0] * room.size[0]), j + (room.position[1] * room.size[1]) });
  235.                 } else if (sValues[i, j] == 0f) {
  236.                     Board.AddTile(Board.self.woodPrefab, new int[] { i + (room.position[0] * room.size[0]), j + (room.position[1] * room.size[1]) });
  237.                 }
  238.             }
  239.         }
  240.     }
  241.  
  242.     private directions RandomDirection() {
  243.         var v = Enum.GetValues(typeof(directions));
  244.         return (directions) v.GetValue(random.Next(v.Length));
  245.     }
  246.  
  247.     private int GetOppositeDirection(int dir) {
  248.         switch (dir) {
  249.             case 0:
  250.                 return 2;
  251.             case 1:
  252.                 return 3;
  253.             case 2:
  254.                 return 0;
  255.             case 3:
  256.                 return 1;
  257.             default:
  258.                 return 0;
  259.         }
  260.     }
  261.  
  262.     private int IntFromDirection(directions dir) {
  263.         switch (dir) {
  264.             case directions.UP:
  265.                 return 0;
  266.             case directions.RIGHT:
  267.                 return 1;
  268.             case directions.DOWN:
  269.                 return 2;
  270.             case directions.LEFT:
  271.                 return 3;
  272.             default:
  273.                 return 0;
  274.         }
  275.     }
  276.  
  277.     private directions DirectionFromInt(int dir) {
  278.         switch (dir) {
  279.             case 0:
  280.                 return directions.UP;
  281.             case 1:
  282.                 return directions.RIGHT;
  283.             case 2:
  284.                 return directions.DOWN;
  285.             case 3:
  286.                 return directions.LEFT;
  287.             default:
  288.                 return directions.UP;
  289.         }
  290.     }
  291.  
  292.     private Room[] GetAdjacentRooms(Room room) {
  293.         // (Clockwise)
  294.         return new Room[] { GetRoom(room, directions.UP), // UP
  295.                             GetRoom(room, directions.RIGHT), // RIGHT
  296.                             GetRoom(room, directions.DOWN), // DOWN
  297.                             GetRoom(room, directions.LEFT)}; // LEFT
  298.     }
  299.  
  300.     private List<Room> GetAdjacentRoomsList(Room room) {
  301.         List<Room> r = new List<Room>();
  302.  
  303.         Room r1 = GetRoom(room, directions.UP);
  304.         Room r2 = GetRoom(room, directions.RIGHT);
  305.         Room r3 = GetRoom(room, directions.DOWN);
  306.         Room r4 = GetRoom(room, directions.LEFT);
  307.  
  308.         if (r1 != null) r.Add(r1);
  309.         if (r2 != null) r.Add(r2);
  310.         if (r3 != null) r.Add(r3);
  311.         if (r4 != null) r.Add(r4);
  312.  
  313.         return r;
  314.     }
  315.  
  316.     private directions GetDirection(Room r1, Room compare) {
  317.         int xDiff = compare.position[0] - r1.position[0];
  318.         int yDiff = compare.position[1] - r1.position[1];
  319.  
  320.         if (xDiff >= 1) return directions.RIGHT;
  321.         else if (xDiff <= -1) return directions.LEFT;
  322.  
  323.         if (yDiff >= 1) return directions.UP;
  324.         else return directions.DOWN;
  325.     }
  326.  
  327.     private Room GetRoom(Room room, directions dir) {
  328.         if (room == null) return null;
  329.         int x = room.position[0];
  330.         int y = room.position[1];
  331.  
  332.         switch (dir) {
  333.             case directions.DOWN:
  334.                 return rooms[x, Math.Max(0, y - 1)];
  335.             case directions.RIGHT:
  336.                 return rooms[Math.Min(size[0] - 1, x + 1), y];
  337.             case directions.UP:
  338.                 return rooms[x, Math.Min(size[1] - 1, y + 1)];
  339.             case directions.LEFT:
  340.                 return rooms[Math.Max(0, x - 1), y];
  341.             default:
  342.                 return room;
  343.         }
  344.     }
  345. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement