Advertisement
SebastianLague

Cave MapGen with spawn items method

Mar 12th, 2016
165
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 12.52 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System;
  5.  
  6. public class MapGenerator : MonoBehaviour {
  7.  
  8.     public int mapWidth;
  9.     public int mapHeight;
  10.  
  11.     public string seed;
  12.     public bool useRandomSeed;
  13.  
  14.     [Range(0,100)]
  15.     public int randomFillPercent;
  16.  
  17.     int[,] map;
  18.  
  19.     public GameObject[] spawnObjectPrefabs;
  20.     public int num = 10;
  21.     public int wallDst = 3;
  22.  
  23.     void SpawnItems(GameObject[] spawn_items, int spawn_num, int spawn_itemDistThreshold, int spawn_distToWall, string spawn_holderName)
  24.     {
  25.         System.Random prng = new System.Random (seed.GetHashCode());
  26.         List<Vector3> possibleSpawnPoints = new List<Vector3>();
  27.         List<Coord> possibleSpawnCoord = new List<Coord>();
  28.  
  29.         for (int i = 0; i < map.GetLength(0); i++)
  30.         {
  31.             for (int j = 0; j < map.GetLength(1); j++)
  32.             {
  33.                 if (map[i, j] == 0)
  34.                 {
  35.                     possibleSpawnPoints.Add(new Vector3(-mapWidth / 2 + i, 0, -mapHeight / 2 + j));
  36.                     possibleSpawnCoord.Add(new Coord(i, j));
  37.                 }
  38.             }
  39.         }
  40.         if (GameObject.Find(spawn_holderName))
  41.         {
  42.             GameObject.Destroy(GameObject.Find(spawn_holderName));
  43.         }
  44.         GameObject holder = new GameObject(spawn_holderName);
  45.  
  46.  
  47.         List<Vector3> spawnedPositions = new List<Vector3>();
  48.         int safeCount = 50 * spawn_num;
  49.         while (spawn_num > 0 && safeCount > 0)
  50.         {
  51.             int spawnIndex = prng.Next(0, possibleSpawnPoints.Count);
  52.             Vector3 spawnLocation = possibleSpawnPoints[spawnIndex];
  53.             Coord spawnCoord = possibleSpawnCoord[spawnIndex];
  54.  
  55.             bool itemTooCloseToPreviousSpawns = false;
  56.             foreach (Vector3 v in spawnedPositions)
  57.             {
  58.                 if (Vector3.SqrMagnitude(v - spawnLocation) < spawn_itemDistThreshold * spawn_itemDistThreshold)
  59.                 {
  60.                     itemTooCloseToPreviousSpawns = true;
  61.                     break;
  62.                 }
  63.             }
  64.  
  65.             bool itemTooCloseToWalls = false;
  66.             if (!itemTooCloseToWalls) {
  67.                 for (int i = -spawn_distToWall; i <= spawn_distToWall; i++) {
  68.                     for (int j = -spawn_distToWall; j <= spawn_distToWall; j++)
  69.                     {
  70.                         int wallCheckX = spawnCoord.tileX + i;
  71.                         int wallCheckY = spawnCoord.tileY + j;
  72.  
  73.                         if (wallCheckX >= 0 && wallCheckX < mapWidth && wallCheckY >= 0 && wallCheckY < mapHeight)
  74.                         {
  75.                             if (map[wallCheckX, wallCheckY] == 1)
  76.                             {
  77.                                 itemTooCloseToWalls = true;
  78.                                 break;
  79.                             }
  80.                         }
  81.                     }
  82.                     if (itemTooCloseToWalls)
  83.                     {
  84.                         break;
  85.                     }
  86.                 }
  87.             }
  88.  
  89.             if (!itemTooCloseToPreviousSpawns && !itemTooCloseToWalls)
  90.             {
  91.                 spawnedPositions.Add(spawnLocation);
  92.                 GameObject spawnedObject = Instantiate(spawn_items[UnityEngine.Random.Range(0, spawn_items.Length)].gameObject, spawnLocation, Quaternion.identity) as GameObject;
  93.                 spawnedObject.transform.Rotate(Vector3.right * 90);
  94.                 spawnedObject.transform.parent = holder.transform;
  95.                 spawn_num--;
  96.             }
  97.             safeCount--;
  98.         }
  99.         holder.transform.Rotate(Vector3.right * 270);
  100.     }
  101.  
  102.  
  103.     void Start() {
  104.         GenerateMap();
  105.     }
  106.  
  107.     void Update() {
  108.         if (Input.GetMouseButtonDown(0)) {
  109.             GenerateMap();
  110.         }
  111.     }
  112.  
  113.     void GenerateMap() {
  114.         map = new int[mapWidth,mapHeight];
  115.         RandomFillMap();
  116.  
  117.         for (int i = 0; i < 5; i ++) {
  118.             SmoothMap();
  119.         }
  120.  
  121.         ProcessMap ();
  122.  
  123.         int borderSize = 1;
  124.         int[,] borderedMap = new int[mapWidth + borderSize * 2,mapHeight + borderSize * 2];
  125.  
  126.         for (int x = 0; x < borderedMap.GetLength(0); x ++) {
  127.             for (int y = 0; y < borderedMap.GetLength(1); y ++) {
  128.                 if (x >= borderSize && x < mapWidth + borderSize && y >= borderSize && y < mapHeight + borderSize) {
  129.                     borderedMap[x,y] = map[x-borderSize,y-borderSize];
  130.                 }
  131.                 else {
  132.                     borderedMap[x,y] =1;
  133.                 }
  134.             }
  135.         }
  136.  
  137.         SpawnItems (spawnObjectPrefabs, num, 1, wallDst, "Holder");
  138.  
  139.         MeshGenerator meshGen = GetComponent<MeshGenerator>();
  140.         meshGen.GenerateMesh(borderedMap, 1);
  141.     }
  142.  
  143.     void ProcessMap() {
  144.         List<List<Coord>> wallRegions = GetRegions (1);
  145.         int wallThresholdSize = 50;
  146.  
  147.         foreach (List<Coord> wallRegion in wallRegions) {
  148.             if (wallRegion.Count < wallThresholdSize) {
  149.                 foreach (Coord tile in wallRegion) {
  150.                     map[tile.tileX,tile.tileY] = 0;
  151.                 }
  152.             }
  153.         }
  154.  
  155.         List<List<Coord>> roomRegions = GetRegions (0);
  156.         int roomThresholdSize = 50;
  157.         List<Room> survivingRooms = new List<Room> ();
  158.        
  159.         foreach (List<Coord> roomRegion in roomRegions) {
  160.             if (roomRegion.Count < roomThresholdSize) {
  161.                 foreach (Coord tile in roomRegion) {
  162.                     map[tile.tileX,tile.tileY] = 1;
  163.                 }
  164.             }
  165.             else {
  166.                 survivingRooms.Add(new Room(roomRegion, map));
  167.             }
  168.         }
  169.         survivingRooms.Sort ();
  170.         survivingRooms [0].isMainRoom = true;
  171.         survivingRooms [0].isAccessibleFromMainRoom = true;
  172.  
  173.         ConnectClosestRooms (survivingRooms);
  174.     }
  175.  
  176.     void ConnectClosestRooms(List<Room> allRooms, bool forceAccessibilityFromMainRoom = false) {
  177.  
  178.         List<Room> roomListA = new List<Room> ();
  179.         List<Room> roomListB = new List<Room> ();
  180.  
  181.         if (forceAccessibilityFromMainRoom) {
  182.             foreach (Room room in allRooms) {
  183.                 if (room.isAccessibleFromMainRoom) {
  184.                     roomListB.Add (room);
  185.                 } else {
  186.                     roomListA.Add (room);
  187.                 }
  188.             }
  189.         } else {
  190.             roomListA = allRooms;
  191.             roomListB = allRooms;
  192.         }
  193.  
  194.         int bestDistance = 0;
  195.         Coord bestTileA = new Coord ();
  196.         Coord bestTileB = new Coord ();
  197.         Room bestRoomA = new Room ();
  198.         Room bestRoomB = new Room ();
  199.         bool possibleConnectionFound = false;
  200.  
  201.         foreach (Room roomA in roomListA) {
  202.             if (!forceAccessibilityFromMainRoom) {
  203.                 possibleConnectionFound = false;
  204.                 if (roomA.connectedRooms.Count > 0) {
  205.                     continue;
  206.                 }
  207.             }
  208.  
  209.             foreach (Room roomB in roomListB) {
  210.                 if (roomA == roomB || roomA.IsConnected(roomB)) {
  211.                     continue;
  212.                 }
  213.            
  214.                 for (int tileIndexA = 0; tileIndexA < roomA.edgeTiles.Count; tileIndexA ++) {
  215.                     for (int tileIndexB = 0; tileIndexB < roomB.edgeTiles.Count; tileIndexB ++) {
  216.                         Coord tileA = roomA.edgeTiles[tileIndexA];
  217.                         Coord tileB = roomB.edgeTiles[tileIndexB];
  218.                         int distanceBetweenRooms = (int)(Mathf.Pow (tileA.tileX-tileB.tileX,2) + Mathf.Pow (tileA.tileY-tileB.tileY,2));
  219.  
  220.                         if (distanceBetweenRooms < bestDistance || !possibleConnectionFound) {
  221.                             bestDistance = distanceBetweenRooms;
  222.                             possibleConnectionFound = true;
  223.                             bestTileA = tileA;
  224.                             bestTileB = tileB;
  225.                             bestRoomA = roomA;
  226.                             bestRoomB = roomB;
  227.                         }
  228.                     }
  229.                 }
  230.             }
  231.             if (possibleConnectionFound && !forceAccessibilityFromMainRoom) {
  232.                 CreatePassage(bestRoomA, bestRoomB, bestTileA, bestTileB);
  233.             }
  234.         }
  235.  
  236.         if (possibleConnectionFound && forceAccessibilityFromMainRoom) {
  237.             CreatePassage(bestRoomA, bestRoomB, bestTileA, bestTileB);
  238.             ConnectClosestRooms(allRooms, true);
  239.         }
  240.  
  241.         if (!forceAccessibilityFromMainRoom) {
  242.             ConnectClosestRooms(allRooms, true);
  243.         }
  244.     }
  245.  
  246.     void CreatePassage(Room roomA, Room roomB, Coord tileA, Coord tileB) {
  247.         Room.ConnectRooms (roomA, roomB);
  248.         //Debug.DrawLine (CoordToWorldPoint (tileA), CoordToWorldPoint (tileB), Color.green, 100);
  249.  
  250.         List<Coord> line = GetLine (tileA, tileB);
  251.         foreach (Coord c in line) {
  252.             DrawCircle(c,5);
  253.         }
  254.     }
  255.  
  256.     void DrawCircle(Coord c, int r) {
  257.         for (int x = -r; x <= r; x++) {
  258.             for (int y = -r; y <= r; y++) {
  259.                 if (x*x + y*y <= r*r) {
  260.                     int drawX = c.tileX + x;
  261.                     int drawY = c.tileY + y;
  262.                     if (IsInMapRange(drawX, drawY)) {
  263.                         map[drawX,drawY] = 0;
  264.                     }
  265.                 }
  266.             }
  267.         }
  268.     }
  269.  
  270.     List<Coord> GetLine(Coord from, Coord to) {
  271.         List<Coord> line = new List<Coord> ();
  272.  
  273.         int x = from.tileX;
  274.         int y = from.tileY;
  275.  
  276.         int dx = to.tileX - from.tileX;
  277.         int dy = to.tileY - from.tileY;
  278.  
  279.         bool inverted = false;
  280.         int step = Math.Sign (dx);
  281.         int gradientStep = Math.Sign (dy);
  282.  
  283.         int longest = Mathf.Abs (dx);
  284.         int shortest = Mathf.Abs (dy);
  285.  
  286.         if (longest < shortest) {
  287.             inverted = true;
  288.             longest = Mathf.Abs(dy);
  289.             shortest = Mathf.Abs(dx);
  290.  
  291.             step = Math.Sign (dy);
  292.             gradientStep = Math.Sign (dx);
  293.         }
  294.  
  295.         int gradientAccumulation = longest / 2;
  296.         for (int i =0; i < longest; i ++) {
  297.             line.Add(new Coord(x,y));
  298.  
  299.             if (inverted) {
  300.                 y += step;
  301.             }
  302.             else {
  303.                 x += step;
  304.             }
  305.  
  306.             gradientAccumulation += shortest;
  307.             if (gradientAccumulation >= longest) {
  308.                 if (inverted) {
  309.                     x += gradientStep;
  310.                 }
  311.                 else {
  312.                     y += gradientStep;
  313.                 }
  314.                 gradientAccumulation -= longest;
  315.             }
  316.         }
  317.  
  318.         return line;
  319.     }
  320.  
  321.     Vector3 CoordToWorldPoint(Coord tile) {
  322.         return new Vector3 (-mapWidth / 2 + .5f + tile.tileX, 2, -mapHeight / 2 + .5f + tile.tileY);
  323.     }
  324.  
  325.     List<List<Coord>> GetRegions(int tileType) {
  326.         List<List<Coord>> regions = new List<List<Coord>> ();
  327.         int[,] mapFlags = new int[mapWidth,mapHeight];
  328.  
  329.         for (int x = 0; x < mapWidth; x ++) {
  330.             for (int y = 0; y < mapHeight; y ++) {
  331.                 if (mapFlags[x,y] == 0 && map[x,y] == tileType) {
  332.                     List<Coord> newRegion = GetRegionTiles(x,y);
  333.                     regions.Add(newRegion);
  334.  
  335.                     foreach (Coord tile in newRegion) {
  336.                         mapFlags[tile.tileX, tile.tileY] = 1;
  337.                     }
  338.                 }
  339.             }
  340.         }
  341.  
  342.         return regions;
  343.     }
  344.  
  345.     List<Coord> GetRegionTiles(int startX, int startY) {
  346.         List<Coord> tiles = new List<Coord> ();
  347.         int[,] mapFlags = new int[mapWidth,mapHeight];
  348.         int tileType = map [startX, startY];
  349.  
  350.         Queue<Coord> queue = new Queue<Coord> ();
  351.         queue.Enqueue (new Coord (startX, startY));
  352.         mapFlags [startX, startY] = 1;
  353.  
  354.         while (queue.Count > 0) {
  355.             Coord tile = queue.Dequeue();
  356.             tiles.Add(tile);
  357.  
  358.             for (int x = tile.tileX - 1; x <= tile.tileX + 1; x++) {
  359.                 for (int y = tile.tileY - 1; y <= tile.tileY + 1; y++) {
  360.                     if (IsInMapRange(x,y) && (y == tile.tileY || x == tile.tileX)) {
  361.                         if (mapFlags[x,y] == 0 && map[x,y] == tileType) {
  362.                             mapFlags[x,y] = 1;
  363.                             queue.Enqueue(new Coord(x,y));
  364.                         }
  365.                     }
  366.                 }
  367.             }
  368.         }
  369.         return tiles;
  370.     }
  371.  
  372.     bool IsInMapRange(int x, int y) {
  373.         return x >= 0 && x < mapWidth && y >= 0 && y < mapHeight;
  374.     }
  375.  
  376.  
  377.     void RandomFillMap() {
  378.         if (useRandomSeed) {
  379.             seed = Time.time.ToString();
  380.         }
  381.  
  382.         System.Random pseudoRandom = new System.Random(seed.GetHashCode());
  383.  
  384.         for (int x = 0; x < mapWidth; x ++) {
  385.             for (int y = 0; y < mapHeight; y ++) {
  386.                 if (x == 0 || x == mapWidth-1 || y == 0 || y == mapHeight -1) {
  387.                     map[x,y] = 1;
  388.                 }
  389.                 else {
  390.                     map[x,y] = (pseudoRandom.Next(0,100) < randomFillPercent)? 1: 0;
  391.                 }
  392.             }
  393.         }
  394.     }
  395.  
  396.     void SmoothMap() {
  397.         for (int x = 0; x < mapWidth; x ++) {
  398.             for (int y = 0; y < mapHeight; y ++) {
  399.                 int neighbourWallTiles = GetSurroundingWallCount(x,y);
  400.  
  401.                 if (neighbourWallTiles > 4)
  402.                     map[x,y] = 1;
  403.                 else if (neighbourWallTiles < 4)
  404.                     map[x,y] = 0;
  405.  
  406.             }
  407.         }
  408.     }
  409.  
  410.     int GetSurroundingWallCount(int gridX, int gridY) {
  411.         int wallCount = 0;
  412.         for (int neighbourX = gridX - 1; neighbourX <= gridX + 1; neighbourX ++) {
  413.             for (int neighbourY = gridY - 1; neighbourY <= gridY + 1; neighbourY ++) {
  414.                 if (IsInMapRange(neighbourX,neighbourY)) {
  415.                     if (neighbourX != gridX || neighbourY != gridY) {
  416.                         wallCount += map[neighbourX,neighbourY];
  417.                     }
  418.                 }
  419.                 else {
  420.                     wallCount ++;
  421.                 }
  422.             }
  423.         }
  424.  
  425.         return wallCount;
  426.     }
  427.  
  428.     struct Coord {
  429.         public int tileX;
  430.         public int tileY;
  431.  
  432.         public Coord(int x, int y) {
  433.             tileX = x;
  434.             tileY = y;
  435.         }
  436.     }
  437.  
  438.  
  439.     class Room : IComparable<Room> {
  440.         public List<Coord> tiles;
  441.         public List<Coord> edgeTiles;
  442.         public List<Room> connectedRooms;
  443.         public int roomSize;
  444.         public bool isAccessibleFromMainRoom;
  445.         public bool isMainRoom;
  446.  
  447.         public Room() {
  448.         }
  449.  
  450.         public Room(List<Coord> roomTiles, int[,] map) {
  451.             tiles = roomTiles;
  452.             roomSize = tiles.Count;
  453.             connectedRooms = new List<Room>();
  454.  
  455.             edgeTiles = new List<Coord>();
  456.             foreach (Coord tile in tiles) {
  457.                 for (int x = tile.tileX-1; x <= tile.tileX+1; x++) {
  458.                     for (int y = tile.tileY-1; y <= tile.tileY+1; y++) {
  459.                         if (x == tile.tileX || y == tile.tileY) {
  460.                             if (map[x,y] == 1) {
  461.                                 edgeTiles.Add(tile);
  462.                             }
  463.                         }
  464.                     }
  465.                 }
  466.             }
  467.         }
  468.  
  469.         public void SetAccessibleFromMainRoom() {
  470.             if (!isAccessibleFromMainRoom) {
  471.                 isAccessibleFromMainRoom = true;
  472.                 foreach (Room connectedRoom in connectedRooms) {
  473.                     connectedRoom.SetAccessibleFromMainRoom();
  474.                 }
  475.             }
  476.         }
  477.  
  478.         public static void ConnectRooms(Room roomA, Room roomB) {
  479.             if (roomA.isAccessibleFromMainRoom) {
  480.                 roomB.SetAccessibleFromMainRoom ();
  481.             } else if (roomB.isAccessibleFromMainRoom) {
  482.                 roomA.SetAccessibleFromMainRoom();
  483.             }
  484.             roomA.connectedRooms.Add (roomB);
  485.             roomB.connectedRooms.Add (roomA);
  486.         }
  487.  
  488.         public bool IsConnected(Room otherRoom) {
  489.             return connectedRooms.Contains(otherRoom);
  490.         }
  491.  
  492.         public int CompareTo(Room otherRoom) {
  493.             return otherRoom.roomSize.CompareTo (roomSize);
  494.         }
  495.     }
  496.  
  497. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement