1
Fork 0
slime-blood-and-pain/Assets/Scripts/Map.cs

244 lines
7.7 KiB
C#
Raw Normal View History

2019-04-27 11:38:29 +00:00
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
2019-04-27 14:15:38 +00:00
[System.Serializable]
public class ImpossibleCorridorError : System.Exception
{
public ImpossibleCorridorError() { }
public ImpossibleCorridorError(string message) : base(message) { }
public ImpossibleCorridorError(string message, System.Exception inner) : base(message, inner) { }
protected ImpossibleCorridorError(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context) : base(info, context) { }
}
public class IntVector2 {
public int x;
public int y;
public IntVector2(int x, int y) {
this.x = x;
this.y = y;
}
}
public class MapRoom {
public readonly IntVector2 start;
public readonly IntVector2 end;
public readonly int mapSize;
public MapRoom(int mapSize) {
this.mapSize = mapSize;
start = new IntVector2(Random.Range(0, mapSize), Random.Range(0, mapSize));
end = new IntVector2(Random.Range(0, mapSize), Random.Range(0, mapSize));
if(start.x > end.x) {
int swap = start.x;
start.x = end.x;
end.x = swap;
}
if(start.y > end.y) {
int swap = start.y;
start.y = end.y;
end.y = swap;
}
}
public IntVector2 RightCorridorAttachment() {
if(end.x+1 >= mapSize) {
throw new ImpossibleCorridorError();
}
return new IntVector2(end.x+1, Random.Range(start.y, end.y+1));
}
public IntVector2 LeftCorridorAttachment() {
if(start.x-1 <= 0) {
throw new ImpossibleCorridorError();
}
return new IntVector2(start.x-1, Random.Range(start.y, start.y-1));
}
public IntVector2 TopCorridorAttachment() {
if(end.y+1 >= mapSize) {
throw new ImpossibleCorridorError();
}
return new IntVector2(Random.Range(start.x, end.x+1), end.y+1);
}
public IntVector2 BottomCorridorAttachment() {
if(start.y-1 <= 0) {
throw new ImpossibleCorridorError();
}
return new IntVector2(Random.Range(start.x, end.x+1), start.y-1);
}
}
public enum CorridorModes {
bottomToTop,
topToBottom,
rightToLeft,
leftToRight
}
public class MapCorridor {
public readonly IntVector2 start;
public readonly IntVector2 end;
public readonly bool horizontal_priority;
public MapCorridor(MapRoom from, MapRoom to, int mapSize) {
List<CorridorModes> corridorModes = new List<CorridorModes>();
//Find allowed CorridorModes
if(from.end.y <= to.start.y) corridorModes.Add(CorridorModes.bottomToTop);
if(from.start.y >= to.end.y) corridorModes.Add(CorridorModes.topToBottom);
if(from.end.x <= to.start.y) corridorModes.Add(CorridorModes.rightToLeft);
if(from.start.y >= to.end.y) corridorModes.Add(CorridorModes.leftToRight);
//Select and use a corridor mode
CorridorModes corridorMode = corridorModes[Random.Range(0, corridorModes.Count)];
if(corridorMode == CorridorModes.bottomToTop) {
start = from.BottomCorridorAttachment();
end = to.TopCorridorAttachment();
}
if(corridorMode == CorridorModes.topToBottom) {
start = from.TopCorridorAttachment();
end = to.BottomCorridorAttachment();
}
if(corridorMode == CorridorModes.rightToLeft) {
start = from.RightCorridorAttachment();
end = to.LeftCorridorAttachment();
}
if(corridorMode == CorridorModes.leftToRight) {
start = from.LeftCorridorAttachment();
end = to.RightCorridorAttachment();
}
//50%
horizontal_priority = Random.Range(0f, 1f) >= 0.5f;
}
}
2019-04-27 11:38:29 +00:00
public class Map : MonoBehaviour
{
2019-04-27 12:21:33 +00:00
[BeforeStartAttribute]
public int mapSize = 30;
[BeforeStartAttribute]
public int roomsToGenerate = 5;
[BeforeStartAttribute]
2019-04-27 11:38:29 +00:00
public Sprite wallSprite;
2019-04-27 14:15:38 +00:00
[BeforeStartAttribute]
public Sprite roomSprite;
[BeforeStartAttribute]
public Sprite corridorSprite;
[BeforeStartAttribute]
2019-04-27 11:38:29 +00:00
public GameObject tilePrefab;
2019-04-27 14:15:38 +00:00
private GameObject[,] tiles;
private List<MapRoom> rooms;
private System.Random rnd;
2019-04-27 11:38:29 +00:00
public Tile GetTile(int x, int y) {
GameObject tileObject = tiles[x, y];
Tile tile = tileObject.GetComponent<Tile>();
return tile;
}
2019-04-27 14:15:38 +00:00
private void InitTile(int x, int y, bool walkable, Sprite tile_sprite, bool roomPart) {
2019-04-27 11:38:29 +00:00
Tile tile = GetTile(x, y);
2019-04-27 14:15:38 +00:00
tile.walkable = walkable;
2019-04-27 12:21:33 +00:00
tile.sprite = tile_sprite;
2019-04-27 14:15:38 +00:00
tile.roomPart = roomPart;
2019-04-27 11:38:29 +00:00
}
private void FillWithWalls() {
2019-04-27 12:21:33 +00:00
for(int x = 0; x < mapSize; x++) {
for(int y = 0; y < mapSize; y++) {
GameObject tileObject = Instantiate(tilePrefab, transform);
tileObject.transform.position = new Vector3(x, y, 0);
tiles[x, y] = tileObject;
Tile tile = tileObject.GetComponent<Tile>();
tile.walkable = false;
tile.sprite = wallSprite;
2019-04-27 11:38:29 +00:00
}
}
}
2019-04-27 14:15:38 +00:00
private void PlaceRoom(MapRoom mr) {
for(int x = mr.start.x; x <= mr.end.x; x++) {
for(int y = mr.start.y; y <= mr.end.y; y++) {
InitTile(x, y, true, roomSprite, true);
2019-04-27 11:38:29 +00:00
}
}
}
2019-04-27 14:15:38 +00:00
private bool ScanRoom(MapRoom mr) {
//Returns true if the room can be safely placed
for(int x = Mathf.Clamp(mr.start.x-1, 0, mapSize-1); x <= Mathf.Clamp(mr.end.x+1, 0, mapSize-1); x++) {
for(int y = Mathf.Clamp(mr.start.y-1, 0, mapSize-1); y <= Mathf.Clamp(mr.end.y+1, 0, mapSize-1); y++) {
if(GetTile(x, y).walkable) {
return false;
}
2019-04-27 11:38:29 +00:00
}
}
2019-04-27 14:15:38 +00:00
return true;
}
private void PlaceCorridor(MapCorridor mc) {
IntVector2 cursor = new IntVector2(mc.start.x, mc.start.y);
InitTile(cursor.x, cursor.y, true, corridorSprite, false);
if(mc.horizontal_priority) {
while(cursor.x != mc.end.x) {
if(cursor.x > mc.end.x) cursor.x--;
else cursor.x++;
InitTile(cursor.x, cursor.y, true, corridorSprite, false);
}
while(cursor.y != mc.end.y) {
if(cursor.y > mc.end.y) cursor.y--;
else cursor.y++;
InitTile(cursor.x, cursor.y, true, corridorSprite, false);
2019-04-27 11:38:29 +00:00
}
2019-04-27 14:15:38 +00:00
}
else
{
while(cursor.y != mc.end.y) {
if(cursor.y > mc.end.y) cursor.y--;
else cursor.y++;
InitTile(cursor.x, cursor.y, true, corridorSprite, false);
}
while(cursor.x != mc.end.x) {
if(cursor.x > mc.end.x) cursor.x--;
else cursor.x++;
InitTile(cursor.x, cursor.y, true, corridorSprite, false);
2019-04-27 11:38:29 +00:00
}
}
}
private void GenerateMap() {
FillWithWalls();
2019-04-27 14:15:38 +00:00
while(rooms.Count < roomsToGenerate) {
MapRoom room = new MapRoom(mapSize);
if(ScanRoom(room)) {
PlaceRoom(room);
rooms.Add(room);
}
if(rooms.Count > 1) {
MapRoom from = rooms[Random.Range(0, rooms.Count)];
MapRoom to = rooms[Random.Range(0, rooms.Count)];
MapCorridor corridor = new MapCorridor(from, to, mapSize);
}
2019-04-27 12:21:33 +00:00
}
2019-04-27 11:38:29 +00:00
}
private void Start()
{
2019-04-27 14:15:38 +00:00
//Initialize everything
2019-04-27 12:21:33 +00:00
tiles = new GameObject[mapSize, mapSize];
2019-04-27 14:15:38 +00:00
rooms = new List<MapRoom>();
rnd = new System.Random();
2019-04-27 11:38:29 +00:00
//Generate the map
GenerateMap();
}
}