@@ -0,0 +1,53 @@
namespace DLS.LD39.Generation
{
using Data;
using Utility;

public class RectRoom : Room
{
public RectRoom(int x, int y, int width, int height, string id, RoomType type = null) : base(new IntVector2(x, y), id, type)
{
Rect = new IntRect(x, y, width, height);
CreateCornerConnectors();
SetTiles();
}

public RectRoom(IntRect rect, string id, RoomType type = null) : base(rect.BottomLeft, id, type)
{
Rect = rect;
CreateCornerConnectors();
SetTiles();
}

public int Width
{
get { return Rect.Width; }
}

public int Height
{
get { return Rect.Height; }
}

public IntRect Rect { get; private set; }

private void CreateCornerConnectors()
{
AddConnector(Rect.TopLeft);
AddConnector(Rect.TopRight);
AddConnector(Rect.BottomLeft);
AddConnector(Rect.BottomRight);
}

private void SetTiles()
{
for (var x = Rect.Left; x <= Rect.Right; x++)
{
for (var y = Rect.Bottom; y <= Rect.Top; y++)
{
AddTile(new IntVector2(x, y));
}
}
}
}
}
@@ -5,45 +5,23 @@
using System;
using System.Collections.Generic;
using Data;
using UnityEngine;
using Utility;

public class Room : MapElement, IEquatable<Room>
public abstract class Room : MapElement, IEquatable<Room>
{
private HashSet<IntVector2> _tiles = new HashSet<IntVector2>();
private readonly HashSet<IntVector2> _tiles = new HashSet<IntVector2>();
private readonly HashSet<Room> _neighbors = new HashSet<Room>();

public Room(int x, int y, int width, int height, string id, RoomType type=null) : base(id)
protected Room(IntVector2 position, string id, RoomType type=null) : base(id)
{
MapRect = new IntRect(x, y, width, height);
Template = type;
UpdateTiles();
Position = position;
}

public RoomType Template
{
get;
private set;
}

public int Width
{
get
{
return MapRect.Width;
}
}

public int Height
{
get
{
return MapRect.Height;
}
}
public RoomType Template { get; private set; }

public IntRect MapRect
{
get; private set;
}
public IntVector2 Position { get; private set; }

public override IEnumerable<IntVector2> Tiles
{
@@ -53,11 +31,6 @@ public override IEnumerable<IntVector2> Tiles
}
}

public IntVector2 TranslateLocalTileCoords(int x, int y)
{
return new IntVector2(x + MapRect.X, y + MapRect.Y);
}

public bool UnitInRoom(GameUnit unit)
{
var map = unit.Position.CurrentTile.Map;
@@ -73,46 +46,79 @@ public bool UnitInRoom(GameUnit unit)
return false;
}

public void SetTiles(TileMap map, string tileID="default")
public virtual bool Overlaps(Room other)
{
foreach (var tile in _tiles)
{
map.SetTileAt(tile.X, tile.Y, tileID);
}
return other != null && other._tiles.Overlaps(_tiles);
}

public override bool TileInElement(int x, int y)
{
return _tiles.Contains(new IntVector2(x, y));
}

public IntVector2 TransformLocalTileCoords(int lX, int lY)
{
return TransformLocalTileCoords(new IntVector2(lX, lY));
}

public IntVector2 TransformLocalTileCoords(IntVector2 localCoords)
{
return Position + localCoords;
}

public void AddNeighbor(Room neighbor)
{
_neighbors.Add(neighbor);
}

public bool Equals(Room other)
{
return other != null && other.MapRect.Equals(MapRect);
if (ReferenceEquals(null, other)) return false;
return ReferenceEquals(this, other) || string.Equals(ID, other.ID);
}

public bool Overlaps(Room other)
public override bool Equals(object obj)
{
return other != null && MapRect.Intersects(other.MapRect);
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
return obj.GetType() == GetType() && Equals((Room) obj);
}
public bool Overlaps(Room other, int padding)

public override int GetHashCode()
{
var paddedRect = new IntRect(MapRect.X - padding, MapRect.Y - padding,
MapRect.Width + padding, MapRect.Height + padding);
return other != null && paddedRect.Intersects(other.MapRect);
return ID != null ? ID.GetHashCode() : 0;
}

private void UpdateTiles()
public void SetTiles(TileMap map, string tileID = "default")
{
_tiles.Clear();
for (var xPos = 0; xPos < MapRect.Width; xPos++)
foreach (var tile in _tiles)
{
for (var yPos = 0; yPos < MapRect.Height; yPos++)
{
_tiles.Add(new IntVector2(xPos + MapRect.X, yPos + MapRect.Y));
}
map.SetTileAt(tile.X, tile.Y, tileID);
}
}

