Add MrGameEng.WorldGen: deterministic procedural world generation
CI / build-test (push) Successful in 1m14s

Introduce a WorldGen module under Simulation with reusable helpers for
seed-based terrain heightmaps: PerlinNoise (deterministic 2D gradient
noise), FractalNoise (fBm over octaves), Falloff (island edge masks),
Heightmap (row-major grid with min-max normalize) and HeightmapGenerator
(settings to normalized heightmap). All deterministic from an integer
seed, allocation-free per sample, covered by xUnit tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Leonid Pershin
2026-06-12 09:23:45 +03:00
co-authored by Claude Opus 4.8
parent ef1111bcb6
commit 53659450a6
6 changed files with 453 additions and 0 deletions
@@ -0,0 +1,64 @@
namespace MrGameEng.WorldGen;
/// <summary>
/// A dense row-major grid of height values. Plain data with indexed access — fill it from a
/// <see cref="HeightmapGenerator"/> and read it from worldgen code. Values are arbitrary until
/// <see cref="Normalize"/> rescales them into <c>[0, 1]</c>.
/// </summary>
public sealed class Heightmap
{
/// <summary>Grid width in cells.</summary>
public int Width { get; }
/// <summary>Grid height in cells.</summary>
public int Height { get; }
/// <summary>Row-major values, length <see cref="Width"/>×<see cref="Height"/>.</summary>
public float[] Values { get; }
/// <summary>Creates an all-zero map of the given size.</summary>
public Heightmap(int width, int height)
{
Width = width;
Height = height;
Values = new float[width * height];
}
/// <summary>Height at (<paramref name="x"/>, <paramref name="y"/>).</summary>
public float this[int x, int y]
{
get => Values[y * Width + x];
set => Values[y * Width + x] = value;
}
/// <summary>Rescales all values into <c>[0, 1]</c> by minmax; a flat map becomes all zeros.</summary>
public void Normalize()
{
var min = float.MaxValue;
var max = float.MinValue;
foreach (var v in Values)
{
if (v < min)
{
min = v;
}
if (v > max)
{
max = v;
}
}
var range = max - min;
if (range <= float.Epsilon)
{
Array.Clear(Values);
return;
}
for (var i = 0; i < Values.Length; i++)
{
Values[i] = (Values[i] - min) / range;
}
}
}