1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
namespace LivingVillage.Desktop.Tests
open Microsoft.VisualStudio.TestTools.UnitTesting
open LivingVillage.Desktop
/// P78 夜晚氛围与场景细节回归(纯函数层):
/// * 夜帧水面逐格微光斑:只落在水面/水田、帧号驱动且确定性、昼夜两档(白天恒 0);
/// * 炊烟:生成器世界每户一个烟源、夜帧 alpha/尺寸更大、升腾摇晃有界且确定性;
/// * 桥头灯柱近圈光晕:半径恒为 1 tile(窄光晕),复用既有灯柱瓦片。
[<TestClass>]
type P78NightAmbienceTests () =
let map = MapGen.generate (MapGen.defaultParams 42UL)
[<TestMethod>]
member _.WaterGlintsAreNightOnlyDeterministicAndTwoTier () =
let glints = SceneDetail.waterGlintTiles map
Assert.IsTrue(not (List.isEmpty glints), "生成器世界须有水面光斑候选格")
for (x, y) in glints do
Assert.IsTrue(SceneDetail.isWaterSurface map x y, sprintf "光斑 (%d,%d) 必须落在水面/水田" x y)
// 白天恒定关闭(零回归),夜帧两个亮度档。
for phase in 0 .. SceneDetail.waterGlintPhaseCount - 1 do
Assert.IsTrue((SceneDetail.waterGlintAlpha 0.0f phase) = 0, "白天光斑必须为 0(零回归)")
let nightBright = SceneDetail.waterGlintAlpha 1.0f 0
let nightDim = SceneDetail.waterGlintAlpha 1.0f 1
Assert.IsTrue(nightBright > 0, "夜帧光斑须可见")
Assert.IsTrue(nightBright > nightDim && nightDim > 0, "光斑须有两档呼吸层次")
// 帧号驱动且确定性。
for tick in [ 0L; 8L; 16L; 32L ] do
let phase = SceneDetail.waterGlintPhase tick 3 5
Assert.IsTrue(phase >= 0 && phase < SceneDetail.waterGlintPhaseCount, "相位越界")
Assert.IsTrue((SceneDetail.waterGlintPhase tick 3 5) = phase, "相位须确定性")
Assert.IsTrue(abs (SceneDetail.waterGlintOffset tick 3 5) <= 1, "光斑位移须有界 ±1px")
Assert.IsTrue(
(SceneDetail.waterGlintPhase 0L 3 5) <> (SceneDetail.waterGlintPhase 8L 3 5)
|| (SceneDetail.waterGlintPhase 8L 3 5) <> (SceneDetail.waterGlintPhase 16L 3 5)
|| (SceneDetail.waterGlintPhase 16L 3 5) <> (SceneDetail.waterGlintPhase 24L 3 5),
"光斑相位须随帧号变化")
[<TestMethod>]
member _.SmokeIsProminentAtNightAndDeterministic () =
let sources = SceneDetail.smokeSourceTiles map
let expected = (map.Buildings @ map.Farmhouses) |> List.length
Assert.IsTrue(not (List.isEmpty sources), "生成器世界须有炊烟源(民居/农舍)")
Assert.IsTrue(List.length sources <= expected, "去重后炊烟源数不得超过户数")
let dayAlpha = SceneDetail.smokeAlphaAt 0.0f
let nightAlpha = SceneDetail.smokeAlphaAt 1.0f
Assert.IsTrue(dayAlpha > 0, "白天炊烟仍须可辨")
Assert.IsTrue(nightAlpha > dayAlpha, "夜帧炊烟须更醒目")
Assert.IsTrue((SceneDetail.smokeCellSize 1.0f) > (SceneDetail.smokeCellSize 0.0f), "夜帧炊烟体量须更大")
for tick in [ 0L; 24L; 48L ] do
let frame = SceneDetail.smokeFrame tick
Assert.IsTrue(frame >= 0 && frame <= 2, "炊烟需三相位")
let sway, rise = SceneDetail.smokeDrift tick 7
Assert.IsTrue(abs sway <= 1, "炊烟摇曳须有界 ±1px")
Assert.IsTrue(rise <= 0 && rise >= -4, "炊烟只向上且位移有界")
Assert.IsTrue((SceneDetail.smokeDrift tick 7) = (sway, rise), "炊烟位移须确定性")
[<TestMethod>]
member _.BridgeHaloIsNarrowAndMatchesLanternTiles () =
Assert.IsTrue((SceneDetail.bridgeHaloRadiusTiles = 1), "桥头光晕须为窄光晕(1 tile)")
Assert.IsTrue((SceneDetail.bridgeLanternTiles map) = (VillageArt.bridgeLanternTiles map), "桥头灯柱瓦片须同源")
|