Liven up animal movement with a walking sway (presentation only)
AnimalBobSystem tilts a moving animal side-to-side via Transform2D.Rotation (a gentle waddle) and eases it upright when standing. Phase runs on game time (frozen on pause, faster when sped up) and is offset per entity id so animals sway out of sync. Purely presentational -- the simulation ignores rotation, and the facing system writes scale (not rotation), so no conflict. Corpses/eggs have no brain so they stay still. Build + --check-content clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
405ed192a8
commit
0c07eba021
@@ -323,6 +323,7 @@ public sealed class WorldScene : Scene
|
||||
UpdateSystems.Add(new AnimalAppearanceSystem(_needs));
|
||||
UpdateSystems.Add(new AnimalGrowthSystem(Context.Clock, SecondsPerDay, _animals, CellSize));
|
||||
UpdateSystems.Add(new AnimalFacingSystem(_animals, CellSize));
|
||||
UpdateSystems.Add(new AnimalBobSystem(Context.Clock));
|
||||
UpdateSystems.Add(new AnimalMortalitySystem(Store, _animals, CellSize));
|
||||
UpdateSystems.Add(new CorpseSystem(Store, Context.Clock, SecondsPerDay, climate));
|
||||
UpdateSystems.Add(
|
||||
|
||||
@@ -1688,6 +1688,52 @@ public sealed class AnimalFacingSystem(AnimalSet animals, int cellSize)
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// «Раскачка» при ходьбе (презентация): идущий зверь покачивается из стороны в сторону (наклон спрайта
|
||||
/// через <see cref="Transform2D.Rotation"/>), стоящий — плавно выпрямляется. Делает движение живее, не
|
||||
/// затрагивая симуляцию (она вращение не использует). Фаза покачивания идёт по игровому времени (стоп на
|
||||
/// паузе, быстрее на ускорении) и сдвинута по id особи — звери качаются вразнобой. Граница sim/presentation
|
||||
/// цела: система пишет только поворот трансформа.
|
||||
/// </summary>
|
||||
public sealed class AnimalBobSystem(GameClock clock) : QuerySystem<AnimalBrain, Transform2D>
|
||||
{
|
||||
private const float SwaySpeed = 9f; // скорость набега фазы (рад/сек игрового времени)
|
||||
private const float SwayAmplitude = 0.08f; // амплитуда наклона (рад ≈ 4.6°)
|
||||
private const float MinMoveSq = 0.5f * 0.5f; // ближе к цели — считаем стоящим
|
||||
private const float UprightDecay = 0.85f; // как быстро выпрямляется стоя (за кадр)
|
||||
|
||||
private float _phase;
|
||||
|
||||
protected override void OnUpdate()
|
||||
{
|
||||
var dt = clock.DeltaTime;
|
||||
if (dt <= 0f)
|
||||
{
|
||||
return; // пауза — не качаем и не выпрямляем
|
||||
}
|
||||
|
||||
_phase += dt * SwaySpeed;
|
||||
foreach (var (brains, transforms, entities) in Query.Chunks)
|
||||
{
|
||||
var b = brains.Span;
|
||||
var t = transforms.Span;
|
||||
for (var i = 0; i < b.Length; i++)
|
||||
{
|
||||
ref var rot = ref t[i].Rotation;
|
||||
if ((b[i].Target - t[i].Position).LengthSquared() > MinMoveSq)
|
||||
{
|
||||
var offset = entities.EntityAt(i).Id * 0.7f; // десинхрон между особями
|
||||
rot = MathF.Sin(_phase + offset) * SwayAmplitude;
|
||||
}
|
||||
else
|
||||
{
|
||||
rot *= UprightDecay; // у цели/стоя — плавно к вертикали
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Рост и стадии (фаза A3): копит возраст в игровых днях, переключает стадию (Baby→Juvenile→Adult→
|
||||
/// Senior) по порогам из генов и при смене стадии меняет спрайт (детёныш/самка/самец) и размер.
|
||||
|
||||
Reference in New Issue
Block a user