riversong code showcase

This commit is contained in:
Daniele Marotta
2026-05-21 15:52:18 +02:00
commit 4c9eea1c02
462 changed files with 23406 additions and 0 deletions

View File

@@ -0,0 +1,32 @@
namespace DanieleMarotta.RiversongCodeShowcase
{
public class PopulationPanelModel : UIModel
{
public int Population { get; set; }
public int Happiness { get; set; }
public LaborTier LaborTier { get; set; }
public void Update(int population, int happiness, LaborTier laborTier)
{
if (Population != population)
{
Population = population;
NotifyPropertyChanged(nameof(Population));
}
if (Happiness != happiness)
{
Happiness = happiness;
NotifyPropertyChanged(nameof(Happiness));
}
if (LaborTier != laborTier)
{
LaborTier = laborTier;
NotifyPropertyChanged(nameof(LaborTier));
}
}
}
}

View File

@@ -0,0 +1,36 @@
using Cysharp.Threading.Tasks;
using Unity.Mathematics;
namespace DanieleMarotta.RiversongCodeShowcase
{
public class PopulationPanelUIController : UIControllerSystem<PopulationPanelUIView>, IUpdatable
{
[InjectService]
private World _world;
private PopulationPanelModel _model;
public PopulationPanelUIController(IServiceLocator serviceLocator) : base(serviceLocator)
{
}
protected override PopulationPanelUIView View => UIRoot.GetView<PopulationPanelUIView>();
public override async UniTask InitializeAsync()
{
await base.InitializeAsync();
_model = new PopulationPanelModel();
View.SetModel(_model);
}
public void Update()
{
var population = _world.PopulationState.Population;
var happiness = math.clamp((int)math.round(_world.PopulationState.Happiness * 100), 0, 100);
_model.Update(population, happiness, _world.ProductionState.LaborTier);
View.UpdateHappinessIconAnimation();
}
}
}

View File

@@ -0,0 +1,113 @@
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using Unity.Mathematics;
using UnityEngine;
using UnityEngine.UIElements;
namespace DanieleMarotta.RiversongCodeShowcase
{
[UIView("population-panel")]
public class PopulationPanelUIView : UIView<PopulationPanelModel>
{
private Label _populationLabel;
private VisualElement _happinessIcon;
private Label _happinessLabel;
private List<VisualElement> _laborTier;
private float _happinessIconScale = 1;
public override UniTask InitializeAsync(UIService uiService, VisualElement rootElement)
{
base.InitializeAsync(uiService, rootElement);
_populationLabel = rootElement.Q<Label>(className: "population-panel__population-label");
_happinessIcon = rootElement.Q<VisualElement>(className: "population-panel__happiness-icon");
_happinessLabel = rootElement.Q<Label>(className: "population-panel__happiness-label");
_laborTier = rootElement.Query<VisualElement>(className: "population-panel__labor-dot").ToList();
return UniTask.CompletedTask;
}
protected override void OnNewModel(PopulationPanelModel model)
{
base.OnNewModel(model);
UpdatePopulationLabel();
UpdateHappinessLabel();
UpdateLaborRating();
}
protected override void OnModelPropertyChanged(object sender, BindablePropertyChangedEventArgs e)
{
base.OnModelPropertyChanged(sender, e);
switch (e.propertyName)
{
case nameof(PopulationPanelModel.Population):
UpdatePopulationLabel();
break;
case nameof(PopulationPanelModel.Happiness):
UpdateHappinessLabel();
break;
case nameof(PopulationPanelModel.LaborTier):
UpdateLaborRating();
break;
}
}
private void UpdatePopulationLabel()
{
_populationLabel.text = Model.Population.ToString();
}
private void UpdateHappinessLabel()
{
_happinessLabel.text = Model.Happiness.ToString();
}
private void UpdateLaborRating()
{
var ratingClass = Model.LaborTier switch
{
LaborTier.Medium => "medium",
LaborTier.High => "high",
_ => "low"
};
foreach (var element in _laborTier)
{
element.RemoveFromClassList("low");
element.RemoveFromClassList("medium");
element.RemoveFromClassList("high");
element.AddToClassList(ratingClass);
}
var rating = math.clamp((int)Model.LaborTier, 0, _laborTier.Count);
for (var i = 0; i < _laborTier.Count; i++) _laborTier[i].EnableInClassList("empty", i >= rating);
}
public void UpdateHappinessIconAnimation()
{
var normalizedHappiness = Model.Happiness * 0.01f;
const float minSpeed = 1.8f;
const float maxSpeed = 2.4f;
var speed = math.lerp(minSpeed, maxSpeed, normalizedHappiness);
const float minAmplitude = 0.03f;
const float maxAmplitude = 0.06f;
var amplitude = math.lerp(minAmplitude, maxAmplitude, normalizedHappiness);
if (normalizedHappiness > 0.98f) amplitude *= 1.15f;
var targetScale = 1 + amplitude * 0.5f * (1 + math.sin(Time.unscaledTime * speed));
_happinessIconScale = math.lerp(_happinessIconScale, targetScale, math.saturate(Time.unscaledDeltaTime * 4));
_happinessIcon.style.scale = new StyleScale(new Scale(Vector2.one * _happinessIconScale));
}
}
}