Generated buildings
This commit is contained in:
@ -11,8 +11,11 @@ namespace TransportGame.Generator
|
||||
{
|
||||
public class BuildingGenerator
|
||||
{
|
||||
private const float LotSquareSize = 1f;
|
||||
private const float LotSpacing = 0.1f;
|
||||
Random random = new Random();
|
||||
|
||||
private float LotSquareMinSize { get { return ConfigManager.Buildgen.LotSquareMinSize; } }
|
||||
private float LotSquareMaxSize { get { return ConfigManager.Buildgen.LotSquareMaxSize; } }
|
||||
private float LotSpacing { get { return ConfigManager.Buildgen.LotSpacing; } }
|
||||
|
||||
private Map map;
|
||||
QuadTree<RoadNode> nodeTree;
|
||||
@ -20,43 +23,75 @@ namespace TransportGame.Generator
|
||||
|
||||
private void AllocateLots()
|
||||
{
|
||||
float advance = LotSquareSize + LotSpacing;
|
||||
|
||||
// Generate lots for every segment
|
||||
foreach (var pair in map.RoadNetwork.ArticulationSegments)
|
||||
{
|
||||
var seg = pair.Value;
|
||||
var dir = seg.Direction;
|
||||
bool didSomething;
|
||||
var segment = pair.Value;
|
||||
var dir = segment.Direction;
|
||||
var perp = dir.RotateDeg(90);
|
||||
|
||||
float width0 = ConfigManager.Roadgen.SidewalkWidth + ConfigManager.Roadgen.LaneWidth * seg.LanesTo1;
|
||||
float width1 = ConfigManager.Roadgen.SidewalkWidth + ConfigManager.Roadgen.LaneWidth * seg.LanesTo2;
|
||||
float width0 = ConfigManager.Roadgen.SidewalkWidth + ConfigManager.Roadgen.LaneWidth * segment.LanesTo1;
|
||||
float width1 = ConfigManager.Roadgen.SidewalkWidth + ConfigManager.Roadgen.LaneWidth * segment.LanesTo2;
|
||||
|
||||
for (Vector2 pos = seg.Terminal1.Position; (pos - seg.Terminal2.Position).LengthSq > advance * advance; pos += dir * advance)
|
||||
Vector2 start = segment.Terminal1.Position;
|
||||
Vector2 end = segment.Terminal2.Position;
|
||||
Vector2 posL = start, posR = start, nposL, nposR;
|
||||
int attempts = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// Build lot squares
|
||||
Vector2[] left = new Vector2[4];
|
||||
left[0] = pos + perp * (width0 + LotSpacing + LotSquareSize);
|
||||
left[1] = pos + perp * (width0 + LotSpacing);
|
||||
left[2] = pos + dir * LotSquareSize + perp * (width0 + LotSpacing);
|
||||
left[3] = pos + dir * LotSquareSize + perp * (width0 + LotSpacing + LotSquareSize);
|
||||
didSomething = false;
|
||||
float sizeL = random.NextSingle(LotSquareMinSize, LotSquareMaxSize), sizeR = random.NextSingle(LotSquareMinSize, LotSquareMaxSize);
|
||||
nposL = posL + dir * sizeL;
|
||||
nposR = posR + dir * sizeR;
|
||||
|
||||
Vector2[] right = new Vector2[4];
|
||||
right[0] = pos - perp * (width0 + LotSpacing + LotSquareSize);
|
||||
right[1] = pos - perp * (width0 + LotSpacing);
|
||||
right[2] = pos + dir * LotSquareSize - perp * (width0 + LotSpacing);
|
||||
right[3] = pos + dir * LotSquareSize - perp * (width0 + LotSpacing + LotSquareSize);
|
||||
// Left side
|
||||
if ((posL - end).LengthSq >= sizeL * sizeL)
|
||||
{
|
||||
didSomething = true;
|
||||
|
||||
BuildingLot lot0 = new BuildingLot(left);
|
||||
BuildingLot lot1 = new BuildingLot(right);
|
||||
// Build lot squares
|
||||
Vector2[] left = new Vector2[4];
|
||||
left[0] = posL + perp * (width0 + LotSpacing + sizeL);
|
||||
left[1] = posL + perp * (width0 + LotSpacing);
|
||||
left[2] = nposL + perp * (width0 + LotSpacing);
|
||||
left[3] = nposL + perp * (width0 + LotSpacing + sizeL);
|
||||
|
||||
// Test for intersections
|
||||
if (CanAllocate(pos, lot0))
|
||||
lotTree.Add(lot0);
|
||||
BuildingLot lot = new BuildingLot(sizeL, left);
|
||||
|
||||
if (CanAllocate(pos, lot1))
|
||||
lotTree.Add(lot1);
|
||||
}
|
||||
if (CanAllocate(posL, lot))
|
||||
lotTree.Add(lot);
|
||||
|
||||
// Advance
|
||||
posL = nposL;
|
||||
}
|
||||
|
||||
// Right side
|
||||
if ((posR - end).LengthSq >= sizeR * sizeR)
|
||||
{
|
||||
didSomething = true;
|
||||
|
||||
// Build lot squares
|
||||
Vector2[] right = new Vector2[4];
|
||||
right[0] = posR - perp * (width1 + LotSpacing + sizeR);
|
||||
right[1] = posR - perp * (width1 + LotSpacing);
|
||||
right[2] = nposR - perp * (width1 + LotSpacing);
|
||||
right[3] = nposR - perp * (width1 + LotSpacing + sizeR);
|
||||
|
||||
BuildingLot lot = new BuildingLot(sizeR, right);
|
||||
|
||||
if (CanAllocate(posL, lot))
|
||||
lotTree.Add(lot);
|
||||
|
||||
// Advance
|
||||
posR = nposR;
|
||||
}
|
||||
|
||||
if (!didSomething)
|
||||
attempts++;
|
||||
|
||||
} while (attempts < ConfigManager.Buildgen.MaxLotAttempts);
|
||||
}
|
||||
|
||||
// Done
|
||||
@ -65,26 +100,34 @@ namespace TransportGame.Generator
|
||||
|
||||
private bool CanAllocate(Vector2 pos, BuildingLot lot0)
|
||||
{
|
||||
if (!lotTree.Boundary.Contains(pos))
|
||||
return false;
|
||||
|
||||
// Test other lots
|
||||
Rectangle lotArea = new Rectangle(pos.X - 2 * LotSquareSize, pos.Y - 2 * LotSquareSize, pos.X + 2 * LotSquareSize, pos.Y + 2 * LotSquareSize);
|
||||
Rectangle lotArea = new Rectangle(
|
||||
pos.X - 2f * LotSquareMaxSize,
|
||||
pos.Y - 2f * LotSquareMaxSize,
|
||||
pos.X + 2f * LotSquareMaxSize,
|
||||
pos.Y + 2f * LotSquareMaxSize);
|
||||
|
||||
foreach (var lot in lotTree.Query(lotArea))
|
||||
{
|
||||
if (BuildingLot.Intersect(lot0, lot))
|
||||
if (BuildingLot.DoesIntersect(lot0, lot))
|
||||
return false;
|
||||
}
|
||||
|
||||
// Test nearby roads
|
||||
Rectangle roadArea = new Rectangle(
|
||||
pos.X - 2 * ConfigManager.Roadgen.HighwaySegmentLength,
|
||||
pos.Y - 2 * ConfigManager.Roadgen.HighwaySegmentLength,
|
||||
pos.X + 2 * ConfigManager.Roadgen.HighwaySegmentLength,
|
||||
pos.Y + 2 * ConfigManager.Roadgen.HighwaySegmentLength);
|
||||
pos.X - 1.1f * ConfigManager.Roadgen.HighwaySegmentLength,
|
||||
pos.Y - 1.1f * ConfigManager.Roadgen.HighwaySegmentLength,
|
||||
pos.X + 1.1f * ConfigManager.Roadgen.HighwaySegmentLength,
|
||||
pos.Y + 1.1f * ConfigManager.Roadgen.HighwaySegmentLength);
|
||||
|
||||
foreach (var node in nodeTree.Query(roadArea))
|
||||
{
|
||||
foreach (var segment in node.ArticulationSegments)
|
||||
{
|
||||
if (BuildingLot.Intersect(lot0, segment.AsLineSegment()))
|
||||
if (BuildingLot.DoesIntersect(lot0, segment.AsLineSegment()))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -95,12 +138,69 @@ namespace TransportGame.Generator
|
||||
|
||||
private void GenerateBuildings()
|
||||
{
|
||||
foreach (var lot in map.BuildingLots)
|
||||
map.Buildings.Add(GenerateBuilding(lot));
|
||||
}
|
||||
|
||||
Polygon GeneratePrimitivePolygon(BuildingLot lot)
|
||||
{
|
||||
int sides = random.Next(3, 8); // Number of sides
|
||||
float angle = 2 * (float)Math.PI / sides; // Angle between sides
|
||||
|
||||
float radius = random.NextSingle(lot.Size * 0.25f, lot.Size * 0.75f) / 2; // Length of a side
|
||||
Vector2 current = lot.Position + new Vector2(random.NextSingle(-lot.Size / 4, lot.Size / 4), random.NextSingle(-lot.Size / 4, lot.Size / 4));
|
||||
Vector2 dir = new Vector2(random.NextSingle(), random.NextSingle()).Normalized * radius;
|
||||
|
||||
List<Vector2> points = new List<Vector2>();
|
||||
|
||||
for (int i = 0; i < sides; i++)
|
||||
{
|
||||
points.Add(current);
|
||||
current = current + dir;
|
||||
dir = dir.Rotate(angle);
|
||||
}
|
||||
|
||||
return new Polygon(points);
|
||||
}
|
||||
|
||||
private Building GenerateBuilding(BuildingLot lot)
|
||||
{
|
||||
Building b = new Building();
|
||||
|
||||
int levelCount = random.Next(1, ConfigManager.Buildgen.MaxBuildingLevels);
|
||||
b.LevelHeights = new float[levelCount];
|
||||
b.Polygons = new Polygon[levelCount][];
|
||||
|
||||
for (int i = levelCount - 1; i >= 0; --i)
|
||||
{
|
||||
List<Polygon> polys = new List<Polygon>();
|
||||
|
||||
for (int j = 0; j < 1 + random.Next(ConfigManager.Buildgen.MaxPolygonsPerLevel); j++)
|
||||
polys.Add(GeneratePrimitivePolygon(lot));
|
||||
|
||||
if (i + 1 < levelCount)
|
||||
{
|
||||
polys.AddRange(b.Polygons[i + 1]);
|
||||
b.LevelHeights[i] = random.NextSingle(0, b.LevelHeights[i + 1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
b.LevelHeights[i] = random.NextSingle(0, ConfigManager.Buildgen.MaxBuildingHeight);
|
||||
}
|
||||
|
||||
for (int j = 0; j < random.Next(ConfigManager.Buildgen.MaxPolygonsPerLevel); j++)
|
||||
polys.Add(GeneratePrimitivePolygon(lot));
|
||||
|
||||
b.Polygons[i] = polys.ToArray();
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
public void Generate(Map map)
|
||||
{
|
||||
this.map = map;
|
||||
map.Buildings = new List<Building>();
|
||||
|
||||
// Construct node tree
|
||||
nodeTree = new QuadTree<RoadNode>(0, 0, map.Width, map.Height);
|
||||
|
@ -35,6 +35,10 @@ namespace TransportGame.Generator
|
||||
RoadGenerator roadGenerator = new RoadGenerator();
|
||||
roadGenerator.Generate(map);
|
||||
|
||||
// Generate buildings
|
||||
BuildingGenerator buildingGenerator = new BuildingGenerator();
|
||||
buildingGenerator.Generate(map);
|
||||
|
||||
// Done
|
||||
return map;
|
||||
}
|
||||
|
Reference in New Issue
Block a user