public override bool TileInElement(int x, int y)
protected void AddTile(IntVector2 tile)
{
return _tiles.Contains(new IntVector2(x, y));
_tiles.Add(tile);
}

protected void AddTiles(IEnumerable<IntVector2> tiles)
{
foreach (var tile in tiles)
{
_tiles.Add(tile);
}
}

protected void AddTiles(IntRect tiles)
{
for (var x = tiles.X; x <= tiles.BottomRight.X; x++)
{
for (var y = tiles.Y; y <= tiles.TopRight.Y; y++)
{
_tiles.Add(new IntVector2(x, y));
}
}
}
}
}
@@ -131,88 +131,89 @@ private Room GetRandomRoom(RoomRollTable rollTable, int roomIdx)

private bool CanPlaceRoom(Room candidateRoom)
{
return RoomIsEntirelyContainedWithinMap(_map, candidateRoom) && !_rooms.Values.Any(
r => candidateRoom.Overlaps(r, 1));
return false;
//return RoomIsEntirelyContainedWithinMap(_map, candidateRoom) && !_rooms.Values.Any(
// r => candidateRoom.Overlaps(r, 1));
}

private void BuildCorridors()
{
var rooms = _rooms.Values.ToList();
for (var i = 0; i < rooms.Count - 1; i++)
{
var roomA = rooms[i];
var roomB = rooms[i + 1];
//var rooms = _rooms.Values.ToList();
//for (var i = 0; i < rooms.Count - 1; i++)
//{
// var roomA = rooms[i];
// var roomB = rooms[i + 1];

var verticalDistance = Mathf.Abs(roomA.MapRect.Center.Y - roomB.MapRect.Center.Y);
var horizontalDistance = Mathf.Abs(roomA.MapRect.Center.X - roomB.MapRect.Center.X);
// var verticalDistance = Mathf.Abs(roomA.MapRect.Center.Y - roomB.MapRect.Center.Y);
// var horizontalDistance = Mathf.Abs(roomA.MapRect.Center.X - roomB.MapRect.Center.X);

if (horizontalDistance > verticalDistance)
{
ConnectHorizontalRooms(roomA, roomB);
}
else
{
ConnectVerticalRooms(roomA, roomB);
}
}
// if (horizontalDistance > verticalDistance)
// {
// ConnectHorizontalRooms(roomA, roomB);
// }
// else
// {
// ConnectVerticalRooms(roomA, roomB);
// }
//}
}

private void ConnectHorizontalRooms(Room a, Room b)
{
var left = a.MapRect.BottomRight.X < b.MapRect.BottomLeft.X
? a
: b;
var right = left.Equals(a) ? b : a;
//var left = a.MapRect.BottomRight.X < b.MapRect.BottomLeft.X
// ? a
// : b;
//var right = left.Equals(a) ? b : a;

var leftConnectorX = left.MapRect.BottomRight.X;
var leftConnectorY = Random.Range(left.MapRect.BottomRight.Y, left.MapRect.TopRight.Y);
//var leftConnectorX = left.MapRect.BottomRight.X;
//var leftConnectorY = Random.Range(left.MapRect.BottomRight.Y, left.MapRect.TopRight.Y);

var rightConnectorX = right.MapRect.BottomLeft.X - 1;
var rightConnectorY = Random.Range(right.MapRect.BottomLeft.Y, right.MapRect.TopLeft.Y);
//var rightConnectorX = right.MapRect.BottomLeft.X - 1;
//var rightConnectorY = Random.Range(right.MapRect.BottomLeft.Y, right.MapRect.TopLeft.Y);

var corridor = new SingleWidthCorridor();
corridor.AddNode(new IntVector2(leftConnectorX, leftConnectorY));
//var corridor = new SingleWidthCorridor();
//corridor.AddNode(new IntVector2(leftConnectorX, leftConnectorY));

var xDist = Mathf.Abs(leftConnectorX - rightConnectorX);
var yDist = Mathf.Abs(leftConnectorY - rightConnectorY);
if (xDist > 2 && yDist > 2)
{
corridor.AddNode(new IntVector2(leftConnectorX + (xDist / 2), leftConnectorY));
}
//var xDist = Mathf.Abs(leftConnectorX - rightConnectorX);
//var yDist = Mathf.Abs(leftConnectorY - rightConnectorY);
//if (xDist > 2 && yDist > 2)
//{
// corridor.AddNode(new IntVector2(leftConnectorX + (xDist / 2), leftConnectorY));
//}

corridor.AddNode(new IntVector2(rightConnectorX, rightConnectorY));
corridor.SetTiles(_map, "white");
//corridor.AddNode(new IntVector2(rightConnectorX, rightConnectorY));
//corridor.SetTiles(_map, "white");
}

