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
|
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))
|