/Assets/Scripts/MapGenerator.cs
C# | 512 lines | 422 code | 88 blank | 2 comment | 125 complexity | 7e93cf8824334e62aada9837023bf058 MD5 | raw file
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- using System;
- public class MapGenerator : MonoBehaviour {
- public bool autoCamera = true;
- public PlayerController2D player2D;
- public PlayerController3D player3D;
- public CameraController2D camera2D;
- public CameraController3D camera3D;
- public bool is2D = false;
- private float baseOrthoCameraY = 12f;
- private float baseOrthoCameraZ = -4f;
- private float baseOrthoCameraSize = 36f;
- private MeshGenerator meshGen;
- private int baseWidth = 128;
- private int baseHeight = 72;
- private int baseBorderSize = 10;
- public int width = 128;
- public int height = 72;
- public int borderSize = 10;
- public int wallThreshold = 50;
- public int roomThreshold = 50;
- public int passageWidth = 1;
- public string seed;
- public bool useRandomSeed;
- [Range(0,100)]
- public int randomFillPercent;
- int[,] map;
- void Awake() {
- if (player2D == null)
- player2D = FindObjectOfType<PlayerController2D> ();
- if (player3D == null)
- player3D = FindObjectOfType<PlayerController3D> ();
- if (camera2D == null)
- camera2D = FindObjectOfType<CameraController2D> ();
- if (camera3D == null)
- camera3D = FindObjectOfType<CameraController3D> ();
- meshGen = GetComponent<MeshGenerator> ();
- }
- void Start() {
- SceneInit ();
- GenerateMap ();
- }
- void Update() {
- if (Input.GetMouseButtonDown(0) || Input.GetButtonDown("A")) {
- GenerateMap ();
- }
- if (Input.GetMouseButton(1) || Input.GetButton("B")) {
- SmoothMap ();
- ProcessMap ();
- GenerateMesh ();
- }
- if (Input.GetKeyDown (KeyCode.LeftControl) || Input.GetButtonDown("X")) {
- is2D = !is2D;
- SwapPlayer ();
- SceneInit ();
- GenerateMesh ();
- }
- if (Input.GetKeyDown (KeyCode.LeftAlt) || Input.GetButtonDown ("Y")) {
- autoCamera = !autoCamera;
- SceneInit ();
- }
- }
- void SwapPlayer() {
- // It's now 2D
- if (is2D) {
- player2D.transform.position = new Vector3 (player3D.transform.position.x, player3D.transform.position.z, 0);
- } else {
- player3D.transform.position = new Vector3 (player2D.transform.position.x, player3D.transform.position.y, player2D.transform.position.y);
- }
- }
- void SceneInit() {
- if (is2D) {
- player2D.TurnOn ();
- player3D.TurnOff ();
- camera2D.TurnOn ();
- camera3D.TurnOff ();
- } else {
- player2D.TurnOff ();
- player3D.TurnOn ();
- camera2D.TurnOff ();
- camera3D.TurnOn ();
- }
- camera2D.autoCamera = autoCamera;
- camera3D.autoCamera = autoCamera;
- Camera camera = Camera.main;
- if (autoCamera) {
- float scaledWidth = (float)width / baseWidth;
- float scaledHeight = (float)height / baseHeight;
- float scale = Mathf.Max (scaledWidth, scaledHeight);
- camera.orthographic = true;
- camera.orthographicSize = baseOrthoCameraSize * scale;
- camera.transform.rotation = Quaternion.identity;
- if (is2D) {
- camera.transform.position = new Vector3 (0, 0, -20);
- } else {
- camera.transform.position = new Vector3 (0, baseOrthoCameraY * scale, baseOrthoCameraZ * scale);
- camera.transform.Rotate (new Vector3 (75, 0, 0));
- }
- if (scaledWidth > scaledHeight) {
- borderSize = Mathf.RoundToInt ((baseHeight * scaledWidth - height) / 2) + baseBorderSize;
- } else {
- borderSize = Mathf.RoundToInt ((baseWidth * scaledHeight - width) / 2) + baseBorderSize;
- }
- } else {
- if (is2D) {
- camera2D.SetupCamera ();
- } else {
- camera.orthographic = false;
- camera3D.SetupCamera ();
- }
- }
- }
- void GenerateMap() {
- map = new int[width, height];
- RandomFillMap ();
- for (int i = 0; i < 3; i++) {
- SmoothMap ();
- }
- ProcessMap ();
- GenerateMesh ();
- }
- void GenerateMesh() {
- int[,] borderedMap = new int[width + borderSize * 2, height + borderSize * 2];
- for (int x = 0; x < borderedMap.GetLength(0); x++) {
- for (int y = 0; y < borderedMap.GetLength(1); y++) {
- if (x >= borderSize && x < width + borderSize && y >= borderSize && y < height + borderSize) {
- borderedMap [x, y] = map [x - borderSize, y - borderSize];
- } else {
- borderedMap [x, y] = 1;
- }
- }
- }
- meshGen.is2D = is2D;
- meshGen.GenerateMesh (borderedMap, 1);
- }
- //
- void ProcessMap() {
- List<List<Coord>> wallRegions = GetRegions (1);
- foreach (List<Coord> wallRegion in wallRegions) {
- if (wallRegion.Count < wallThreshold) {
- foreach (Coord tile in wallRegion) {
- map [tile.tileX, tile.tileY] = 0;
- }
- }
- }
- List<List<Coord>> roomRegions = GetRegions (0);
- List<Room> survivingRooms = new List<Room> ();
- foreach (List<Coord> roomRegion in roomRegions) {
- if (roomRegion.Count < roomThreshold) {
- 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;
- ConnectClosesRooms (survivingRooms);
- }
- void ConnectClosesRooms(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);
- ConnectClosesRooms (allRooms, true);
- }
- if (!forceAccessibilityFromMainRoom) {
- ConnectClosesRooms (allRooms, true);
- }
- }
- void CreatePassage(Room roomA, Room roomB, Coord tileA, Coord tileB) {
- Room.ConnectRooms (roomA, roomB);
- List<Coord> line = GetLine (tileA, tileB);
- foreach (Coord c in line) {
- DrawCircle (c, passageWidth);
- }
- }
- 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 (-width / 2 + 0.5f + tile.tileX, 2, -height / 2 + 0.5f + tile.tileY);
- }
- List<List<Coord>> GetRegions(int tileType) {
- List<List<Coord>> regions = new List<List<Coord>> ();
- int[,] mapFlags = new int[width, height];
- for (int x = 0; x < width; x++) {
- for (int y = 0; y < height; 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[width, height];
- 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 < width && y >= 0 && y < height;
- }
- void RandomFillMap() {
- if (useRandomSeed) {
- seed = Time.time.ToString ();
- }
- System.Random rngod = new System.Random (seed.GetHashCode ());
- for (int x = 0; x < width; x++) {
- for (int y = 0; y < height; y++) {
- if (x == 0 || x == width - 1 || y == 0 || y == height - 1)
- map [x, y] = 1;
- else
- map [x, y] = (rngod.Next (0, 100) < randomFillPercent) ? 1 : 0;
- }
- }
- }
- void SmoothMap() {
- for (int x = 0; x < width; x++) {
- for (int y = 0; y < height; y++) {
- int neighborWallCount = GetSurroundingWallCount (x, y);
- if (neighborWallCount > 4)
- map [x, y] = 1;
- else if (neighborWallCount < 4)
- map [x, y] = 0;
- }
- }
- }
- int GetSurroundingWallCount(int x, int y) {
- int wallCount = 0;
- for (int i = x - 1; i <= x + 1; i++) {
- for (int j = y - 1; j <= y + 1; j++) {
- if (IsInMapRange(i,j)) {
- if (i != x || j != y) {
- wallCount += map [i, j];
- }
- } 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);
- }
- }
- }