Generated buildings
This commit is contained in:
parent
352f212ae9
commit
4b61f0bdb5
BIN
Documentation/Pictures/funnyresult.png
Normal file
BIN
Documentation/Pictures/funnyresult.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.7 MiB |
@ -54,11 +54,15 @@
|
||||
<Compile Include="Assets\Scripts\Generator\RoadGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Generator\TerrainGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Biome.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Building.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\BuildingLot.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Config\BuildingGeneratorConfig.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Config\RoadGeneratorConfig.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Config\TerrainGeneratorConfig.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\IPositionable.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\LineSegment.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Map.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Polygon.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Rectangle.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Road\RoadNetwork.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Road\RoadNode.cs" />
|
||||
@ -67,6 +71,7 @@
|
||||
<Compile Include="Assets\Scripts\Model\Vector2.cs" />
|
||||
<Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\BuildingMeshGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\InitializeScript.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\RoadMeshGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\TerrainGeneratorScript.cs" />
|
||||
@ -75,6 +80,7 @@
|
||||
<Compile Include="Assets\Scripts\Utils\ColorHelper.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\Expression.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\Logger.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\MeshExtensions.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\QuadTree.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\RandomExtensions.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\Range.cs" />
|
||||
|
@ -54,11 +54,15 @@
|
||||
<Compile Include="Assets\Scripts\Generator\RoadGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Generator\TerrainGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Biome.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Building.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\BuildingLot.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Config\BuildingGeneratorConfig.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Config\RoadGeneratorConfig.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Config\TerrainGeneratorConfig.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\IPositionable.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\LineSegment.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Map.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Polygon.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Rectangle.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Road\RoadNetwork.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Road\RoadNode.cs" />
|
||||
@ -67,6 +71,7 @@
|
||||
<Compile Include="Assets\Scripts\Model\Vector2.cs" />
|
||||
<Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\BuildingMeshGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\InitializeScript.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\RoadMeshGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\TerrainGeneratorScript.cs" />
|
||||
@ -75,6 +80,7 @@
|
||||
<Compile Include="Assets\Scripts\Utils\ColorHelper.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\Expression.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\Logger.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\MeshExtensions.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\QuadTree.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\RandomExtensions.cs" />
|
||||
<Compile Include="Assets\Scripts\Utils\Range.cs" />
|
||||
|
@ -3,7 +3,7 @@
|
||||
<noiseOctaves>9</noiseOctaves>
|
||||
<noiseNonLinearPower>2.4</noiseNonLinearPower>
|
||||
<waterNonLinearPower>1.9</waterNonLinearPower>
|
||||
<elevationScale>0.001</elevationScale>
|
||||
<elevationScale>0.00075</elevationScale>
|
||||
<erodePoints>100</erodePoints>
|
||||
<erodeIterations>60</erodeIterations>
|
||||
<erodeAmountPercent>0.1</erodeAmountPercent>
|
||||
|
BIN
Game/Assets/Data/Materials/building.mat
Normal file
BIN
Game/Assets/Data/Materials/building.mat
Normal file
Binary file not shown.
8
Game/Assets/Data/Materials/building.mat.meta
Normal file
8
Game/Assets/Data/Materials/building.mat.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 269eb1f1b18ec284784864c4015500d7
|
||||
timeCreated: 1433922839
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -19,7 +19,7 @@ TextureImporter:
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
@ -45,7 +45,7 @@ TextureImporter:
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: -1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
|
@ -19,7 +19,7 @@ TextureImporter:
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
@ -45,7 +45,7 @@ TextureImporter:
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: -1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
|
@ -19,7 +19,7 @@ TextureImporter:
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
@ -45,7 +45,7 @@ TextureImporter:
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: -1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
|
@ -19,7 +19,7 @@ TextureImporter:
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
@ -45,7 +45,7 @@ TextureImporter:
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: -1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
|
@ -19,7 +19,7 @@ TextureImporter:
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
@ -45,7 +45,7 @@ TextureImporter:
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: -1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
|
@ -19,7 +19,7 @@ TextureImporter:
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
@ -45,7 +45,7 @@ TextureImporter:
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: -1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
|
@ -19,7 +19,7 @@ TextureImporter:
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
@ -45,7 +45,7 @@ TextureImporter:
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: -1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
|
@ -19,7 +19,7 @@ TextureImporter:
|
||||
externalNormalMap: 0
|
||||
heightScale: .25
|
||||
normalMapFilter: 0
|
||||
isReadable: 0
|
||||
isReadable: 1
|
||||
grayScaleToAlpha: 0
|
||||
generateCubemap: 0
|
||||
cubemapConvolution: 0
|
||||
@ -45,7 +45,7 @@ TextureImporter:
|
||||
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||
spritePixelsToUnits: 100
|
||||
alphaIsTransparency: 0
|
||||
textureType: -1
|
||||
textureType: 5
|
||||
buildTargetSettings: []
|
||||
spriteSheet:
|
||||
sprites: []
|
||||
|
Binary file not shown.
@ -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;
|
||||
}
|
||||
|
20
Game/Assets/Scripts/Model/Building.cs
Normal file
20
Game/Assets/Scripts/Model/Building.cs
Normal file
@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace TransportGame.Model
|
||||
{
|
||||
public class Building
|
||||
{
|
||||
/// <summary>
|
||||
/// From lowest to highest level
|
||||
/// </summary>
|
||||
public Polygon[][] Polygons { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// From lowest to highest level
|
||||
/// </summary>
|
||||
public float[] LevelHeights { get; set; }
|
||||
}
|
||||
}
|
12
Game/Assets/Scripts/Model/Building.cs.meta
Normal file
12
Game/Assets/Scripts/Model/Building.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ef412bd6ccb705428e5569cf84b018f
|
||||
timeCreated: 1433489978
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TransportGame.Business;
|
||||
using TransportGame.Utils;
|
||||
|
||||
namespace TransportGame.Model
|
||||
{
|
||||
@ -13,21 +14,54 @@ namespace TransportGame.Model
|
||||
/// </summary>
|
||||
public Vector2[] Points { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the size of the lot
|
||||
/// </summary>
|
||||
public float Size { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the building lot
|
||||
/// </summary>
|
||||
public BuildingLot()
|
||||
{
|
||||
Points = new Vector2[4];
|
||||
}
|
||||
|
||||
public BuildingLot(params Vector2[] points)
|
||||
/// <summary>
|
||||
/// Initializes lot with given size
|
||||
/// </summary>
|
||||
/// <param name="size">size</param>
|
||||
public BuildingLot(float size)
|
||||
{
|
||||
Points = new Vector2[4];
|
||||
Size = size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes lot with given points and size
|
||||
/// </summary>
|
||||
/// <param name="size">Size</param>
|
||||
/// <param name="points">Points</param>
|
||||
public BuildingLot(float size, params Vector2[] points)
|
||||
{
|
||||
Points = points;
|
||||
Size = size;
|
||||
}
|
||||
|
||||
public BuildingLot(IEnumerable<Vector2> points)
|
||||
/// <summary>
|
||||
/// Initializes lot with given points and size
|
||||
/// </summary>
|
||||
/// <param name="size">Size</param>
|
||||
/// <param name="points">Points</param>
|
||||
public BuildingLot(float size, IEnumerable<Vector2> points)
|
||||
{
|
||||
Points = points.ToArray();
|
||||
Size = size;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the lot position
|
||||
/// </summary>
|
||||
public Vector2 Position
|
||||
{
|
||||
get { return Points.Aggregate((x, y) => x + y) / Points.Length; }
|
||||
@ -39,9 +73,9 @@ namespace TransportGame.Model
|
||||
/// <param name="a">First lot</param>
|
||||
/// <param name="b">Second lot</param>
|
||||
/// <returns></returns>
|
||||
public static bool Intersect(BuildingLot a, BuildingLot b)
|
||||
public static bool DoesIntersect(BuildingLot a, BuildingLot b)
|
||||
{
|
||||
return (a.Position - b.Position).LengthSq <= ConfigManager.Buildgen.LotSquareSize + ConfigManager.Buildgen.LotSpacing;
|
||||
return Algorithmss.DoPolygonsIntersect(a.Points, b.Points);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -50,7 +84,7 @@ namespace TransportGame.Model
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
public static bool Intersect(BuildingLot a, LineSegment b)
|
||||
public static bool DoesIntersect(BuildingLot a, LineSegment b)
|
||||
{
|
||||
for (int i = 0; i < a.Points.Length; i++)
|
||||
{
|
||||
|
12
Game/Assets/Scripts/Model/BuildingLot.cs.meta
Normal file
12
Game/Assets/Scripts/Model/BuildingLot.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8d4e9031660798e43954c6c698daf966
|
||||
timeCreated: 1433365105
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -8,19 +8,49 @@ namespace TransportGame.Model.Config
|
||||
public class BuildingGeneratorConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// Lot size
|
||||
/// Minimum lot size
|
||||
/// </summary>
|
||||
public float LotSquareSize { get; set; }
|
||||
public float LotSquareMinSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum lot size
|
||||
/// </summary>
|
||||
public float LotSquareMaxSize { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Space between lots
|
||||
/// </summary>
|
||||
public float LotSpacing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of attempts to generate a lot in a specific area
|
||||
/// </summary>
|
||||
public int MaxLotAttempts { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of levels on a building
|
||||
/// </summary>
|
||||
public int MaxBuildingLevels { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum height for a building
|
||||
/// </summary>
|
||||
public float MaxBuildingHeight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of primitive polygons to be generated per level
|
||||
/// </summary>
|
||||
public int MaxPolygonsPerLevel { get; set; }
|
||||
|
||||
public BuildingGeneratorConfig()
|
||||
{
|
||||
LotSquareSize = 1f;
|
||||
LotSquareMinSize = 5f;
|
||||
LotSquareMaxSize = 20f;
|
||||
LotSpacing = 0.1f;
|
||||
MaxLotAttempts = 3;
|
||||
MaxBuildingHeight = 20f;
|
||||
MaxBuildingLevels = 5;
|
||||
MaxPolygonsPerLevel = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 67b392479c775904c970253005f9c856
|
||||
timeCreated: 1433365105
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -75,6 +75,9 @@ namespace TransportGame.Model
|
||||
[XmlArrayItem("center")]
|
||||
public List<Vector2> PopulationCenters { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the range of one population center (distance how far it influences)
|
||||
/// </summary>
|
||||
public float PopulationCenterRange { get; set; }
|
||||
|
||||
/// <summary>
|
||||
@ -89,6 +92,12 @@ namespace TransportGame.Model
|
||||
[XmlElement("lots")]
|
||||
public List<BuildingLot> BuildingLots { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the buildings
|
||||
/// </summary>
|
||||
[XmlElement("buildings")]
|
||||
public List<Building> Buildings { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
247
Game/Assets/Scripts/Model/Polygon.cs
Normal file
247
Game/Assets/Scripts/Model/Polygon.cs
Normal file
@ -0,0 +1,247 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TransportGame.Utils;
|
||||
|
||||
namespace TransportGame.Model
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a polygon
|
||||
/// </summary>
|
||||
public class Polygon : IPositionable
|
||||
{
|
||||
#region Private types
|
||||
|
||||
private struct Edge
|
||||
{
|
||||
public int U, V;
|
||||
|
||||
public Edge(int U, int V)
|
||||
{
|
||||
this.U = U;
|
||||
this.V = V;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the points that define the polygon
|
||||
/// </summary>
|
||||
public Vector2[] Points { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the gravitational center
|
||||
/// </summary>
|
||||
public Vector2 Position
|
||||
{
|
||||
get { return Points.Aggregate((x, y) => x + y) / Points.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes polygon
|
||||
/// </summary>
|
||||
public Polygon()
|
||||
{
|
||||
Points = new Vector2[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes polygon using given points
|
||||
/// </summary>
|
||||
/// <param name="points">Points</param>
|
||||
public Polygon(IEnumerable<Vector2> points)
|
||||
{
|
||||
Points = points.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes polygon using given points
|
||||
/// </summary>
|
||||
/// <param name="points">Points</param>
|
||||
public Polygon(params Vector2[] points)
|
||||
{
|
||||
Points = points;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Compares angle between two NORMALIZED vectors.
|
||||
/// </summary>
|
||||
/// <param name="a"></param>
|
||||
/// <param name="b"></param>
|
||||
/// <returns></returns>
|
||||
private static float CompareAngle(Vector2 a, Vector2 b)
|
||||
{
|
||||
float sin = Vector2.Cross(a, b);
|
||||
float cos = Vector2.Dot(a, b);
|
||||
|
||||
if (sin >= 0 && cos >= 0)
|
||||
return sin;
|
||||
|
||||
else if (sin >= 0 && cos <= 0)
|
||||
return 1 + Math.Abs(cos);
|
||||
|
||||
else if (sin <= 0 && cos <= 0)
|
||||
return 2 + Math.Abs(sin);
|
||||
|
||||
else return 3 + cos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the union between given polygons
|
||||
/// </summary>
|
||||
/// <param name="polys">Polygons</param>
|
||||
/// <returns>Polygon representing union</returns>
|
||||
public static Polygon Union(params Polygon[] polys)
|
||||
{
|
||||
return Union(polys);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the union between given polygons
|
||||
/// </summary>
|
||||
/// <param name="polys">Polygons</param>
|
||||
/// <returns>Polygon representing union</returns>
|
||||
public static Polygon Union(IEnumerable<Polygon> polys)
|
||||
{
|
||||
List<Vector2> vertices = new List<Vector2>();
|
||||
List<Edge> edges = new List<Edge>();
|
||||
List<Vector2> union = new List<Vector2>();
|
||||
|
||||
foreach (var poly in polys)
|
||||
{
|
||||
// Add all points
|
||||
for (int i = 0; i < poly.Points.Length; i++)
|
||||
{
|
||||
int j = (i + 1) % poly.Points.Length;
|
||||
|
||||
// Get/add first point
|
||||
int indexi = vertices.IndexOf(poly.Points[i]);
|
||||
if (indexi == -1)
|
||||
{
|
||||
vertices.Add(poly.Points[i]);
|
||||
indexi = vertices.Count - 1;
|
||||
}
|
||||
|
||||
// Get/add second point
|
||||
int indexj = vertices.IndexOf(poly.Points[j]);
|
||||
if (indexj == -1)
|
||||
{
|
||||
vertices.Add(poly.Points[j]);
|
||||
indexj = vertices.Count - 1;
|
||||
}
|
||||
|
||||
// Add edge
|
||||
edges.Add(new Edge(indexi, indexj));
|
||||
}
|
||||
}
|
||||
|
||||
// Intersect edges
|
||||
for (int i = 0; i < edges.Count; i++)
|
||||
for (int j = i + 1; j < edges.Count; j++)
|
||||
{
|
||||
LineSegment a = new LineSegment(vertices[edges[i].U], vertices[edges[i].V]);
|
||||
LineSegment b = new LineSegment(vertices[edges[j].U], vertices[edges[j].V]);
|
||||
|
||||
var inters = LineSegment.Intersect(a, b);
|
||||
if (inters.HasValue && inters.Value != a.P0 && inters.Value != a.P1 && inters.Value != b.P0 && inters.Value != b.P1)
|
||||
{
|
||||
vertices.Add(inters.Value);
|
||||
int index = vertices.Count - 1;
|
||||
|
||||
edges.Add(new Edge(index, edges[i].V));
|
||||
edges[i] = new Edge(edges[i].U, index);
|
||||
edges.Add(new Edge(index, edges[j].V));
|
||||
edges[j] = new Edge(edges[j].U, index);
|
||||
}
|
||||
}
|
||||
|
||||
// Compute union
|
||||
int start = 0;
|
||||
|
||||
// Find starting point
|
||||
for (int i = 0; i < vertices.Count; i++)
|
||||
if (vertices[i].X + vertices[i].Y < vertices[start].X + vertices[start].Y)
|
||||
start = i;
|
||||
|
||||
int v = start, vold = -1;
|
||||
Vector2 prev = vertices[v].Normalized;
|
||||
|
||||
do
|
||||
{
|
||||
union.Add(vertices[v]);
|
||||
|
||||
int newV = -1;
|
||||
float smallestAngle = -1;
|
||||
Vector2 smallestDir = Vector2.Zero;
|
||||
|
||||
foreach (var edge in edges)
|
||||
{
|
||||
if ((edge.U == v || edge.V == v) && edge.V != vold && edge.U != vold)
|
||||
{
|
||||
int otherv = (edge.U == v) ? edge.V : edge.U;
|
||||
Vector2 dir = (vertices[otherv] - vertices[v]).Normalized;
|
||||
|
||||
// Find smallest angle
|
||||
float cmpAngle = CompareAngle(-prev, dir);
|
||||
if (cmpAngle < smallestAngle || smallestAngle < 0)
|
||||
{
|
||||
newV = otherv;
|
||||
smallestAngle = cmpAngle;
|
||||
smallestDir = dir;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Advance
|
||||
prev = smallestDir;
|
||||
vold = v;
|
||||
v = newV;
|
||||
|
||||
} while (v != start);
|
||||
|
||||
return new Polygon(union);
|
||||
}
|
||||
|
||||
public static bool DoPolygonsIntersect(Polygon a, Polygon b)
|
||||
{
|
||||
foreach (var poly in new[] { a, b })
|
||||
{
|
||||
for (int i = 0; i < poly.Points.Length; i++)
|
||||
{
|
||||
int j = (i + 1) % poly.Points.Length;
|
||||
|
||||
var normal = new Vector2(poly.Points[j].Y - poly.Points[i].Y, poly.Points[i].X - poly.Points[j].X);
|
||||
|
||||
double? minA = null, maxA = null;
|
||||
foreach (var p in a.Points)
|
||||
{
|
||||
var projected = Vector2.Dot(normal, p);
|
||||
if (minA == null || projected < minA)
|
||||
minA = projected;
|
||||
if (maxA == null || projected > maxA)
|
||||
maxA = projected;
|
||||
}
|
||||
|
||||
double? minB = null, maxB = null;
|
||||
foreach (var p in b.Points)
|
||||
{
|
||||
var projected = Vector2.Dot(normal, p);
|
||||
if (minB == null || projected < minB)
|
||||
minB = projected;
|
||||
if (maxB == null || projected > maxB)
|
||||
maxB = projected;
|
||||
}
|
||||
|
||||
if (maxA <= minB || maxB <= minA)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
12
Game/Assets/Scripts/Model/Polygon.cs.meta
Normal file
12
Game/Assets/Scripts/Model/Polygon.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ee96020375a8f3d4bb7a04e9f7a6b05e
|
||||
timeCreated: 1433489979
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
97
Game/Assets/Scripts/Unity/BuildingMeshGenerator.cs
Normal file
97
Game/Assets/Scripts/Unity/BuildingMeshGenerator.cs
Normal file
@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TransportGame.Model;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TransportGame.Unity
|
||||
{
|
||||
public class BuildingMeshGenerator
|
||||
{
|
||||
public Material BuildingMaterial { get; set; }
|
||||
|
||||
private GameObject parent = new GameObject("buildings");
|
||||
private Map map;
|
||||
|
||||
public IEnumerable Generate(Map map)
|
||||
{
|
||||
this.map = map;
|
||||
|
||||
foreach (var building in map.Buildings)
|
||||
{
|
||||
GenerateBuilding(building);
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateBuilding(Building building)
|
||||
{
|
||||
List<Vector3> vertices = new List<Vector3>();
|
||||
List<UnityEngine.Vector2> uv = new List<UnityEngine.Vector2>();
|
||||
List<int> triangles = new List<int>();
|
||||
int vIndex = 0;
|
||||
|
||||
if (building.Polygons.Length == 0)
|
||||
return;
|
||||
|
||||
float terrainHeight = building.Polygons[0].SelectMany(poly => poly.Points).Min(pt => map.GetHeight((int)pt.X, (int)pt.Y));
|
||||
float minY, maxY = terrainHeight;
|
||||
|
||||
for (int i = 0; i < building.Polygons.Length; i++)
|
||||
{
|
||||
// Update minY and maxY
|
||||
minY = maxY;
|
||||
maxY += building.LevelHeights[i];
|
||||
|
||||
for (int p = 0; p < building.Polygons[i].Length; p++)
|
||||
{
|
||||
// Build mesh
|
||||
var center = building.Polygons[i][p].Position;
|
||||
var pts = building.Polygons[i][p].Points;
|
||||
|
||||
for (int j = 0; j < pts.Length; j++)
|
||||
{
|
||||
int k = (j + 1) % pts.Length;
|
||||
|
||||
vertices.Add(new Vector3(pts[j].Y, minY, pts[j].X));
|
||||
vertices.Add(new Vector3(pts[k].Y, minY, pts[k].X));
|
||||
vertices.Add(new Vector3(pts[k].Y, maxY, pts[k].X));
|
||||
vertices.Add(new Vector3(pts[j].Y, maxY, pts[j].X));
|
||||
vertices.Add(new Vector3(center.Y, maxY, center.X));
|
||||
|
||||
uv.Add(new UnityEngine.Vector2(0, 0));
|
||||
uv.Add(new UnityEngine.Vector2(0, 1));
|
||||
uv.Add(new UnityEngine.Vector2(1, 1));
|
||||
uv.Add(new UnityEngine.Vector2(1, 0));
|
||||
uv.Add(new UnityEngine.Vector2(0.5f, 0.5f));
|
||||
|
||||
triangles.AddRange(new[] { vIndex, vIndex + 1, vIndex + 2 });
|
||||
triangles.AddRange(new[] { vIndex, vIndex + 2, vIndex + 3 });
|
||||
triangles.AddRange(new[] { vIndex + 4, vIndex + 3, vIndex + 2 }); // top side
|
||||
|
||||
vIndex = vertices.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Construct mesh
|
||||
Mesh mesh = new Mesh();
|
||||
mesh.vertices = vertices.ToArray();
|
||||
mesh.triangles = triangles.ToArray();
|
||||
mesh.uv = uv.ToArray();
|
||||
mesh.RecalculateNormals();
|
||||
|
||||
// Construct game object
|
||||
GameObject inters = new GameObject("building");
|
||||
inters.transform.parent = parent.transform;
|
||||
|
||||
MeshFilter meshFilter = inters.AddComponent<MeshFilter>();
|
||||
meshFilter.mesh = mesh;
|
||||
|
||||
MeshRenderer meshRenderer = inters.AddComponent<MeshRenderer>();
|
||||
meshRenderer.materials = new[] { BuildingMaterial };
|
||||
}
|
||||
}
|
||||
}
|
12
Game/Assets/Scripts/Unity/BuildingMeshGenerator.cs.meta
Normal file
12
Game/Assets/Scripts/Unity/BuildingMeshGenerator.cs.meta
Normal file
@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 285289bd35a5aac429d15f8fdf99512f
|
||||
timeCreated: 1433859861
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -16,6 +16,7 @@ public class TerrainGeneratorScript : MonoBehaviour
|
||||
public GameObject WaterObject;
|
||||
public Texture2D[] Textures;
|
||||
public Material RoadMaterial;
|
||||
public Material BuildingMaterial;
|
||||
|
||||
// Use this for initialization
|
||||
void Start()
|
||||
@ -54,7 +55,7 @@ public class TerrainGeneratorScript : MonoBehaviour
|
||||
private IEnumerator GenerateMap()
|
||||
{
|
||||
// Generate terrain
|
||||
foreach (var i in Task.RunAsync(GenerateTerrainThread))
|
||||
foreach (var i in Task.Await(GenerateTerrainThread))
|
||||
yield return i;
|
||||
|
||||
// Generate terrain data
|
||||
@ -105,20 +106,62 @@ public class TerrainGeneratorScript : MonoBehaviour
|
||||
|
||||
// Set up textures
|
||||
Logger.Info("Setting up textures...");
|
||||
foreach (var i in SetupSplatmaps(terrainData))
|
||||
BeginSetupSplatmaps(terrainData);
|
||||
|
||||
foreach (var lot in map.BuildingLots)
|
||||
{
|
||||
for (int i = 0; i < lot.Points.Length; i++)
|
||||
{
|
||||
int j = (i + 1) % lot.Points.Length;
|
||||
|
||||
if (!map.IsInside(lot.Points[i]))
|
||||
{
|
||||
Logger.Warning("Generated point not inside: {0}", lot.Points[i]);
|
||||
continue;
|
||||
}
|
||||
if (!map.IsInside(lot.Points[j]))
|
||||
{
|
||||
Logger.Warning("Generated point not inside: {0}", lot.Points[j]);
|
||||
continue;
|
||||
}
|
||||
|
||||
Debug.DrawLine(
|
||||
new Vector3(lot.Points[i].Y, map.GetHeight((int)lot.Points[i].X, (int)lot.Points[i].Y) + 0.5f, lot.Points[i].X),
|
||||
new Vector3(lot.Points[j].Y, map.GetHeight((int)lot.Points[j].X, (int)lot.Points[j].Y) + 0.5f, lot.Points[j].X),
|
||||
Color.yellow, 10000);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate road & building mesh (we run the loops in parallel)
|
||||
Logger.Info("Generating buildings and roads...");
|
||||
|
||||
BuildingMeshGenerator buildingMeshGenerator = new BuildingMeshGenerator();
|
||||
buildingMeshGenerator.BuildingMaterial = BuildingMaterial;
|
||||
var it1 = buildingMeshGenerator.Generate(map).GetEnumerator();
|
||||
|
||||
RoadMeshGenerator roadMeshGenerator = new RoadMeshGenerator();
|
||||
roadMeshGenerator.RoadMaterial = RoadMaterial;
|
||||
var it2 = roadMeshGenerator.Generate(map).GetEnumerator();
|
||||
|
||||
bool stop;
|
||||
do
|
||||
{
|
||||
stop = true;
|
||||
if (it1.MoveNext())
|
||||
{
|
||||
yield return it1.Current;
|
||||
stop = false;
|
||||
}
|
||||
if (it2.MoveNext())
|
||||
{
|
||||
yield return it2.Current;
|
||||
stop = false;
|
||||
}
|
||||
} while (!stop);
|
||||
|
||||
// Finish setting up textures
|
||||
foreach (var i in EndSetupSplatmaps(terrainData))
|
||||
yield return i;
|
||||
|
||||
// Generate road mesh
|
||||
Logger.Info("Generating roads...");
|
||||
RoadMeshGenerator meshGenerator = new RoadMeshGenerator();
|
||||
meshGenerator.RoadMaterial = RoadMaterial;
|
||||
foreach (object i in meshGenerator.Generate(map))
|
||||
yield return i;
|
||||
|
||||
// -- DEBUG --
|
||||
|
||||
foreach (var center in map.PopulationCenters)
|
||||
Debug.DrawLine(new Vector3(center.Y, 0, center.X), new Vector3(center.Y, map.Biome.Height, center.X), Color.yellow, 100000);
|
||||
}
|
||||
|
||||
private float[,,] GenerateSplatData(int alphaWidth, int alphaHeight, int alphaLayers)
|
||||
@ -174,14 +217,21 @@ public class TerrainGeneratorScript : MonoBehaviour
|
||||
return splatData;
|
||||
}
|
||||
|
||||
private IEnumerable SetupSplatmaps(TerrainData terrainData)
|
||||
float[, ,] splatData = null;
|
||||
private Task splatmapsTask = null;
|
||||
|
||||
private void BeginSetupSplatmaps(TerrainData terrainData)
|
||||
{
|
||||
float[, ,] splatData = null;
|
||||
int alphaW = terrainData.alphamapWidth;
|
||||
int alphaH = terrainData.alphamapHeight;
|
||||
int alphaL = terrainData.alphamapLayers;
|
||||
|
||||
foreach (var i in Task.RunAsync(() => splatData = GenerateSplatData(alphaW, alphaH, alphaL)))
|
||||
splatmapsTask = Task.RunAsync(() => splatData = GenerateSplatData(alphaW, alphaH, alphaL));
|
||||
}
|
||||
|
||||
private IEnumerable EndSetupSplatmaps(TerrainData terrainData)
|
||||
{
|
||||
foreach (var i in splatmapsTask.Await())
|
||||
yield return i;
|
||||
|
||||
terrainData.SetAlphamaps(0, 0, splatData);
|
||||
|
@ -2,11 +2,48 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TransportGame.Model;
|
||||
|
||||
namespace TransportGame.Utils
|
||||
{
|
||||
public static class Algorithmss
|
||||
{
|
||||
public static bool DoPolygonsIntersect(Vector2[] a, Vector2[] b)
|
||||
{
|
||||
foreach (var poly in new[] {a, b})
|
||||
{
|
||||
for (int i = 0; i < poly.Length; i++)
|
||||
{
|
||||
int j = (i + 1) % poly.Length;
|
||||
|
||||
var normal = new Vector2(poly[j].Y - poly[i].Y, poly[i].X - poly[j].X);
|
||||
|
||||
double? minA = null, maxA = null;
|
||||
foreach (var p in a)
|
||||
{
|
||||
var projected = Vector2.Dot(normal, p);
|
||||
if (minA == null || projected < minA)
|
||||
minA = projected;
|
||||
if (maxA == null || projected > maxA)
|
||||
maxA = projected;
|
||||
}
|
||||
|
||||
double? minB = null, maxB = null;
|
||||
foreach (var p in b)
|
||||
{
|
||||
var projected = Vector2.Dot(normal, p);
|
||||
if (minB == null || projected < minB)
|
||||
minB = projected;
|
||||
if (maxB == null || projected > maxB)
|
||||
maxB = projected;
|
||||
}
|
||||
|
||||
if (maxA <= minB || maxB <= minA)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,41 +7,55 @@ using System.Threading;
|
||||
|
||||
namespace TransportGame.Utils
|
||||
{
|
||||
public static class Task
|
||||
public class Task
|
||||
{
|
||||
private class TaskInfo
|
||||
public bool? Success { get; private set; }
|
||||
|
||||
private Exception thrownException;
|
||||
private Action action;
|
||||
private Thread thread;
|
||||
|
||||
private Task()
|
||||
{
|
||||
public Action Action { get; set; }
|
||||
public bool? Success { get; set; }
|
||||
public Exception ThrownException { get; set; }
|
||||
}
|
||||
|
||||
private static void RunAsync_ActionThread(object info)
|
||||
{
|
||||
TaskInfo taskInfo = (TaskInfo)info;
|
||||
Task taskInfo = (Task)info;
|
||||
|
||||
try
|
||||
{
|
||||
taskInfo.Action();
|
||||
taskInfo.action();
|
||||
taskInfo.Success = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
taskInfo.ThrownException = ex;
|
||||
taskInfo.thrownException = ex;
|
||||
taskInfo.Success = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable RunAsync(Action action)
|
||||
public static Task RunAsync(Action action)
|
||||
{
|
||||
// Set up task info object
|
||||
TaskInfo taskInfo = new TaskInfo();
|
||||
taskInfo.Action = action;
|
||||
Task taskInfo = new Task();
|
||||
taskInfo.action = action;
|
||||
taskInfo.thread = new Thread(RunAsync_ActionThread);
|
||||
|
||||
// Start thread and wait
|
||||
var thread = new Thread(RunAsync_ActionThread);
|
||||
thread.Start(taskInfo);
|
||||
// Start thread
|
||||
taskInfo.thread.Start(taskInfo);
|
||||
|
||||
// Return task info
|
||||
return taskInfo;
|
||||
}
|
||||
|
||||
public static IEnumerable Await(Action action)
|
||||
{
|
||||
return Task.RunAsync(action).Await();
|
||||
}
|
||||
|
||||
public IEnumerable Await()
|
||||
{
|
||||
// Wait for thread to finish
|
||||
while (thread.ThreadState == ThreadState.Running)
|
||||
yield return null;
|
||||
@ -49,8 +63,8 @@ namespace TransportGame.Utils
|
||||
thread.Join();
|
||||
|
||||
// Rethrow exception
|
||||
if (taskInfo.Success.HasValue && !taskInfo.Success.Value)
|
||||
throw new Exception("Task failed", taskInfo.ThrownException);
|
||||
if (Success.HasValue && !Success.Value)
|
||||
throw new Exception("Task failed", thrownException);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ Global
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
StartupItem = Assembly-CSharp.csproj
|
||||
Policies = $0
|
||||
$0.TextStylePolicy = $1
|
||||
|
@ -29,7 +29,7 @@ Global
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
StartupItem = Assembly-CSharp.csproj
|
||||
Policies = $0
|
||||
$0.TextStylePolicy = $1
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1 +1 @@
|
||||
listen 267420748 1 1
|
||||
listen 3921045144 1 1
|
Binary file not shown.
Binary file not shown.
@ -4,7 +4,7 @@ Direct3D:
|
||||
Version: Direct3D 11.0 [level 11.0]
|
||||
Renderer: NVIDIA GeForce GTX 750 (ID=0x1381)
|
||||
Vendor: NVIDIA
|
||||
VRAM: 968 MB
|
||||
VRAM: 967 MB
|
||||
Begin MonoManager ReloadAssembly
|
||||
Platform assembly: C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\TransportGame_Data\Managed\UnityEngine.dll (this message is harmless)
|
||||
Loading C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\TransportGame_Data\Managed\UnityEngine.dll into Unity Child Domain
|
||||
@ -16,25 +16,82 @@ Platform assembly: C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Transpo
|
||||
Loading C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\TransportGame_Data\Managed\Assembly-UnityScript-firstpass.dll into Unity Child Domain
|
||||
Platform assembly: C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\TransportGame_Data\Managed\UnityEngine.UI.dll (this message is harmless)
|
||||
Loading C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\TransportGame_Data\Managed\UnityEngine.UI.dll into Unity Child Domain
|
||||
Platform assembly: C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\TransportGame_Data\Managed\UnityEngine.UI.dll (this message is harmless)
|
||||
Loading C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\TransportGame_Data\Managed\UnityEngine.UI.dll into Unity Child Domain
|
||||
- Completed reload, in 0.094 seconds
|
||||
- Completed reload, in 0.045 seconds
|
||||
desktop: 1920x1080 60Hz; virtual: 1920x1080 at 0,0
|
||||
<RI> Initializing input.
|
||||
<RI> Input initialized.
|
||||
<RI> Initialized touch support.
|
||||
Platform assembly: C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\TransportGame_Data\Managed\System.Core.dll (this message is harmless)
|
||||
Loading configuration...
|
||||
UnityEngine.Debug:Internal_Log(Int32, String, Object)
|
||||
UnityEngine.Debug:Log(Object)
|
||||
TransportGame.Utils.Logger:Log(Level, String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:66)
|
||||
TransportGame.Utils.Logger:Info(String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:74)
|
||||
InitializeScript:Start() (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Unity\InitializeScript.cs:14)
|
||||
|
||||
(Filename: C:/Users/Tibi/Google Drive/FacultateCY/$ Licenta/Game/Assets/Scripts/Utils/Logger.cs Line: 66)
|
||||
|
||||
Platform assembly: C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\TransportGame_Data\Managed\System.Xml.dll (this message is harmless)
|
||||
Platform assembly: C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\TransportGame_Data\Managed\System.dll (this message is harmless)
|
||||
Unable to find shaders used for the terrain engine. Please include Nature/Terrain/Diffuse shader in Graphics settings.
|
||||
UnityEngine.Terrain:CreateTerrainGameObject(TerrainData)
|
||||
<GenerateMap>c__Iterator0:MoveNext() (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Unity\TerrainGeneratorScript.cs:67)
|
||||
Loading biomes...
|
||||
UnityEngine.Debug:Internal_Log(Int32, String, Object)
|
||||
UnityEngine.Debug:Log(Object)
|
||||
TransportGame.Utils.Logger:Log(Level, String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:66)
|
||||
TransportGame.Utils.Logger:Info(String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:74)
|
||||
InitializeScript:Start() (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Unity\InitializeScript.cs:18)
|
||||
|
||||
[C:/buildslave/unity/build/Runtime/Terrain/SplatMaterials.cpp line 383]
|
||||
(Filename: C:/Users/Tibi/Google Drive/FacultateCY/$ Licenta/Game/Assets/Scripts/Unity/TerrainGeneratorScript.cs Line: 67)
|
||||
(Filename: C:/Users/Tibi/Google Drive/FacultateCY/$ Licenta/Game/Assets/Scripts/Utils/Logger.cs Line: 66)
|
||||
|
||||
Unable to find shaders used for the terrain engine. Please include Nature/Terrain/Diffuse shader in Graphics settings.
|
||||
Loaded biome 'Grassland' from file 'Assets\Data\Biomes\Grassland.xml'.
|
||||
UnityEngine.Debug:Internal_Log(Int32, String, Object)
|
||||
UnityEngine.Debug:Log(Object)
|
||||
TransportGame.Utils.Logger:Log(Level, String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:66)
|
||||
TransportGame.Utils.Logger:Info(String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:74)
|
||||
TransportGame.Business.BiomeManager:LoadBiomes() (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Business\BiomeManager.cs:42)
|
||||
InitializeScript:Start() (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Unity\InitializeScript.cs:19)
|
||||
|
||||
(Filename: C:/buildslave/unity/build/Runtime/Terrain/DetailRenderer.cpp Line: 65)
|
||||
(Filename: C:/Users/Tibi/Google Drive/FacultateCY/$ Licenta/Game/Assets/Scripts/Utils/Logger.cs Line: 66)
|
||||
|
||||
Loaded biome 'Mountain' from file 'Assets\Data\Biomes\Mountain.xml'.
|
||||
UnityEngine.Debug:Internal_Log(Int32, String, Object)
|
||||
UnityEngine.Debug:Log(Object)
|
||||
TransportGame.Utils.Logger:Log(Level, String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:66)
|
||||
TransportGame.Utils.Logger:Info(String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:74)
|
||||
TransportGame.Business.BiomeManager:LoadBiomes() (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Business\BiomeManager.cs:42)
|
||||
InitializeScript:Start() (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Unity\InitializeScript.cs:19)
|
||||
|
||||
(Filename: C:/Users/Tibi/Google Drive/FacultateCY/$ Licenta/Game/Assets/Scripts/Utils/Logger.cs Line: 66)
|
||||
|
||||
Picked biome: Grassland
|
||||
|
||||
(Filename: C:/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineDebug.gen.cpp Line: 56)
|
||||
|
||||
Setting up textures...
|
||||
UnityEngine.Debug:Internal_Log(Int32, String, Object)
|
||||
UnityEngine.Debug:Log(Object)
|
||||
TransportGame.Utils.Logger:Log(Level, String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:66)
|
||||
TransportGame.Utils.Logger:Info(String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:74)
|
||||
<GenerateMap>c__Iterator3:MoveNext() (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Unity\TerrainGeneratorScript.cs:108)
|
||||
|
||||
(Filename: C:/Users/Tibi/Google Drive/FacultateCY/$ Licenta/Game/Assets/Scripts/Utils/Logger.cs Line: 66)
|
||||
|
||||
Generating buildings and roads...
|
||||
UnityEngine.Debug:Internal_Log(Int32, String, Object)
|
||||
UnityEngine.Debug:Log(Object)
|
||||
TransportGame.Utils.Logger:Log(Level, String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:66)
|
||||
TransportGame.Utils.Logger:Info(String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:74)
|
||||
<GenerateMap>c__Iterator3:MoveNext() (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Unity\TerrainGeneratorScript.cs:136)
|
||||
|
||||
(Filename: C:/Users/Tibi/Google Drive/FacultateCY/$ Licenta/Game/Assets/Scripts/Utils/Logger.cs Line: 66)
|
||||
|
||||
Finished generating road mesh.
|
||||
UnityEngine.Debug:Internal_Log(Int32, String, Object)
|
||||
UnityEngine.Debug:Log(Object)
|
||||
TransportGame.Utils.Logger:Log(Level, String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:66)
|
||||
TransportGame.Utils.Logger:Info(String, Object[]) (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Utils\Logger.cs:74)
|
||||
TransportGame.Unity.<Generate>c__Iterator2:MoveNext() (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Unity\RoadMeshGenerator.cs:95)
|
||||
<GenerateMap>c__Iterator3:MoveNext() (at C:\Users\Tibi\Google Drive\FacultateCY\$ Licenta\Game\Assets\Scripts\Unity\TerrainGeneratorScript.cs:155)
|
||||
|
||||
(Filename: C:/Users/Tibi/Google Drive/FacultateCY/$ Licenta/Game/Assets/Scripts/Utils/Logger.cs Line: 66)
|
||||
|
||||
Waiting for finish
|
||||
|
Binary file not shown.
@ -78,6 +78,7 @@
|
||||
<Compile Include="Assets\Scripts\Generator\RoadGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Generator\TerrainGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Biome.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Building.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\BuildingLot.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Config\BuildingGeneratorConfig.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Config\RoadGeneratorConfig.cs" />
|
||||
@ -85,6 +86,7 @@
|
||||
<Compile Include="Assets\Scripts\Model\IPositionable.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\LineSegment.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Map.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Polygon.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Rectangle.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Road\RoadNetwork.cs" />
|
||||
<Compile Include="Assets\Scripts\Model\Road\RoadNode.cs" />
|
||||
@ -93,6 +95,7 @@
|
||||
<Compile Include="Assets\Scripts\Model\Vector2.cs" />
|
||||
<Compile Include="Assets\Scripts\Noise\NoiseGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Noise\PerlinNoiseGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\BuildingMeshGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\InitializeScript.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\RoadMeshGenerator.cs" />
|
||||
<Compile Include="Assets\Scripts\Unity\TerrainGeneratorScript.cs" />
|
||||
|
Loading…
Reference in New Issue
Block a user