private void ConnectVerticalRooms(Room a, Room b)
{
var top = a.MapRect.BottomRight.Y > b.MapRect.TopRight.Y
? a
: b;
var bottom = top.Equals(a) ? b : a;
//var top = a.MapRect.BottomRight.Y > b.MapRect.TopRight.Y
// ? a
// : b;
//var bottom = top.Equals(a) ? b : a;

var bottomConnectorY = bottom.MapRect.TopLeft.Y;
var bottomConnectorX = Random.Range(bottom.MapRect.TopLeft.X, bottom.MapRect.TopRight.X);
//var bottomConnectorY = bottom.MapRect.TopLeft.Y;
//var bottomConnectorX = Random.Range(bottom.MapRect.TopLeft.X, bottom.MapRect.TopRight.X);

var topConnectorY = top.MapRect.BottomLeft.Y - 1;
var topConnectorX = Random.Range(top.MapRect.BottomLeft.X, top.MapRect.BottomRight.X);
//var topConnectorY = top.MapRect.BottomLeft.Y - 1;
//var topConnectorX = Random.Range(top.MapRect.BottomLeft.X, top.MapRect.BottomRight.X);

var corridor = new SingleWidthCorridor();
corridor.AddNode(new IntVector2(bottomConnectorX, bottomConnectorY));
corridor.AddNode(new IntVector2(topConnectorX, topConnectorY));
corridor.SetTiles(_map, "red");
//var corridor = new SingleWidthCorridor();
//corridor.AddNode(new IntVector2(bottomConnectorX, bottomConnectorY));
//corridor.AddNode(new IntVector2(topConnectorX, topConnectorY));
//corridor.SetTiles(_map, "red");
}

private void SpawnPlayerUnits()
{
var tile1 = _map.GetTile(_rooms["entry"].TranslateLocalTileCoords(2, 1));
var tile2 = _map.GetTile(_rooms["entry"].TranslateLocalTileCoords(2, 2));
var tile3 = _map.GetTile(_rooms["entry"].TranslateLocalTileCoords(2, 3));
var tile4 = _map.GetTile(_rooms["entry"].TranslateLocalTileCoords(3, 2));
UnitSpawner.Instance.SpawnUnit("test_player", tile1);
UnitSpawner.Instance.SpawnUnit("test_player", tile2);
UnitSpawner.Instance.SpawnUnit("test_player", tile3);
UnitSpawner.Instance.SpawnUnit("test_player", tile4);
//var tile1 = _map.GetTile(_rooms["entry"].TranslateLocalTileCoords(2, 1));
//var tile2 = _map.GetTile(_rooms["entry"].TranslateLocalTileCoords(2, 2));
//var tile3 = _map.GetTile(_rooms["entry"].TranslateLocalTileCoords(2, 3));
//var tile4 = _map.GetTile(_rooms["entry"].TranslateLocalTileCoords(3, 2));
//UnitSpawner.Instance.SpawnUnit("test_player", tile1);
//UnitSpawner.Instance.SpawnUnit("test_player", tile2);
//UnitSpawner.Instance.SpawnUnit("test_player", tile3);
//UnitSpawner.Instance.SpawnUnit("test_player", tile4);
}

private void SpawnBadGuys(TileMap map, Room room)
@@ -243,10 +244,11 @@ private void SpawnBadGuys(TileMap map, Room room)

