summaryrefslogtreecommitdiff
path: root/src/LivingVillage.Desktop.Tests
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-29 11:08:32 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-29 11:08:32 +0800
commit837fd81a2bd857011855ca1dc32e646629f14236 (patch)
tree896e33d5948bb5457cf0dd17494792f9aa631cd2 /src/LivingVillage.Desktop.Tests
parentf3ad37b1d057566a9e5e01a7ee9850eb1c4598f4 (diff)
downloadliving-village-837fd81a2bd857011855ca1dc32e646629f14236.tar.gz
p74: 启动开场过渡(水墨式渐显)+ 开始界面布局回归
新增纯函数 InkReveal.fs(inkStrength ease-out 消散 + 6 滴预乘墨滴 dabs),DrawSplash 在场景层之上、标题之下绘制,与既有 reveal/veil 淡入叠加,形成可辨识水墨开场;单滴 alpha<255 且椭圆行落成,无实心黑块。开始界面沿用既有 开始/读档/退出(有档 继续)。新增 P74LaunchTransitionTests(4 例)与 LV_P74_SHOT/-analyze-p74 证据(5 帧墨幕非增、两两 diff>0,verdict=PASS)。HUD 结构未动;Desktop 350/350、Kernel 120/120、digest 与 p70 一致。
Diffstat (limited to 'src/LivingVillage.Desktop.Tests')
-rw-r--r--src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj1
-rw-r--r--src/LivingVillage.Desktop.Tests/P74LaunchTransitionTests.fs59
2 files changed, 60 insertions, 0 deletions
diff --git a/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj b/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj
index 11a1b90..fb7ecb7 100644
--- a/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj
+++ b/src/LivingVillage.Desktop.Tests/LivingVillage.Desktop.Tests.fsproj
@@ -45,6 +45,7 @@
<Compile Include="P71ApiDocsTests.fs" />
<Compile Include="P72CharacterWalkTests.fs" />
<Compile Include="P73LightingTierTests.fs" />
+ <Compile Include="P74LaunchTransitionTests.fs" />
<Compile Include="SampleTests.fs" />
</ItemGroup>
diff --git a/src/LivingVillage.Desktop.Tests/P74LaunchTransitionTests.fs b/src/LivingVillage.Desktop.Tests/P74LaunchTransitionTests.fs
new file mode 100644
index 0000000..880f33b
--- /dev/null
+++ b/src/LivingVillage.Desktop.Tests/P74LaunchTransitionTests.fs
@@ -0,0 +1,59 @@
+namespace LivingVillage.Desktop.Tests
+
+open Microsoft.VisualStudio.TestTools.UnitTesting
+open LivingVillage.Desktop
+open LivingVillage.Kernel
+open LivingVillage.Kernel.Sim
+
+/// P74 回归:启动开场过渡(水墨渐显)纯函数性质 + 开始界面布局入口。
+[<TestClass>]
+type P74LaunchTransitionTests () =
+
+ let width = 1280
+ let height = 720
+
+ [<TestMethod>]
+ member _.InkRevealDissolvesMonotonicallyAndStaysSoft () =
+ // 起手满墨、96 帧后散尽,且整体强度随帧非增(确定性 ease-out)。
+ Assert.AreEqual<float32>(1.0f, InkReveal.inkStrength 0L)
+ Assert.AreEqual<float32>(0.0f, InkReveal.inkStrength InkReveal.dissolveFrames)
+ Assert.AreEqual<float32>(0.0f, InkReveal.inkStrength 140L)
+ let strengths = [ 0L; 8L; 30L; 60L; 95L ] |> List.map InkReveal.inkStrength
+ Assert.AreEqual<float32 list>(strengths, strengths |> List.sortDescending)
+ // 墨滴始终存在、均在画布内、alpha < 255(柔和墨晕,非实心黑块)、半径不覆盖半屏。
+ for frame in [ 0L; 8L; 30L; 60L; 95L ] do
+ let dabs = InkReveal.dabs frame width height
+ Assert.IsTrue(dabs.Length > 0, "墨滴集合不得为空")
+ for dab in dabs do
+ Assert.IsTrue(dab.Alpha >= 0 && dab.Alpha < 255, sprintf "alpha %d 越界" dab.Alpha)
+ Assert.IsTrue(dab.Rx > 0 && dab.Rx < width / 2, "Rx 覆盖过半屏")
+ Assert.IsTrue(dab.Ry > 0 && dab.Ry < height / 2, "Ry 覆盖过半屏")
+
+ [<TestMethod>]
+ member _.InkRevealDabsChangeOverTheTransition () =
+ // 同一帧两次调用一致(确定性);不同帧墨滴布局不同(动画在变)。
+ Assert.AreEqual<InkReveal.Dab list>(InkReveal.dabs 20L width height, InkReveal.dabs 20L width height)
+ Assert.AreNotEqual<InkReveal.Dab list>(InkReveal.dabs 8L width height, InkReveal.dabs 60L width height)
+
+ [<TestMethod>]
+ member _.LaunchScreenTransitionIsDeterministic () =
+ Assert.AreEqual<float32>(0.0f, LaunchScreen.revealProgress 0L)
+ Assert.AreEqual<float32>(1.0f, LaunchScreen.revealProgress LaunchScreen.fadeInFrames)
+ Assert.AreEqual<float32>(1.0f, LaunchScreen.veilAlpha 0L)
+ Assert.AreEqual<float32>(0.0f, LaunchScreen.veilAlpha LaunchScreen.durationFrames)
+ Assert.IsTrue(LaunchScreen.isComplete LaunchScreen.durationFrames)
+ Assert.IsFalse(LaunchScreen.isComplete (LaunchScreen.durationFrames - 1L))
+ Assert.AreEqual<string>("江南水乡", LaunchScreen.title)
+
+ [<TestMethod>]
+ member _.StartMenuLayoutExposesStartLoadExit () =
+ // 开场结束后的可交互开始界面:无存档 → 开始/读档/退出。
+ let fresh = MenuState.create { Paused = false; Speed = OneX } false
+ Assert.AreEqual<MenuPage>(MainMenu, fresh.Page)
+ Assert.AreEqual<MenuItem list>([ NewGameItem; LoadItem; ExitItem ], MenuState.items fresh)
+ let labels = MenuState.items fresh |> List.map MenuState.itemLabel
+ Assert.AreEqual<string list>([ "开始"; "读档"; "退出" ], labels)
+ // 有进行中的世界 → 继续/读档/退出。
+ let resumed = MenuState.create { Paused = false; Speed = OneX } true
+ Assert.AreEqual<MenuItem list>([ ContinueItem; LoadItem; ExitItem ], MenuState.items resumed)
+ Assert.AreEqual<string>("继续", MenuState.itemLabel (MenuState.selectedItem resumed))