Files
riversong-code-showcase/Source/Riversong/Game/World/Population/PopulationUpdateSystem.cs
2026-05-21 16:04:49 +02:00

89 lines
3.4 KiB
C#

using Cysharp.Threading.Tasks;
using Unity.Mathematics;
using UnityEngine;
namespace DanieleMarotta.RiversongCodeShowcase
{
[UpdateAfter(typeof(PopulationNeedsSystem))]
public class PopulationUpdateSystem : GameSystem, IInitializable, IUpdatable
{
[InjectService]
private ISignalBus _signalBus;
[InjectService]
private World _world;
[InjectService]
private IEntityCache _entityCache;
[InjectService]
private GameConfig _config;
public PopulationUpdateSystem(IServiceLocator serviceLocator) : base(serviceLocator)
{
}
public UniTask InitializeAsync()
{
_world.PopulationState.Happiness = _config.Population.InitialeOverallHappiness;
return UniTask.CompletedTask;
}
public void Update()
{
if (_world.TimeState.DayNightCycleStep != DayNightCycleStep.Day) return;
UpdateOverallHappiness();
UpdatePopulation();
}
private void UpdateOverallHappiness()
{
var targetHappiness = 0f;
var totalWeight = 0f;
foreach (var house in _entityCache.GetHouses())
{
ref var needsState = ref house.GetNeedsStateRW();
targetHappiness += needsState.OverallHappinessWeight * needsState.Happiness;
totalWeight += needsState.OverallHappinessWeight;
}
if (totalWeight > 0) targetHappiness = math.saturate(targetHappiness / totalWeight);
var grace = _world.TimeState.TotalWeeks < _config.Population.GraceWeekCount;
if (grace) targetHappiness = math.max(targetHappiness, _config.Population.GraceMinHappiness);
var populationState = _world.PopulationState;
var delta = math.abs(targetHappiness - populationState.Happiness);
const float halfOnePercent = 0.005f;
populationState.Sentiment = delta > halfOnePercent ? math.sign(targetHappiness - populationState.Happiness) : 0;
populationState.Happiness = Mathf.MoveTowards(populationState.Happiness, targetHappiness, _config.Population.OverallHappinessChangeRate * Time.deltaTime);
populationState.Happiness = math.saturate(populationState.Happiness);
}
private void UpdatePopulation()
{
var populationState = _world.PopulationState;
populationState.PopulationCapacity = 0;
foreach (var house in _entityCache.GetHouses()) populationState.PopulationCapacity += house.PopulationCapacity;
var growthRate = _config.Population.GrowthRatePeakValue * _config.Population.GrowthRateCurve.Evaluate(populationState.Happiness);
if (populationState.Sentiment > 0) growthRate = math.max(growthRate, 0);
populationState.GrowthAccumulator += growthRate * Time.deltaTime;
if (math.abs(populationState.GrowthAccumulator) < 1) return;
var delta = (int)math.sign(populationState.GrowthAccumulator);
populationState.GrowthAccumulator -= delta;
var updatedPopulation = math.clamp(populationState.Population + delta, 0, populationState.PopulationCapacity);
if (updatedPopulation == populationState.Population) return;
populationState.Population = updatedPopulation;
_signalBus.Raise(new PopulationChangedSignal(updatedPopulation));
}
}
}