private bool RoomIsEntirelyContainedWithinMap(TileMap map, Room room)
{
var upLeft = room.MapRect.TopLeft;
var botRight = room.MapRect.BottomRight;
return false;
//var upLeft = room.MapRect.TopLeft;
//var botRight = room.MapRect.BottomRight;

return map.GetTile(upLeft) != null && map.GetTile(botRight) != null;
//return map.GetTile(upLeft) != null && map.GetTile(botRight) != null;
}
}
}
@@ -1,24 +1,25 @@
namespace DLS.LD39.Generation.Subdivider
{
using System;
using Utility;

public class Connection : IEquatable<Connection>
{
public Connection(Room a, Room b)
public Connection(Room a, IntVector2 aConnect, Room b, IntVector2 bConnect)
{
RoomA = a;
AConnect = aConnect;
RoomB = b;
BConnect = bConnect;
}

public Room RoomA
{
get; private set;
}
public Room RoomA { get; private set; }

public Room RoomB
{
get; private set;
}
public IntVector2 AConnect { get; private set; }

public Room RoomB { get; private set; }

public IntVector2 BConnect { get; private set; }

public bool Equals(Connection other)
{
@@ -32,8 +33,7 @@ public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((Connection) obj);
return obj.GetType() == GetType() && Equals((Connection) obj);
}

public override int GetHashCode()
@@ -1,9 +1,11 @@
namespace DLS.LD39.Generation.Subdivider
{
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Utility;
using Random = UnityEngine.Random;

public static class ConnectionBuilder
{
@@ -71,22 +73,26 @@ public static SubdividedMap GetMap(RectNode root, int minRoomSize, int maxRoomSi
var startRoom = roomA;
var currentRoom = roomA;
var targetRoom = roomB;
var currentTile = startRoom.Rect.Center;
var targetTile = targetRoom.Rect.Center;
IntVector2 currentTile, targetTile;
MapElement.GetClosestConnectionPair(startRoom, targetRoom, out currentTile, out targetTile);

while (true)
{
var tileRoom = PointInRoom(currentTile, roomMap.Values);
if (targetRoom.Equals(tileRoom))
if (currentTile.Equals(targetTile))
{
connections.Add(new Connection(currentRoom, targetRoom));
IntVector2 a, b;
MapElement.GetClosestConnectionPair(currentRoom, targetRoom, out a, out b);
connections.Add(new Connection(currentRoom, a, targetRoom, b));
currentRoom.AddNeighbor(targetRoom);
targetRoom.AddNeighbor(currentRoom);
break;
}
if (tileRoom != null && !currentRoom.Equals(tileRoom))
{
connections.Add(new Connection(currentRoom, tileRoom));
IntVector2 a, b;
MapElement.GetClosestConnectionPair(currentRoom, tileRoom, out a, out b);
connections.Add(new Connection(currentRoom, a, tileRoom, b));
currentRoom.AddNeighbor(tileRoom);
tileRoom.AddNeighbor(currentRoom);
currentRoom = tileRoom;
@@ -100,7 +106,7 @@ public static SubdividedMap GetMap(RectNode root, int minRoomSize, int maxRoomSi

private static Room PointInRoom(IntVector2 tile, IEnumerable<Room> rooms)
{
return rooms.FirstOrDefault(room => room.Rect.Contains(tile));
return rooms.FirstOrDefault(room => room.TileInElement(tile));
}

private static IntVector2 GetNextTile(IntVector2 currentTile, IntVector2 target)
@@ -140,7 +146,7 @@ private static Room BuildRoom(RectNode node, int minRoomSize, int maxRoomSide)
node.Rect.Center.Y - size.Y / 2);

var roomRect = new IntRect(pos, size.X, size.Y);
return new Room(roomRect, node);
return new RectRoom(roomRect, Guid.NewGuid().ToString());
}

private static RectNode GetRandomRoom(RectNode node)
@@ -23,16 +23,22 @@ public static class RecursiveRectSplitter
RectNode.CutDirection direction, bool alternate, float splitChance=1.0f,
int requiredLevels=2)
{
if (node.Depth > requiredLevels && Random.Range(0.0f, 1.0f) <= splitChance)
Debug.LogFormat("Attempting to split node with depth {0}", node.Depth);
var roll = Random.Range(0.0f, 1.0f);
Debug.LogFormat("Split check roll: {0}", roll);
if (node.Depth > requiredLevels && roll >= splitChance)
{
Debug.LogFormat("Failed split roll");
return;
}
if (!node.Split(direction, minSize, maxDepth))
{
Debug.LogFormat("Too small to split");
return;
}

var nextDirection = GetNextDirection(direction, alternate);
Debug.LogFormat("Splitting {0}", nextDirection);

RecursivelySplitNode(node.Left, minSize, maxDepth, nextDirection, alternate, splitChance, requiredLevels);
RecursivelySplitNode(node.Right, minSize, maxDepth, nextDirection, alternate, splitChance, requiredLevels);
@@ -1,41 +1,99 @@
namespace DLS.LD39.Generation.Subdivider
{
using System.Collections.Generic;
using System.Linq;
using Utility;

public class Room
public abstract class RoomOld
{
private HashSet<Room> _neighbors = new HashSet<Room>();
private readonly HashSet<Room> _neighbors = new HashSet<Room>();
private readonly HashSet<IntVector2> _tiles = new HashSet<IntVector2>();
private readonly HashSet<IntVector2> _hallConnectors = new HashSet<IntVector2>();

public Room(IntRect roomRect, RectNode roomNode)
protected RoomOld(RectNode roomNode)
{
Rect = roomRect;
RoomNode = roomNode;

if (RoomNode.Parent == null)
{
return;
}

SiblingNode = RoomNode.Parent.Left == RoomNode
SiblingNode = Equals(RoomNode.Parent.Left, RoomNode)
? roomNode.Parent.Right
: roomNode.Parent.Left;
}

public IEnumerable<IntVector2> Tiles { get { return _tiles; } }

public RectNode SiblingNode { get; private set; }

public RectNode RoomNode { get; private set; }

public IntRect Rect { get; private set; }
public abstract IntVector2 Center { get; }

public abstract bool ContainsTile(IntVector2 position);

public IEnumerable<Room> Neighbors
{
get { return _neighbors; }
}

public IEnumerable<IntVector2> Connectors
{
get { return _hallConnectors; }
}

public void AddNeighbor(Room neighbor)
{
_neighbors.Add(neighbor);
}

public static void GetClosestPair(Room a, Room b, out IntVector2 aConnect, out IntVector2 bConnect)
{
var minDistance = int.MaxValue;
aConnect = a.Connectors.First();
bConnect = b.Connectors.First();
foreach (var connectorA in a.Connectors)
{
foreach (var connectorB in b.Connectors)
{
var distance = IntVector2.ManhattanDistance(connectorA, connectorB);
if (distance >= minDistance) continue;
aConnect = connectorA;
bConnect = connectorB;
minDistance = distance;
}
}
}

public IntVector2 GetClosestConnector(IntVector2 target)
{
if (!_hallConnectors.Any())
{
throw new System.Exception("No connectors");
}

var min = int.MaxValue;
IntVector2 closest = new IntVector2(0, 0);
foreach (var connector in _hallConnectors)
{
var distance = IntVector2.ManhattanDistance(connector, target);
if (distance >= min) continue;
min = distance;
closest = connector;
}
return closest;
}

protected bool AddTile(IntVector2 tile)
{
return _tiles.Add(tile);
}

protected bool AddConnector(IntVector2 newConnector)
{
return _hallConnectors.Add(newConnector);
}
}
}
@@ -43,74 +43,67 @@ public IntRect(int x, int y, int w, int h)

public int X
{
get
{
return _x1;
}
get { return _x1; }
}

public int Y
{
get
{
return _y1;
}
get { return _y1; }
}

public int Width
{
get
{
return _w;
}
get { return _w; }
}

public int Height
{
get
{
return _h;
}
get { return _h; }
}

public int Left
{
get { return _x1; }
}

public int Right
{
get { return _x2; }
}

public int Top
{
get { return _y2; }
}

public int Bottom
{
get { return _y1; }
}

public IntVector2 Center
{
get
{
return _center;
}
get { return _center; }
}

public IntVector2 TopLeft
{
get
{
return _topLeft;
}
get { return _topLeft; }
}

public IntVector2 TopRight
{
get
{
return _topRight;
}
get { return _topRight; }
}

public IntVector2 BottomLeft
{
get
{
return _botLeft;
}
get { return _botLeft; }
}

public IntVector2 BottomRight
{
get
{
return _botRight;
}
get { return _botRight; }
}

public override bool Equals(object obj)
@@ -121,7 +114,7 @@ public override bool Equals(object obj)
}
return Equals(obj as IntRect);
}

public override int GetHashCode()
{
return SimpleHashBuilder.GetHash(_x1, _y1, _w, _h);
@@ -135,10 +128,10 @@ public override string ToString()
public bool Equals(IntRect other)
{
return other != null &&
_x1 == other._x1 &&
_y1 == other._y1 &&
_w == other._w &&
_h == other._h;
_x1 == other._x1 &&
_y1 == other._y1 &&
_w == other._w &&
_h == other._h;
}

public bool Contains(IntVector2 point)
@@ -48,6 +48,16 @@ public Vector3 AsVector3()
return new Vector3(_x, _y, 0);
}

public static float Distance(IntVector2 a, IntVector2 b)
{
return Mathf.Sqrt(Mathf.Pow(b.X - a.X, 2) + Mathf.Pow(b.Y - a.Y, 2));
}

public static int ManhattanDistance(IntVector2 a, IntVector2 b)
{
return Mathf.Abs(b.X - a.X) + Mathf.Abs(b.Y - a.Y);
}

public override int GetHashCode()
{
return SimpleHashBuilder.GetHash(_x, _y);