From 6f58a9d1bf9aa2767fdd8fe79762e3ae7c6eeffc Mon Sep 17 00:00:00 2001 From: "Somhairle H. Marisol" Date: Mon, 21 Sep 2026 20:22:28 +0800 Subject: test(desktop): 覆盖六帧角色、待机呼吸与三相水面/炊烟 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 更新 isMoving 签名、WalkFrame 帧号、characterAtlasWidth=3840 - 水面断言改三相 (0,0,1,1,2,2,0),新增待机呼吸与炊烟三相测试 - Desktop 75/75 通过 --- src/LivingVillage.Desktop.Tests/PrototypeTests.fs | 59 +++++++++++++++++++---- 1 file 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(sameNpc, repeatedNpc) Assert.AreNotEqual(sameNpc, otherNpc) Assert.AreEqual(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(FrameOne, (VillageArt.animationFrame 0L)) Assert.AreEqual(FrameTwo, (VillageArt.animationFrame 4L)) Assert.AreEqual(FrameThree, (VillageArt.animationFrame 8L)) @@ -352,17 +352,17 @@ type PrototypeTests () = Assert.AreEqual(4, npcVariants.Count) Assert.IsFalse(npcVariants.Contains StrawHat) - Assert.AreEqual(StrawHat, (avatarSpriteSpec SouthFacing 0L).Variant) + Assert.AreEqual(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(4, variantXes.Count) - Assert.AreEqual(2560, VillageArt.characterAtlasWidth) + Assert.AreEqual(3840, VillageArt.characterAtlasWidth) [] 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([ 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([ 4; 5 ], idleXes) + [] member _.ChineseCopyProvidesFormalSceneTimeMenuAndStatusLabels () = let labels = @@ -490,14 +498,41 @@ type PrototypeTests () = | _ -> () [] - member _.WaterRippleFramesAreDeterministicAndTwoPhase () = + member _.WaterRippleFramesAreDeterministicAndThreePhase () = Assert.AreEqual(0, VillageArt.waterFrameTick 0L) Assert.AreEqual(0, VillageArt.waterFrameTick 31L) Assert.AreEqual(1, VillageArt.waterFrameTick 32L) Assert.AreEqual(1, VillageArt.waterFrameTick 63L) - Assert.AreEqual(0, VillageArt.waterFrameTick 64L) + Assert.AreEqual(2, VillageArt.waterFrameTick 64L) + Assert.AreEqual(2, VillageArt.waterFrameTick 95L) + Assert.AreEqual(0, VillageArt.waterFrameTick 96L) Assert.AreEqual(VillageArt.waterFrameTick 100L, VillageArt.waterFrameTick 100L) + [] + member _.IdleBreathCycleIsDeterministicAndDistinctFromWalking () = + // Two-pose breath cycle over a 48-tick window (one pose per 24 sim ticks). + Assert.AreEqual(IdleOne, VillageArt.idleFrame 0L) + Assert.AreEqual(IdleOne, VillageArt.idleFrame 23L) + Assert.AreEqual(IdleTwo, VillageArt.idleFrame 24L) + Assert.AreEqual(IdleOne, VillageArt.idleFrame 48L) + Assert.AreEqual(VillageArt.idleFrame 77L, VillageArt.idleFrame 77L) + + // Standing still breathes; moving walks. Both stay pure functions of tick. + Assert.AreEqual(IdleFrame IdleOne, VillageArt.characterFrame false 0L) + Assert.AreEqual(IdleFrame IdleTwo, VillageArt.characterFrame false 24L) + Assert.AreEqual(WalkFrame FrameOne, VillageArt.characterFrame true 0L) + Assert.AreEqual(WalkFrame FrameTwo, VillageArt.characterFrame true 4L) + Assert.AreEqual(VillageArt.characterFrame true 12L, VillageArt.characterFrame true 12L) + + [] + member _.ChimneySmokeFramesAreDeterministicAndThreePhase () = + Assert.AreEqual(0, VillageArt.smokeFrameTick 0L) + Assert.AreEqual(0, VillageArt.smokeFrameTick 39L) + Assert.AreEqual(1, VillageArt.smokeFrameTick 40L) + Assert.AreEqual(2, VillageArt.smokeFrameTick 80L) + Assert.AreEqual(0, VillageArt.smokeFrameTick 120L) + Assert.AreEqual(VillageArt.smokeFrameTick 99L, VillageArt.smokeFrameTick 99L) + [] member _.RiverBandSpansTheSceneWithBankPathsAndCrossing () = let plan = VillageArt.sampleRenderPlan () @@ -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.EastFacing, idle) Assert.AreEqual(VillageArt.WestFacing, moved) Assert.AreEqual(VillageArt.NorthFacing, targetSpec.Direction) + // Walking toward a target uses the walk cycle; reaching it settles into the breath cycle. + Assert.AreEqual(WalkFrame FrameTwo, targetSpec.Frame) + Assert.AreEqual(IdleFrame IdleOne, arrivedSpec.Frame) [] member _.RenderPlanCoordinatesAndCharacterAtlasCellsAreDeterministic () = @@ -548,8 +587,8 @@ type PrototypeTests () = let expectedWorldTile : TilePosition = { X = 31; Y = 22 } Assert.AreEqual(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(first, second) Assert.AreEqual(32, first.Width) Assert.AreEqual(48, first.Height) -- cgit v1.2.3