Merge branch 'animal-bob' into main
Walking sway for animals (AnimalBobSystem) to make movement feel livelier. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -323,6 +323,7 @@ public sealed class WorldScene : Scene
|
|||||||
UpdateSystems.Add(new AnimalAppearanceSystem(_needs));
|
UpdateSystems.Add(new AnimalAppearanceSystem(_needs));
|
||||||
UpdateSystems.Add(new AnimalGrowthSystem(Context.Clock, SecondsPerDay, _animals, CellSize));
|
UpdateSystems.Add(new AnimalGrowthSystem(Context.Clock, SecondsPerDay, _animals, CellSize));
|
||||||
UpdateSystems.Add(new AnimalFacingSystem(_animals, CellSize));
|
UpdateSystems.Add(new AnimalFacingSystem(_animals, CellSize));
|
||||||
|
UpdateSystems.Add(new AnimalBobSystem(Context.Clock));
|
||||||
UpdateSystems.Add(new AnimalMortalitySystem(Store, _animals, CellSize));
|
UpdateSystems.Add(new AnimalMortalitySystem(Store, _animals, CellSize));
|
||||||
UpdateSystems.Add(new CorpseSystem(Store, Context.Clock, SecondsPerDay, climate));
|
UpdateSystems.Add(new CorpseSystem(Store, Context.Clock, SecondsPerDay, climate));
|
||||||
UpdateSystems.Add(
|
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>
|
/// <summary>
|
||||||
/// Рост и стадии (фаза A3): копит возраст в игровых днях, переключает стадию (Baby→Juvenile→Adult→
|
/// Рост и стадии (фаза A3): копит возраст в игровых днях, переключает стадию (Baby→Juvenile→Adult→
|
||||||
/// Senior) по порогам из генов и при смене стадии меняет спрайт (детёныш/самка/самец) и размер.
|
/// Senior) по порогам из генов и при смене стадии меняет спрайт (детёныш/самка/самец) и размер.
|
||||||
|
|||||||
Reference in New Issue
Block a user