Животные A3: жизненный цикл, стадии и пол
Компонент AnimalGrowth (стадия + возраст). Ген пола GeneSex (локус XX/XY; генерация основателя задаёт пол явно через AnimalSet.GenerateGenome, исключая невозможный YY) и GeneMaturityAge. Стадии Baby->Juvenile->Adult->Senior с порогами из генов. AnimalGrowthSystem меняет спрайт (детёныш/самец/самка) и размер по стадии; AnimalMortalitySystem — смерть от старости и истощения (деспавн), замыкает контур ёмкости среды. Стадо спавнится разновозрастным. Сборка чистая, --check-content (30 генов, 29 признаков). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e35e620655
commit
355ced4937
@@ -40,6 +40,9 @@ public struct AnimalNeeds : IComponent
|
||||
/// <summary>Отдых/бодрость [0,1].</summary>
|
||||
public float Rest;
|
||||
|
||||
/// <summary>Накоплено игровых дней истощения (голод/жажда на нуле); порог — смерть (A3).</summary>
|
||||
public float Starve;
|
||||
|
||||
/// <summary>Наименьшая (самая острая) нужда — для выбора и внешнего вида.</summary>
|
||||
public readonly float Worst() => MathF.Min(Hunger, MathF.Min(Thirst, Rest));
|
||||
}
|
||||
@@ -99,6 +102,12 @@ public sealed class AnimalNeedsSystem(GameClock clock, float secondsPerDay)
|
||||
need.Hunger = Math.Clamp(need.Hunger - HungerPerDay * metabolism * days, 0f, 1f);
|
||||
need.Thirst = Math.Clamp(need.Thirst - ThirstPerDay * metabolism * days, 0f, 1f);
|
||||
need.Rest = Math.Clamp(need.Rest - RestPerDay * metabolism * days, 0f, 1f);
|
||||
|
||||
// Истощение: голод/жажда на нуле копят счётчик смерти (A3), иначе он рассасывается вдвое быстрее.
|
||||
need.Starve =
|
||||
need.Hunger <= 0f || need.Thirst <= 0f
|
||||
? need.Starve + days
|
||||
: MathF.Max(0f, need.Starve - days * 2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,3 +450,97 @@ public sealed class AnimalAppearanceSystem : QuerySystem<AnimalNeeds, AnimalOrga
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Рост и стадии (фаза A3): копит возраст в игровых днях, переключает стадию (Baby→Juvenile→Adult→
|
||||
/// Senior) по порогам из генов (возраст созревания, продолжительность жизни) и при смене стадии меняет
|
||||
/// спрайт (детёныш/самка/самец) и размер. Зеркало <see cref="PlantGrowthSystem"/>.
|
||||
/// </summary>
|
||||
public sealed class AnimalGrowthSystem(
|
||||
GameClock clock,
|
||||
float secondsPerDay,
|
||||
AnimalSet animals,
|
||||
int cellSize
|
||||
) : QuerySystem<AnimalGrowth, AnimalOrganism, Transform2D, Sprite>
|
||||
{
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
var days = clock.DeltaTime / secondsPerDay;
|
||||
if (days <= 0f)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var (growths, organisms, transforms, sprites, _) in Query.Chunks)
|
||||
{
|
||||
var g = growths.Span;
|
||||
var o = organisms.Span;
|
||||
var t = transforms.Span;
|
||||
var s = sprites.Span;
|
||||
for (var i = 0; i < g.Length; i++)
|
||||
{
|
||||
ref var grow = ref g[i];
|
||||
grow.AgeDays += days;
|
||||
ref readonly var org = ref o[i];
|
||||
var stage = AnimalFactory.StageAt(
|
||||
grow.AgeDays,
|
||||
org.Traits.MaturityAge,
|
||||
org.Traits.Lifespan
|
||||
);
|
||||
if (stage == grow.Stage)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
grow.Stage = stage;
|
||||
var sp = animals[org.Species];
|
||||
var region = AnimalFactory.RegionFor(sp, stage, org.IsMale);
|
||||
ref var sprite = ref s[i];
|
||||
sprite.Region = region;
|
||||
sprite.Origin = new Vector2(region.Width / 2f, region.Height / 2f);
|
||||
t[i].Scale = new Vector2(AnimalFactory.Scale(sp, org.Traits, stage, region, cellSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Смертность (фаза A3): простая гибель с деспавном — от старости (возраст превысил продолжительность
|
||||
/// жизни) или от истощения (счётчик голода/жажды превысил порог). Замыкает контур ёмкости среды.
|
||||
/// На A5 «апгрейдится» в смерть через здоровье и оставит труп вместо деспавна.
|
||||
/// </summary>
|
||||
public sealed class AnimalMortalitySystem : BaseSystem
|
||||
{
|
||||
private const float LethalStarveDays = 3f;
|
||||
|
||||
private readonly ArchetypeQuery<AnimalGrowth, AnimalOrganism, AnimalNeeds> _query;
|
||||
private readonly List<Entity> _deaths = [];
|
||||
|
||||
public AnimalMortalitySystem(EntityStore store)
|
||||
{
|
||||
_query = store.Query<AnimalGrowth, AnimalOrganism, AnimalNeeds>();
|
||||
}
|
||||
|
||||
protected override void OnUpdateGroup()
|
||||
{
|
||||
_deaths.Clear();
|
||||
foreach (var (growths, organisms, needs, entities) in _query.Chunks)
|
||||
{
|
||||
var g = growths.Span;
|
||||
var o = organisms.Span;
|
||||
var n = needs.Span;
|
||||
for (var i = 0; i < g.Length; i++)
|
||||
{
|
||||
if (g[i].AgeDays > o[i].Traits.Lifespan || n[i].Starve >= LethalStarveDays)
|
||||
{
|
||||
_deaths.Add(entities.EntityAt(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entity in _deaths)
|
||||
{
|
||||
entity.DeleteEntity();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user