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>
65 lines
1.7 KiB
C#
65 lines
1.7 KiB
C#
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 min–max; 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;
|
||
}
|
||
}
|
||
}
|