89 lines
3.4 KiB
C#
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));
|
|
}
|
|
}
|
|
} |