mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 11:05:34 +00:00
68 lines
2.7 KiB
C#
68 lines
2.7 KiB
C#
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Godot;
|
|
|
|
namespace Cirno.Scripts.Resources.Loot;
|
|
|
|
/// <summary>
|
|
/// Shared logic for spawning and scattering <see cref="LootDrop"/> entries in the 3D world.
|
|
/// Used by both destructibles and enemies so the distribution behaviour stays consistent.
|
|
/// </summary>
|
|
public static class LootDropHelper
|
|
{
|
|
/// <summary>
|
|
/// Rolls each drop's chance, then spawns the resulting pickups scattered uniformly
|
|
/// in a circle around <paramref name="center"/> with an outward + upward launch velocity
|
|
/// so they arc through the air and fall to the floor.
|
|
/// </summary>
|
|
/// <param name="drops">The list of possible drops to evaluate.</param>
|
|
/// <param name="anchor">Node used as the spawn parent / sibling reference.</param>
|
|
/// <param name="center">World-space centre of the scatter circle.</param>
|
|
/// <param name="scatterRadius">Radius of the circle in which items are spread.</param>
|
|
/// <param name="launchUpSpeed">Initial upward speed applied to each pickup.</param>
|
|
/// <param name="rng">Caller-owned RNG instance so seeds are consistent per object.</param>
|
|
public static void SpawnDrops(
|
|
IEnumerable<LootDrop> drops,
|
|
Node3D anchor,
|
|
Vector3 center,
|
|
float scatterRadius,
|
|
float launchUpSpeed,
|
|
RandomNumberGenerator rng)
|
|
{
|
|
var dropList = drops?.ToList();
|
|
if (dropList is not { Count: > 0 }) return;
|
|
|
|
// Count total spawns up front so golden-angle spacing is proportional to the full set.
|
|
var totalSpawns = dropList
|
|
.Where(d => d?.Item is not null)
|
|
.Sum(d => Mathf.Max(d.Count, 1));
|
|
|
|
var itemIndex = 0;
|
|
|
|
foreach (var drop in dropList)
|
|
{
|
|
if (drop?.Item is null) continue;
|
|
|
|
var roll = rng.RandfRange(0f, 100f);
|
|
if (roll > drop.Chance) continue;
|
|
|
|
var spawnCount = Mathf.Max(drop.Count, 1);
|
|
for (var i = 0; i < spawnCount; i++)
|
|
{
|
|
// Golden-angle placement gives uniform, non-clustering distribution.
|
|
itemIndex++;
|
|
var angle = itemIndex * Mathf.Tau / 1.618033988f;
|
|
var radius = scatterRadius * Mathf.Sqrt((float)itemIndex / Mathf.Max(totalSpawns, 1));
|
|
var offset = new Vector3(Mathf.Cos(angle) * radius, 0f, Mathf.Sin(angle) * radius);
|
|
var spawnPos = center + offset;
|
|
|
|
var lateralDir = offset.LengthSquared() > 0f ? offset.Normalized() : Vector3.Right;
|
|
var launch = lateralDir * (scatterRadius * 0.5f) + Vector3.Up * launchUpSpeed;
|
|
|
|
drop.Item.Spawn3D(anchor, spawnPosition: spawnPos, launchVelocity: launch);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|