Updated project to unity 5, finalized terrain generation
This commit is contained in:
19
Game/Assets/Scripts/Generator/RoadGenerator.cs
Normal file
19
Game/Assets/Scripts/Generator/RoadGenerator.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TransportGame.Model;
|
||||
|
||||
namespace Assets.Scripts.Generator
|
||||
{
|
||||
public class RoadGenerator
|
||||
{
|
||||
public RoadGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
public void Generate(Map map)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
@ -1,234 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using TransportGame.Business;
|
||||
using TransportGame.Model;
|
||||
|
||||
namespace TransportGame.Generator
|
||||
{
|
||||
/// <summary>
|
||||
/// Simulates water erosion
|
||||
/// </summary>
|
||||
public class TerrainEroder
|
||||
{
|
||||
#region Constants
|
||||
|
||||
/// <summary> Direction vector (X)</summary>
|
||||
/// <remarks>
|
||||
/// In order: Center, North, North-East, East, South-East, South, South-West, West, North-West
|
||||
/// </remarks>
|
||||
readonly static private int[] DirectionsX = { 0, 0, 1, 1, 1, 0, -1, -1, -1 };
|
||||
|
||||
/// <summary> Direction vector (Y)</summary>
|
||||
/// <remarks>
|
||||
/// In order: Center, North, North-East, East, South-East, South, South-West, West, North-West
|
||||
/// </remarks>
|
||||
readonly static private int[] DirectionsY = { 0, -1, -1, 0, 1, 1, 1, 0, -1 };
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets the terrain to erode
|
||||
/// </summary>
|
||||
public Map Terrain { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
protected int SpringCount { get { return ConfigurationManager.TerrGenConfig.ErodePoints; } }
|
||||
protected int IterationCount { get { return ConfigurationManager.TerrGenConfig.ErodeIterations; } }
|
||||
protected float ErosionAmount { get { return ConfigurationManager.TerrGenConfig.ErodeAmountPercent; } }
|
||||
|
||||
#region Private variables
|
||||
|
||||
private Random random = new Random();
|
||||
private float[,] water;
|
||||
private int[] springsX;
|
||||
private int[] springsY;
|
||||
|
||||
#endregion
|
||||
|
||||
public TerrainEroder(Map terrain)
|
||||
{
|
||||
this.Terrain = terrain;
|
||||
}
|
||||
|
||||
public void Erode()
|
||||
{
|
||||
Initialize();
|
||||
GenerateSprings();
|
||||
|
||||
for (int i = 0; i < IterationCount; i++)
|
||||
NextIteration();
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
// Initialize matrices
|
||||
water = new float[Terrain.Width, Terrain.Height];
|
||||
}
|
||||
|
||||
private void GenerateSprings()
|
||||
{
|
||||
// Step 1: Generate random points, which will be the water springs
|
||||
springsX = new int[SpringCount];
|
||||
springsY = new int[SpringCount];
|
||||
|
||||
for (int i = 0; i < SpringCount; i++)
|
||||
{
|
||||
springsX[i] = random.Next(0, Terrain.Width);
|
||||
springsY[i] = random.Next(0, Terrain.Height);
|
||||
}
|
||||
|
||||
// Step 2: Find local maximums, where the springs are placed
|
||||
bool changed;
|
||||
int iterations = 100;
|
||||
|
||||
do
|
||||
{
|
||||
changed = false;
|
||||
for (int i = 0; i < SpringCount; i++)
|
||||
{
|
||||
// Find best neighbour
|
||||
float maxHeight = Terrain[springsX[i], springsY[i]];
|
||||
int maxDir = 0;
|
||||
|
||||
ForEachDirection(springsX[i], springsY[i], (dx, dy, dir) =>
|
||||
{
|
||||
if (Terrain[dx, dy] >= maxHeight)
|
||||
{
|
||||
maxHeight = Terrain[dx, dy];
|
||||
maxDir = dir;
|
||||
}
|
||||
});
|
||||
|
||||
if (maxDir > 0)
|
||||
{
|
||||
springsX[i] += DirectionsX[maxDir];
|
||||
springsY[i] += DirectionsY[maxDir];
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
--iterations;
|
||||
} while (changed && iterations > 0);
|
||||
}
|
||||
|
||||
private void NextIteration()
|
||||
{
|
||||
Step1_RainAndErode();
|
||||
Step2_MoveWater();
|
||||
Step3_Evaporate();
|
||||
}
|
||||
|
||||
private void Step1_RainAndErode()
|
||||
{
|
||||
// Springs generate a lot of water
|
||||
for (int i = 0; i < SpringCount; i++)
|
||||
water[springsX[i], springsY[i]] += 100f;
|
||||
|
||||
// Rain in the rest of the terrain
|
||||
for (int x = 0; x < Terrain.Width; x++)
|
||||
for (int y = 0; y < Terrain.Height; y++)
|
||||
{
|
||||
water[x, y] += 1f;
|
||||
|
||||
// Erode some terrain
|
||||
Terrain[x, y] -= ErosionAmount * water[x, y];
|
||||
}
|
||||
}
|
||||
|
||||
private void Step2_MoveWater()
|
||||
{
|
||||
for (int x = 0; x < Terrain.Width; x++)
|
||||
for (int y = 0; y < Terrain.Height; y++)
|
||||
{
|
||||
List<int> directions = new List<int>();
|
||||
|
||||
// Find relevant directions
|
||||
ForEachDirection(x, y, (dx, dy, dir) =>
|
||||
{
|
||||
if (Level(x, y) > Level(dx, dy))
|
||||
directions.Add(dir);
|
||||
});
|
||||
|
||||
// Order directions by level
|
||||
directions.Sort((dir1, dir2) =>
|
||||
{
|
||||
float level1 = Level(x + DirectionsX[dir1], y + DirectionsY[dir1]);
|
||||
float level2 = Level(x + DirectionsX[dir2], y + DirectionsY[dir2]);
|
||||
|
||||
return Convert.ToInt32(100 * (level1 - level2));
|
||||
});
|
||||
|
||||
// Distribute water
|
||||
for (int dirIndex = 0; dirIndex < directions.Count; dirIndex++)
|
||||
{
|
||||
int dir = directions[dirIndex];
|
||||
|
||||
// We distribute all the water equally to cells from
|
||||
// directions 0..dir.
|
||||
float distributeAmount = water[x, y] / (dirIndex + 1);
|
||||
|
||||
// If the resulting level is higher than the level of the next direction,
|
||||
// we only add the level difference
|
||||
if (dirIndex < directions.Count - 1)
|
||||
{
|
||||
int dx = x + DirectionsX[dir], dy = y + DirectionsY[dir];
|
||||
int dx1 = x + DirectionsX[directions[dirIndex + 1]], dy1 = y + DirectionsY[directions[dirIndex + 1]];
|
||||
|
||||
distributeAmount = Math.Min(distributeAmount, Level(dx1, dy1) - Level(dx, dy));
|
||||
}
|
||||
|
||||
// Distribute water & sediment
|
||||
for (int dirDistribIndex = 0; dirDistribIndex < dirIndex; dirDistribIndex++)
|
||||
{
|
||||
int dirDistrib = directions[dirDistribIndex];
|
||||
water[x + DirectionsX[dirDistrib], y + DirectionsY[dirDistrib]] += distributeAmount;
|
||||
}
|
||||
|
||||
// Subtract from current cell
|
||||
water[x, y] -= distributeAmount * (dirIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Step3_Evaporate()
|
||||
{
|
||||
for (int x = 0; x < Terrain.Width; x++)
|
||||
for (int y = 0; y < Terrain.Height; y++)
|
||||
{
|
||||
// Some sediment deposits
|
||||
Terrain[x, y] += water[x, y] * ErosionAmount;
|
||||
|
||||
// Water evaporates
|
||||
water[x, y] *= .5f;
|
||||
}
|
||||
}
|
||||
|
||||
private void ForEachDirection(int x, int y, Action<int, int, int> action)
|
||||
{
|
||||
for (int dir = 1; dir < DirectionsX.Length; dir++)
|
||||
{
|
||||
int dx = x + DirectionsX[dir];
|
||||
int dy = y + DirectionsY[dir];
|
||||
|
||||
if (Terrain.IsInside(dx, dy))
|
||||
action(dx, dy, dir);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the soil + water level
|
||||
/// </summary>
|
||||
/// <param name="x">x coordinate</param>
|
||||
/// <param name="y">y coordinate</param>
|
||||
/// <returns>level</returns>
|
||||
private float Level(int x, int y)
|
||||
{
|
||||
return Terrain[x, y] + water[x, y];
|
||||
}
|
||||
}
|
||||
}
|
@ -27,7 +27,7 @@ namespace TransportGame.Generator
|
||||
Noise = new PerlinNoiseGenerator();
|
||||
|
||||
if (ConfigurationManager.TerrGenConfig == null)
|
||||
throw new Exception("WTF?");
|
||||
throw new Exception("Not initialized!");
|
||||
|
||||
Noise.Octaves = ConfigurationManager.TerrGenConfig.NoiseOctaves;
|
||||
Noise.NonLinearPower = ConfigurationManager.TerrGenConfig.NoiseNonLinearPower;
|
||||
@ -50,12 +50,6 @@ namespace TransportGame.Generator
|
||||
float waterAmount = random.NextSingle(map.Biome.Moisture.Minimum, map.Biome.Moisture.Maximum);
|
||||
map.WaterLevel = Mathf.Pow(waterAmount, ConfigurationManager.TerrGenConfig.WaterNonLinearPower) * map.Biome.Height;
|
||||
|
||||
DumpData(map, "1generated.map");
|
||||
|
||||
// Simulate water erosion
|
||||
new TerrainEroder(map).Erode();
|
||||
DumpData(map, "2eroded.map");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user