Files
riversong-code-showcase/Source/Riversong/Game/WorldGen/Operations/TreeResourcesGeneratorOperation.cs
2026-05-21 16:04:49 +02:00

87 lines
3.1 KiB
C#

using Cysharp.Threading.Tasks;
using Unity.Mathematics;
using UnityEngine;
using Random = Unity.Mathematics.Random;
namespace DanieleMarotta.RiversongCodeShowcase
{
public class TreeResourcesGeneratorOperation : IWorldGeneratorOperation
{
[InjectService]
private GameConfig _config;
[InjectService]
private ITileSpace _tileSpace;
public async UniTask Execute(World world)
{
await GenerateTreesAsync(world);
}
private async UniTask GenerateTreesAsync(World world)
{
var config = _config.WorldGen;
var treeDefinition = await config.Trees.TreeDefinition.LoadAssetAsync<ResourceNodeDefinition>();
var horizontalResolution = Mathf.FloorToInt(world.Size.x / config.Trees.Spacing);
var verticalResolution = Mathf.FloorToInt(world.Size.y / config.Trees.Spacing);
var random = new Random((uint)world.Seed);
var noiseSalt = world.Seed % ushort.MaxValue * 37;
for (var x = 0; x < horizontalResolution; x++)
for (var z = 0; z < verticalResolution; z++)
{
var treePosition = new Vector3((x + 0.5f) * config.Trees.Spacing, 0, (z + 0.5f) * config.Trees.Spacing);
if (z % 2 == 0) treePosition.x += 0.5f * config.Trees.Spacing;
treePosition.x += Mathf.Lerp(config.Trees.OffsetRange.x, config.Trees.OffsetRange.y, random.NextFloat());
treePosition.z += Mathf.Lerp(config.Trees.OffsetRange.x, config.Trees.OffsetRange.y, random.NextFloat());
var tile = _tileSpace.WorldToTile(treePosition);
if (!EnoughSpaceAround(world, tile)) continue;
var h = world.Heightmap.GetValue(tile);
if (h == 0) continue;
treePosition.y = h;
var noiseSamplePos = new float2(h * 997 + x, noiseSalt + z) * config.Trees.NoiseScale;
var n = noise.snoise(noiseSamplePos);
if (n < 1 - config.Trees.Coverage && random.NextFloat() < 1 - config.Trees.RandomTreeChance) continue;
world.RawResources.AddResourceNode(
new ResourceNode
{
Id = 1 + world.RawResources.Count,
DefinitionId = treeDefinition.RuntimeId,
Position = treePosition,
Tile = tile,
Elevation = _tileSpace.GetElevation(treePosition.y),
CanBeDeleted = true
});
world.BlockMap.AddReason(tile, BlockReason.RawResource);
}
}
private static bool EnoughSpaceAround(World world, int2 center)
{
const int radius = 1;
for (var x = -radius; x <= radius; x++)
for (var y = -radius; y <= radius; y++)
{
var p = center + new int2(x, y);
if (!world.Contains(p)) continue;
if (world.Fertility.GetValue(p).MaxFertility > 0) return false;
}
return true;
}
}
}