blob: b9241adb29e626ddd49a81d6d12e31d2853e5151 (
plain)
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
namespace LivingVillage.Desktop.Tests
open Microsoft.VisualStudio.TestTools.UnitTesting
open LivingVillage.Kernel
open LivingVillage.Kernel.Sim
open LivingVillage.Desktop
/// P45 角色动画帧升级回归:四向 x 8 帧(6 走 + 2 待机)原创点阵、帧序列确定性、行走推进、停止回 idle。
[<TestClass>]
type P45CharacterAnimTests () =
let assertEqualMsg (expected: 'a) (actual: 'a) (message: string) =
Assert.IsTrue((expected = actual), sprintf "%s (expected %A, actual %A)" message expected actual)
[<TestMethod>]
member _.EveryCharacterFrameIsAWellFormedDotMatrix () =
for variant in 0 .. CharacterArt.variantCount - 1 do
for direction in 0 .. CharacterArt.directionCount - 1 do
for frame in 0 .. CharacterArt.frameCount - 1 do
let rows = CharacterArt.frameLetters variant direction frame
assertEqualMsg CharacterArt.sourceHeight rows.Length (sprintf "v%d d%d f%d 行数" variant direction frame)
for row in rows do
assertEqualMsg CharacterArt.sourceWidth row.Length (sprintf "v%d d%d f%d 行宽" variant direction frame)
Assert.IsTrue(rows |> List.exists (fun r -> r.Contains "S"), "角色须有皮肤像素")
[<TestMethod>]
member _.WalkFramesAndIdleFramesDifferVisibly () =
let cellDiff (a: string list) (b: string list) : int =
List.zip a b
|> List.sumBy (fun (ra, rb) -> (Seq.zip ra rb |> Seq.filter (fun (x, y) -> x <> y) |> Seq.length))
for variant in 0 .. CharacterArt.variantCount - 1 do
for direction in 0 .. CharacterArt.directionCount - 1 do
let frames = [ 0 .. CharacterArt.frameCount - 1 ] |> List.map (CharacterArt.frameLetters variant direction)
// 四帧行走两两相邻必须有可见差异。
for i in 0 .. CharacterArt.walkFrameCount - 2 do
Assert.IsTrue(cellDiff frames.[i] frames.[i + 1] >= 4, sprintf "走帧 %d->%d 差异不足" i (i + 1))
// 待机两帧(呼吸)必须不同。
let idle1 = CharacterArt.frameLetters variant direction (CharacterArt.walkFrameCount)
let idle2 = CharacterArt.frameLetters variant direction (CharacterArt.walkFrameCount + 1)
Assert.IsTrue(cellDiff idle1 idle2 >= 4, "待机两帧差异不足")
// 行走帧与待机帧必须不同。
Assert.IsTrue(cellDiff frames.[0] idle1 >= 4, "行走帧与待机帧相同")
[<TestMethod>]
member _.FourDirectionsAreVisuallyDistinct () =
for variant in 0 .. CharacterArt.variantCount - 1 do
for frame in 0 .. CharacterArt.frameCount - 1 do
let heads =
[ 0 .. CharacterArt.directionCount - 1 ]
|> List.map (fun d -> (CharacterArt.frameLetters variant d frame) |> List.take 10)
Assert.IsTrue(heads.[0] <> heads.[1], "North 与 South 头部须不同")
Assert.IsTrue(heads.[2] <> heads.[3], "West 与 East 头部须不同")
Assert.IsTrue(heads.[0] <> heads.[2], "North 与 West 头部须不同")
[<TestMethod>]
member _.FiveVariantsHaveDistinctPalettes () =
let palettes = [ 0 .. CharacterArt.variantCount - 1 ] |> List.map CharacterArt.variantColors
assertEqualMsg CharacterArt.variantCount (palettes |> List.distinct |> List.length) "5 个变体配色须互不相同"
[<TestMethod>]
member _.AtlasDimensionsMatchTheSourceRectangleContract () =
assertEqualMsg 32 CharacterArt.cellWidth "cell 宽"
assertEqualMsg 48 CharacterArt.cellHeight "cell 高"
assertEqualMsg VillageArt.characterAtlasWidth CharacterArt.atlasWidth "图集总宽须与既有契约一致"
[<TestMethod>]
member _.DirectionMapsToDistinctDeterministicSourceCells () =
let rect variant direction frame =
VillageArt.characterSourceRectangle
{ Variant = variant; Direction = direction; Frame = frame }
for direction in [ VillageArt.NorthFacing; VillageArt.SouthFacing; VillageArt.WestFacing; VillageArt.EastFacing ] do
let a = rect VillageArt.IndigoRobe direction (VillageArt.WalkFrame VillageArt.FrameOne)
let b = rect VillageArt.IndigoRobe direction (VillageArt.WalkFrame VillageArt.FrameOne)
assertEqualMsg a b "同一输入的源矩形必须确定"
let xs =
[ VillageArt.NorthFacing; VillageArt.SouthFacing; VillageArt.WestFacing; VillageArt.EastFacing ]
|> List.map (fun d -> (rect VillageArt.IndigoRobe d (VillageArt.WalkFrame VillageArt.FrameOne)).X)
assertEqualMsg 4 (xs |> List.distinct |> List.length) "四向必须落在不同源格"
// 同向 8 帧源格逐一不同且按序排列。
let frameXs =
[ VillageArt.WalkFrame VillageArt.FrameOne
VillageArt.WalkFrame VillageArt.FrameTwo
VillageArt.WalkFrame VillageArt.FrameThree
VillageArt.WalkFrame VillageArt.FrameFour
VillageArt.WalkFrame VillageArt.FrameFive
VillageArt.WalkFrame VillageArt.FrameSix
VillageArt.IdleFrame VillageArt.IdleOne
VillageArt.IdleFrame VillageArt.IdleTwo ]
|> List.map (fun f -> (rect VillageArt.IndigoRobe VillageArt.SouthFacing f).X)
assertEqualMsg 8 (frameXs |> List.distinct |> List.length) "同向 8 帧源格须互不同"
assertEqualMsg frameXs (List.sort frameXs) "帧源格须按帧序递增"
[<TestMethod>]
member _.WalkingAdvancesFramesAndStoppingReturnsToIdle () =
// 行走:帧随 tick 按 WalkWindow 推进并循环。
assertEqualMsg (VillageArt.WalkFrame VillageArt.FrameOne) (VillageArt.characterFrame true 0L) "走 0"
assertEqualMsg (VillageArt.WalkFrame VillageArt.FrameTwo) (VillageArt.characterFrame true 4L) "走 4"
assertEqualMsg (VillageArt.WalkFrame VillageArt.FrameThree) (VillageArt.characterFrame true 8L) "走 8"
assertEqualMsg (VillageArt.WalkFrame VillageArt.FrameFour) (VillageArt.characterFrame true 12L) "走 12"
assertEqualMsg (VillageArt.WalkFrame VillageArt.FrameFive) (VillageArt.characterFrame true 16L) "走 16"
assertEqualMsg (VillageArt.WalkFrame VillageArt.FrameSix) (VillageArt.characterFrame true 20L) "走 20"
assertEqualMsg (VillageArt.WalkFrame VillageArt.FrameOne) (VillageArt.characterFrame true 24L) "走 24 循环"
// 停止:无论 tick,回 idle 两帧呼吸循环。
assertEqualMsg (VillageArt.IdleFrame VillageArt.IdleOne) (VillageArt.characterFrame false 0L) "停 0"
assertEqualMsg (VillageArt.IdleFrame VillageArt.IdleTwo) (VillageArt.characterFrame false 24L) "停 24"
assertEqualMsg (VillageArt.IdleFrame VillageArt.IdleOne) (VillageArt.characterFrame false 9999L) "停任意 tick 仍在 idle"
// 玩家行走规格:方向 + 是否移动 + tick 决定帧,四向共享同一帧序(方向只换源格)。
let framesFor direction =
[ 0L; 4L; 8L; 12L; 16L; 20L ] |> List.map (fun t -> (VillageArt.avatarSpriteSpec direction true t).Frame)
let north = framesFor VillageArt.NorthFacing
assertEqualMsg [ VillageArt.WalkFrame VillageArt.FrameOne
VillageArt.WalkFrame VillageArt.FrameTwo
VillageArt.WalkFrame VillageArt.FrameThree
VillageArt.WalkFrame VillageArt.FrameFour
VillageArt.WalkFrame VillageArt.FrameFive
VillageArt.WalkFrame VillageArt.FrameSix ] north "方向->帧序确定"
for direction in [ VillageArt.SouthFacing; VillageArt.WestFacing; VillageArt.EastFacing ] do
assertEqualMsg north (framesFor direction) "四向帧序一致"
|