summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-21 20:22:28 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-21 20:22:28 +0800
commit6f58a9d1bf9aa2767fdd8fe79762e3ae7c6eeffc (patch)
treeeb765a837db1521151c08d6453c59e1951ace05b
parenta16d0cd0c079530385b53026133c93af69be5628 (diff)
downloadliving-village-6f58a9d1bf9aa2767fdd8fe79762e3ae7c6eeffc.tar.gz
test(desktop): 覆盖六帧角色、待机呼吸与三相水面/炊烟
- 更新 isMoving 签名、WalkFrame 帧号、characterAtlasWidth=3840 - 水面断言改三相 (0,0,1,1,2,2,0),新增待机呼吸与炊烟三相测试 - Desktop 75/75 通过
-rw-r--r--src/LivingVillage.Desktop.Tests/PrototypeTests.fs59
1 files changed, 49 insertions, 10 deletions
diff --git a/src/LivingVillage.Desktop.Tests/PrototypeTests.fs b/src/LivingVillage.Desktop.Tests/PrototypeTests.fs
index bf8fa82..46fb878 100644
--- a/src/LivingVillage.Desktop.Tests/PrototypeTests.fs
+++ b/src/LivingVillage.Desktop.Tests/PrototypeTests.fs
@@ -334,12 +334,12 @@ type PrototypeTests () =
SouthFacing
WestFacing
EastFacing ]
- let sprites = directions |> List.map (fun direction -> npcSpriteSpec (NpcId 7) direction 4L)
+ let sprites = directions |> List.map (fun direction -> npcSpriteSpec (NpcId 7) direction true 4L)
Assert.AreEqual<NpcVisualVariant>(sameNpc, repeatedNpc)
Assert.AreNotEqual<NpcVisualVariant>(sameNpc, otherNpc)
Assert.AreEqual<int>(4, sprites |> List.map (fun sprite -> sprite.Direction) |> List.distinct |> List.length)
- Assert.IsTrue(sprites |> List.forall (fun sprite -> sprite.Frame = FrameTwo))
+ Assert.IsTrue(sprites |> List.forall (fun sprite -> sprite.Frame = WalkFrame FrameTwo))
Assert.AreEqual<AnimationFrame>(FrameOne, (VillageArt.animationFrame 0L))
Assert.AreEqual<AnimationFrame>(FrameTwo, (VillageArt.animationFrame 4L))
Assert.AreEqual<AnimationFrame>(FrameThree, (VillageArt.animationFrame 8L))
@@ -352,17 +352,17 @@ type PrototypeTests () =
Assert.AreEqual<int>(4, npcVariants.Count)
Assert.IsFalse(npcVariants.Contains StrawHat)
- Assert.AreEqual<NpcVisualVariant>(StrawHat, (avatarSpriteSpec SouthFacing 0L).Variant)
+ Assert.AreEqual<NpcVisualVariant>(StrawHat, (avatarSpriteSpec SouthFacing true 0L).Variant)
let variantXes =
npcVariants
|> Set.toList
|> List.map (fun variant ->
- let rect = characterSourceRectangle { Variant = variant; Direction = SouthFacing; Frame = FrameOne }
+ let rect = characterSourceRectangle { Variant = variant; Direction = SouthFacing; Frame = WalkFrame FrameOne }
rect.X)
|> Set.ofList
Assert.AreEqual<int>(4, variantXes.Count)
- Assert.AreEqual<int>(2560, VillageArt.characterAtlasWidth)
+ Assert.AreEqual<int>(3840, VillageArt.characterAtlasWidth)
[<TestMethod>]
member _.WalkAnimationCoversFourFramesDeterministically () =
@@ -381,10 +381,18 @@ type PrototypeTests () =
let perFrameX =
[ FrameOne; FrameTwo; FrameThree; FrameFour ]
|> List.map (fun frame ->
- let rect = characterSourceRectangle { Variant = IndigoRobe; Direction = NorthFacing; Frame = frame }
+ let rect = characterSourceRectangle { Variant = IndigoRobe; Direction = NorthFacing; Frame = WalkFrame frame }
rect.X / 32)
Assert.AreEqual<int list>([ 0; 1; 2; 3 ], perFrameX)
+ // Idle breath poses occupy the two cells after the walk cycle for each (variant, direction).
+ let idleXes =
+ [ IdleOne; IdleTwo ]
+ |> List.map (fun frame ->
+ let rect = characterSourceRectangle { Variant = IndigoRobe; Direction = NorthFacing; Frame = IdleFrame frame }
+ rect.X / 32)
+ Assert.AreEqual<int list>([ 4; 5 ], idleXes)
+
[<TestMethod>]
member _.ChineseCopyProvidesFormalSceneTimeMenuAndStatusLabels () =
let labels =
@@ -490,15 +498,42 @@ type PrototypeTests () =
| _ -> ()
[<TestMethod>]
- member _.WaterRippleFramesAreDeterministicAndTwoPhase () =
+ member _.WaterRippleFramesAreDeterministicAndThreePhase () =
Assert.AreEqual<int>(0, VillageArt.waterFrameTick 0L)
Assert.AreEqual<int>(0, VillageArt.waterFrameTick 31L)
Assert.AreEqual<int>(1, VillageArt.waterFrameTick 32L)
Assert.AreEqual<int>(1, VillageArt.waterFrameTick 63L)
- Assert.AreEqual<int>(0, VillageArt.waterFrameTick 64L)
+ Assert.AreEqual<int>(2, VillageArt.waterFrameTick 64L)
+ Assert.AreEqual<int>(2, VillageArt.waterFrameTick 95L)
+ Assert.AreEqual<int>(0, VillageArt.waterFrameTick 96L)
Assert.AreEqual<int>(VillageArt.waterFrameTick 100L, VillageArt.waterFrameTick 100L)
[<TestMethod>]
+ member _.IdleBreathCycleIsDeterministicAndDistinctFromWalking () =
+ // Two-pose breath cycle over a 48-tick window (one pose per 24 sim ticks).
+ Assert.AreEqual<IdleFrame>(IdleOne, VillageArt.idleFrame 0L)
+ Assert.AreEqual<IdleFrame>(IdleOne, VillageArt.idleFrame 23L)
+ Assert.AreEqual<IdleFrame>(IdleTwo, VillageArt.idleFrame 24L)
+ Assert.AreEqual<IdleFrame>(IdleOne, VillageArt.idleFrame 48L)
+ Assert.AreEqual<IdleFrame>(VillageArt.idleFrame 77L, VillageArt.idleFrame 77L)
+
+ // Standing still breathes; moving walks. Both stay pure functions of tick.
+ Assert.AreEqual<CharacterFrame>(IdleFrame IdleOne, VillageArt.characterFrame false 0L)
+ Assert.AreEqual<CharacterFrame>(IdleFrame IdleTwo, VillageArt.characterFrame false 24L)
+ Assert.AreEqual<CharacterFrame>(WalkFrame FrameOne, VillageArt.characterFrame true 0L)
+ Assert.AreEqual<CharacterFrame>(WalkFrame FrameTwo, VillageArt.characterFrame true 4L)
+ Assert.AreEqual<CharacterFrame>(VillageArt.characterFrame true 12L, VillageArt.characterFrame true 12L)
+
+ [<TestMethod>]
+ member _.ChimneySmokeFramesAreDeterministicAndThreePhase () =
+ Assert.AreEqual<int>(0, VillageArt.smokeFrameTick 0L)
+ Assert.AreEqual<int>(0, VillageArt.smokeFrameTick 39L)
+ Assert.AreEqual<int>(1, VillageArt.smokeFrameTick 40L)
+ Assert.AreEqual<int>(2, VillageArt.smokeFrameTick 80L)
+ Assert.AreEqual<int>(0, VillageArt.smokeFrameTick 120L)
+ Assert.AreEqual<int>(VillageArt.smokeFrameTick 99L, VillageArt.smokeFrameTick 99L)
+
+ [<TestMethod>]
member _.RiverBandSpansTheSceneWithBankPathsAndCrossing () =
let plan = VillageArt.sampleRenderPlan ()
let footprintOf (value: VillageArt.JiangnanRenderPlan) = VillageArt.planFootprint value
@@ -535,10 +570,14 @@ type PrototypeTests () =
let idle = VillageArt.facingAfterMovement { X = 4.0f; Y = 4.0f } { X = 4.0f; Y = 4.0f } VillageArt.EastFacing
let moved = VillageArt.facingAfterMovement { X = 4.0f; Y = 4.0f } { X = 2.0f; Y = 4.0f } VillageArt.EastFacing
let targetSpec = VillageArt.npcSpriteSpecAtTarget (NpcId 7) { X = 10.0f; Y = 10.0f } { X = 10.0f; Y = 8.0f } 4L
+ let arrivedSpec = VillageArt.npcSpriteSpecAtTarget (NpcId 7) { X = 10.0f; Y = 10.0f } { X = 10.0f; Y = 10.0f } 4L
Assert.AreEqual<VillageArt.FacingDirection>(VillageArt.EastFacing, idle)
Assert.AreEqual<VillageArt.FacingDirection>(VillageArt.WestFacing, moved)
Assert.AreEqual<VillageArt.FacingDirection>(VillageArt.NorthFacing, targetSpec.Direction)
+ // Walking toward a target uses the walk cycle; reaching it settles into the breath cycle.
+ Assert.AreEqual<CharacterFrame>(WalkFrame FrameTwo, targetSpec.Frame)
+ Assert.AreEqual<CharacterFrame>(IdleFrame IdleOne, arrivedSpec.Frame)
[<TestMethod>]
member _.RenderPlanCoordinatesAndCharacterAtlasCellsAreDeterministic () =
@@ -548,8 +587,8 @@ type PrototypeTests () =
let expectedWorldTile : TilePosition = { X = 31; Y = 22 }
Assert.AreEqual<TilePosition>(expectedWorldTile, worldTile)
- let first = VillageArt.characterSourceRectangle { Variant = IndigoRobe; Direction = NorthFacing; Frame = FrameOne }
- let second = VillageArt.characterSourceRectangle { Variant = JadeSash; Direction = EastFacing; Frame = FrameTwo }
+ let first = VillageArt.characterSourceRectangle { Variant = IndigoRobe; Direction = NorthFacing; Frame = WalkFrame FrameOne }
+ let second = VillageArt.characterSourceRectangle { Variant = JadeSash; Direction = EastFacing; Frame = WalkFrame FrameTwo }
Assert.AreNotEqual<Rectangle>(first, second)
Assert.AreEqual<int>(32, first.Width)
Assert.AreEqual<int>(48, first.Height)