Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- using System;
- public class MapGenerator : MonoBehaviour {
- public int mapWidth;
- public int mapHeight;
- public string seed;
- public bool useRandomSeed;
- [Range(0,100)]
- public int randomFillPercent;
- int[,] map;
- public GameObject[] spawnObjectPrefabs;
- public int num = 10;
- public int wallDst = 3;
- void SpawnItems(GameObject[] spawn_items, int spawn_num, int spawn_itemDistThreshold, int spawn_distToWall, string spawn_holderName)
- {
- System.Random prng = new System.Random (seed.GetHashCode());
- List<Vector3> possibleSpawnPoints = new List<Vector3>();
- List<Coord> possibleSpawnCoord = new List<Coord>();
- for (int i = 0; i < map.GetLength(0); i++)
- {
- for (int j = 0; j < map.GetLength(1); j++)
- {
- if (map[i, j] == 0)
- {
- possibleSpawnPoints.Add(new Vector3(-mapWidth / 2 + i, 0, -mapHeight / 2 + j));
- possibleSpawnCoord.Add(new Coord(i, j));
- }
- }
- }
- if (GameObject.Find(spawn_holderName))
- {
- GameObject.Destroy(GameObject.Find(spawn_holderName));
- }
- GameObject holder = new GameObject(spawn_holderName);
- List<Vector3> spawnedPositions = new List<Vector3>();
- int safeCount = 50 * spawn_num;
- while (spawn_num > 0 && safeCount > 0)
- {
- int spawnIndex = prng.Next(0, possibleSpawnPoints.Count);
- Vector3 spawnLocation = possibleSpawnPoints[spawnIndex];
- Coord spawnCoord = possibleSpawnCoord[spawnIndex];
- bool itemTooCloseToPreviousSpawns = false;
- foreach (Vector3 v in spawnedPositions)
- {
- if (Vector3.SqrMagnitude(v - spawnLocation) < spawn_itemDistThreshold * spawn_itemDistThreshold)
- {
- itemTooCloseToPreviousSpawns = true;
- break;
- }
- }
- bool itemTooCloseToWalls = false;
- if (!itemTooCloseToWalls) {
- for (int i = -spawn_distToWall; i <= spawn_distToWall; i++) {
- for (int j = -spawn_distToWall; j <= spawn_distToWall; j++)
- {
- int wallCheckX = spawnCoord.tileX + i;
- int wallCheckY = spawnCoord.tileY + j;
- if (wallCheckX >= 0 && wallCheckX < mapWidth && wallCheckY >= 0 && wallCheckY < mapHeight)
- {
- if (map[wallCheckX, wallCheckY] == 1)
- {
- itemTooCloseToWalls = true;
- break;
- }
- }
- }
- if (itemTooCloseToWalls)
- {
- break;
- }
- }
- }
- if (!itemTooCloseToPreviousSpawns && !itemTooCloseToWalls)
- {
- spawnedPositions.Add(spawnLocation);
- GameObject spawnedObject = Instantiate(spawn_items[UnityEngine.Random.Range(0, spawn_items.Length)].gameObject, spawnLocation, Quaternion.identity) as GameObject;
- spawnedObject.transform.Rotate(Vector3.right * 90);
- spawnedObject.transform.parent = holder.transform;
- spawn_num--;
- }
- safeCount--;
- }
- holder.transform.Rotate(Vector3.right * 270);
- }
- void Start() {
- GenerateMap();
- }
- void Update() {
- if (Input.GetMouseButtonDown(0)) {
- GenerateMap();
- }
- }
- void GenerateMap() {
- map = new int[mapWidth,mapHeight];
- RandomFillMap();
- for (int i = 0; i < 5; i ++) {
- SmoothMap();
- }
- ProcessMap ();
- int borderSize = 1;
- int[,] borderedMap = new int[mapWidth + borderSize * 2,mapHeight + borderSize * 2];
- for (int x = 0; x < borderedMap.GetLength(0); x ++) {
- for (int y = 0; y < borderedMap.GetLength(1); y ++) {
- if (x >= borderSize && x < mapWidth + borderSize && y >= borderSize && y < mapHeight + borderSize) {
- borderedMap[x,y] = map[x-borderSize,y-borderSize];
- }
- else {
- borderedMap[x,y] =1;
- }
- }
- }
- SpawnItems (spawnObjectPrefabs, num, 1, wallDst, "Holder");
- MeshGenerator meshGen = GetComponent<MeshGenerator>();
- meshGen.GenerateMesh(borderedMap, 1);
- }
- void ProcessMap() {
- List<List<Coord>> wallRegions = GetRegions (1);
- int wallThresholdSize = 50;
- foreach (List<Coord> wallRegion in wallRegions) {
- if (wallRegion.Count < wallThresholdSize) {
- foreach (Coord tile in wallRegion) {
- map[tile.tileX,tile.tileY] = 0;
- }
- }
- }
- List<List<Coord>> roomRegions = GetRegions (0);
- int roomThresholdSize = 50;
- List<Room> survivingRooms = new List<Room> ();
- foreach (List<Coord> roomRegion in roomRegions) {
- if (roomRegion.Count < roomThresholdSize) {
- foreach (Coord tile in roomRegion) {
- map[tile.tileX,tile.tileY] = 1;
- }
- }
- else {
- survivingRooms.Add(new Room(roomRegion, map));
- }
- }
- survivingRooms.Sort ();
- survivingRooms [0].isMainRoom = true;
- survivingRooms [0].isAccessibleFromMainRoom = true;
- ConnectClosestRooms (survivingRooms);
- }
- void ConnectClosestRooms(List<Room> allRooms, bool forceAccessibilityFromMainRoom = false) {
- List<Room> roomListA = new List<Room> ();
- List<Room> roomListB = new List<Room> ();
- if (forceAccessibilityFromMainRoom) {
- foreach (Room room in allRooms) {
- if (room.isAccessibleFromMainRoom) {
- roomListB.Add (room);
- } else {
- roomListA.Add (room);
- }
- }
- } else {
- roomListA = allRooms;
- roomListB = allRooms;
- }
- int bestDistance = 0;
- Coord bestTileA = new Coord ();
- Coord bestTileB = new Coord ();
- Room bestRoomA = new Room ();
- Room bestRoomB = new Room ();
- bool possibleConnectionFound = false;
- foreach (Room roomA in roomListA) {
- if (!forceAccessibilityFromMainRoom) {
- possibleConnectionFound = false;
- if (roomA.connectedRooms.Count > 0) {
- continue;
- }
- }
- foreach (Room roomB in roomListB) {
- if (roomA == roomB || roomA.IsConnected(roomB)) {
- continue;
- }
- for (int tileIndexA = 0; tileIndexA < roomA.edgeTiles.Count; tileIndexA ++) {
- for (int tileIndexB = 0; tileIndexB < roomB.edgeTiles.Count; tileIndexB ++) {
- Coord tileA = roomA.edgeTiles[tileIndexA];
- Coord tileB = roomB.edgeTiles[tileIndexB];
- int distanceBetweenRooms = (int)(Mathf.Pow (tileA.tileX-tileB.tileX,2) + Mathf.Pow (tileA.tileY-tileB.tileY,2));
- if (distanceBetweenRooms < bestDistance || !possibleConnectionFound) {
- bestDistance = distanceBetweenRooms;
- possibleConnectionFound = true;
- bestTileA = tileA;
- bestTileB = tileB;
- bestRoomA = roomA;
- bestRoomB = roomB;
- }
- }
- }
- }
- if (possibleConnectionFound && !forceAccessibilityFromMainRoom) {
- CreatePassage(bestRoomA, bestRoomB, bestTileA, bestTileB);
- }
- }
- if (possibleConnectionFound && forceAccessibilityFromMainRoom) {
- CreatePassage(bestRoomA, bestRoomB, bestTileA, bestTileB);
- ConnectClosestRooms(allRooms, true);
- }
- if (!forceAccessibilityFromMainRoom) {
- ConnectClosestRooms(allRooms, true);
- }
- }
- void CreatePassage(Room roomA, Room roomB, Coord tileA, Coord tileB) {
- Room.ConnectRooms (roomA, roomB);
- //Debug.DrawLine (CoordToWorldPoint (tileA), CoordToWorldPoint (tileB), Color.green, 100);
- List<Coord> line = GetLine (tileA, tileB);
- foreach (Coord c in line) {
- DrawCircle(c,5);
- }
- }
- void DrawCircle(Coord c, int r) {
- for (int x = -r; x <= r; x++) {
- for (int y = -r; y <= r; y++) {
- if (x*x + y*y <= r*r) {
- int drawX = c.tileX + x;
- int drawY = c.tileY + y;
- if (IsInMapRange(drawX, drawY)) {
- map[drawX,drawY] = 0;
- }
- }
- }
- }
- }
- List<Coord> GetLine(Coord from, Coord to) {
- List<Coord> line = new List<Coord> ();
- int x = from.tileX;
- int y = from.tileY;
- int dx = to.tileX - from.tileX;
- int dy = to.tileY - from.tileY;
- bool inverted = false;
- int step = Math.Sign (dx);
- int gradientStep = Math.Sign (dy);
- int longest = Mathf.Abs (dx);
- int shortest = Mathf.Abs (dy);
- if (longest < shortest) {
- inverted = true;
- longest = Mathf.Abs(dy);
- shortest = Mathf.Abs(dx);
- step = Math.Sign (dy);
- gradientStep = Math.Sign (dx);
- }
- int gradientAccumulation = longest / 2;
- for (int i =0; i < longest; i ++) {
- line.Add(new Coord(x,y));
- if (inverted) {
- y += step;
- }
- else {
- x += step;
- }
- gradientAccumulation += shortest;
- if (gradientAccumulation >= longest) {
- if (inverted) {
- x += gradientStep;
- }
- else {
- y += gradientStep;
- }
- gradientAccumulation -= longest;
- }
- }
- return line;
- }
- Vector3 CoordToWorldPoint(Coord tile) {
- return new Vector3 (-mapWidth / 2 + .5f + tile.tileX, 2, -mapHeight / 2 + .5f + tile.tileY);
- }
- List<List<Coord>> GetRegions(int tileType) {
- List<List<Coord>> regions = new List<List<Coord>> ();
- int[,] mapFlags = new int[mapWidth,mapHeight];
- for (int x = 0; x < mapWidth; x ++) {
- for (int y = 0; y < mapHeight; y ++) {
- if (mapFlags[x,y] == 0 && map[x,y] == tileType) {
- List<Coord> newRegion = GetRegionTiles(x,y);
- regions.Add(newRegion);
- foreach (Coord tile in newRegion) {
- mapFlags[tile.tileX, tile.tileY] = 1;
- }
- }
- }
- }
- return regions;
- }
- List<Coord> GetRegionTiles(int startX, int startY) {
- List<Coord> tiles = new List<Coord> ();
- int[,] mapFlags = new int[mapWidth,mapHeight];
- int tileType = map [startX, startY];
- Queue<Coord> queue = new Queue<Coord> ();
- queue.Enqueue (new Coord (startX, startY));
- mapFlags [startX, startY] = 1;
- while (queue.Count > 0) {
- Coord tile = queue.Dequeue();
- tiles.Add(tile);
- for (int x = tile.tileX - 1; x <= tile.tileX + 1; x++) {
- for (int y = tile.tileY - 1; y <= tile.tileY + 1; y++) {
- if (IsInMapRange(x,y) && (y == tile.tileY || x == tile.tileX)) {
- if (mapFlags[x,y] == 0 && map[x,y] == tileType) {
- mapFlags[x,y] = 1;
- queue.Enqueue(new Coord(x,y));
- }
- }
- }
- }
- }
- return tiles;
- }
- bool IsInMapRange(int x, int y) {
- return x >= 0 && x < mapWidth && y >= 0 && y < mapHeight;
- }
- void RandomFillMap() {
- if (useRandomSeed) {
- seed = Time.time.ToString();
- }
- System.Random pseudoRandom = new System.Random(seed.GetHashCode());
- for (int x = 0; x < mapWidth; x ++) {
- for (int y = 0; y < mapHeight; y ++) {
- if (x == 0 || x == mapWidth-1 || y == 0 || y == mapHeight -1) {
- map[x,y] = 1;
- }
- else {
- map[x,y] = (pseudoRandom.Next(0,100) < randomFillPercent)? 1: 0;
- }
- }
- }
- }
- void SmoothMap() {
- for (int x = 0; x < mapWidth; x ++) {
- for (int y = 0; y < mapHeight; y ++) {
- int neighbourWallTiles = GetSurroundingWallCount(x,y);
- if (neighbourWallTiles > 4)
- map[x,y] = 1;
- else if (neighbourWallTiles < 4)
- map[x,y] = 0;
- }
- }
- }
- int GetSurroundingWallCount(int gridX, int gridY) {
- int wallCount = 0;
- for (int neighbourX = gridX - 1; neighbourX <= gridX + 1; neighbourX ++) {
- for (int neighbourY = gridY - 1; neighbourY <= gridY + 1; neighbourY ++) {
- if (IsInMapRange(neighbourX,neighbourY)) {
- if (neighbourX != gridX || neighbourY != gridY) {
- wallCount += map[neighbourX,neighbourY];
- }
- }
- else {
- wallCount ++;
- }
- }
- }
- return wallCount;
- }
- struct Coord {
- public int tileX;
- public int tileY;
- public Coord(int x, int y) {
- tileX = x;
- tileY = y;
- }
- }
- class Room : IComparable<Room> {
- public List<Coord> tiles;
- public List<Coord> edgeTiles;
- public List<Room> connectedRooms;
- public int roomSize;
- public bool isAccessibleFromMainRoom;
- public bool isMainRoom;
- public Room() {
- }
- public Room(List<Coord> roomTiles, int[,] map) {
- tiles = roomTiles;
- roomSize = tiles.Count;
- connectedRooms = new List<Room>();
- edgeTiles = new List<Coord>();
- foreach (Coord tile in tiles) {
- for (int x = tile.tileX-1; x <= tile.tileX+1; x++) {
- for (int y = tile.tileY-1; y <= tile.tileY+1; y++) {
- if (x == tile.tileX || y == tile.tileY) {
- if (map[x,y] == 1) {
- edgeTiles.Add(tile);
- }
- }
- }
- }
- }
- }
- public void SetAccessibleFromMainRoom() {
- if (!isAccessibleFromMainRoom) {
- isAccessibleFromMainRoom = true;
- foreach (Room connectedRoom in connectedRooms) {
- connectedRoom.SetAccessibleFromMainRoom();
- }
- }
- }
- public static void ConnectRooms(Room roomA, Room roomB) {
- if (roomA.isAccessibleFromMainRoom) {
- roomB.SetAccessibleFromMainRoom ();
- } else if (roomB.isAccessibleFromMainRoom) {
- roomA.SetAccessibleFromMainRoom();
- }
- roomA.connectedRooms.Add (roomB);
- roomB.connectedRooms.Add (roomA);
- }
- public bool IsConnected(Room otherRoom) {
- return connectedRooms.Contains(otherRoom);
- }
- public int CompareTo(Room otherRoom) {
- return otherRoom.roomSize.CompareTo (roomSize);
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement