CI / build-test (push) Successful in 1m11s
Climate (Core) layers a continuous seasonal-plus-daily temperature and the current season over the Calendar, registered via context.UseClimate. A new Lighting module (Graphics) adds DayNight: a daylight factor and ambient color from the calendar's time of day, pushed into the renderer's new AmbientLight (multiplied into world-space sprites only, so the scene darkens at night while screen-space overlays stay readable) and exposed as a sampleable SampleAt for the simulation. Both deterministic and GPU-free, covered by tests; docs updated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
85 lines
2.5 KiB
C#
85 lines
2.5 KiB
C#
using MrGameEng.Core;
|
|
using Xunit;
|
|
|
|
namespace MrGameEng.Core.Tests;
|
|
|
|
public class ClimateTests
|
|
{
|
|
private static (GameClock Clock, Climate Climate) Make(ClimateSettings settings)
|
|
{
|
|
var clock = new GameClock();
|
|
var calendar = new Calendar(clock, secondsPerDay: 10f);
|
|
return (clock, new Climate(calendar, settings));
|
|
}
|
|
|
|
private static ClimateSettings Seasonal =>
|
|
new()
|
|
{
|
|
DaysPerYear = 60,
|
|
MeanTemperature = 10f,
|
|
SeasonalAmplitude = 20f,
|
|
DailyAmplitude = 0f,
|
|
WarmestDay = 15,
|
|
};
|
|
|
|
[Fact]
|
|
public void Constructor_NonPositiveYear_Throws()
|
|
{
|
|
Assert.Throws<ArgumentOutOfRangeException>(() =>
|
|
new Climate(new Calendar(new GameClock(), 10f), Seasonal with { DaysPerYear = 0 })
|
|
);
|
|
}
|
|
|
|
[Fact]
|
|
public void Temperature_PeaksOnWarmestDay_AndBottomsHalfYearLater()
|
|
{
|
|
var (clock, climate) = Make(Seasonal);
|
|
|
|
clock.Advance(15 * 10f); // day 15 = warmest
|
|
Assert.Equal(30f, climate.Temperature, 2); // mean 10 + amplitude 20
|
|
|
|
clock.Advance(30 * 10f); // +30 days = half a 60-day year later
|
|
Assert.Equal(-10f, climate.Temperature, 2); // mean 10 - amplitude 20
|
|
}
|
|
|
|
[Fact]
|
|
public void DailySwing_WarmerAtNoonThanMidnight()
|
|
{
|
|
var settings = Seasonal with { SeasonalAmplitude = 0f, DailyAmplitude = 6f };
|
|
var (clock, climate) = Make(settings);
|
|
|
|
clock.Advance(5f); // day 0, noon (DayProgress 0.5)
|
|
Assert.Equal(16f, climate.Temperature, 2); // mean 10 + daily 6
|
|
|
|
clock.Advance(5f); // day 1, midnight (DayProgress 0)
|
|
Assert.Equal(4f, climate.Temperature, 2); // mean 10 - daily 6
|
|
}
|
|
|
|
[Fact]
|
|
public void Season_FollowsTheQuarterOfTheYear()
|
|
{
|
|
var (clock, climate) = Make(Seasonal); // 60-day year → 15 days per season
|
|
|
|
Assert.Equal(Season.Spring, climate.Season);
|
|
clock.Advance(20 * 10f);
|
|
Assert.Equal(Season.Summer, climate.Season);
|
|
clock.Advance(15 * 10f);
|
|
Assert.Equal(Season.Autumn, climate.Season);
|
|
clock.Advance(15 * 10f);
|
|
Assert.Equal(Season.Winter, climate.Season);
|
|
}
|
|
|
|
[Fact]
|
|
public void YearAndDayOfYear_RollOver()
|
|
{
|
|
var (clock, climate) = Make(Seasonal);
|
|
|
|
Assert.Equal(1, climate.Year);
|
|
Assert.Equal(0, climate.DayOfYear);
|
|
|
|
clock.Advance(60 * 10f); // exactly one year
|
|
Assert.Equal(2, climate.Year);
|
|
Assert.Equal(0, climate.DayOfYear);
|
|
}
|
|
}
|