feat: 帧动画Timeline问题处理
This commit is contained in:
@@ -15,325 +15,325 @@ MonoBehaviour:
|
||||
id: intro
|
||||
displayName: "\u68C0\u7D22"
|
||||
frames:
|
||||
- sprite: {fileID: 7572446778344178281, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 504396963, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 0.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 0.aseprite"
|
||||
sourceIndex: 0
|
||||
- sprite: {fileID: -362215467011434174, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 291796385, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 1.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 1.aseprite"
|
||||
sourceIndex: 1
|
||||
- sprite: {fileID: -4996972306367436102, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 624098569, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 2.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 2.aseprite"
|
||||
sourceIndex: 2
|
||||
- sprite: {fileID: -6337999013739407263, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1172030325, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 3.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 3.aseprite"
|
||||
sourceIndex: 3
|
||||
- sprite: {fileID: 6998681854070186983, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1079787295, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 4.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 4.aseprite"
|
||||
sourceIndex: 4
|
||||
- sprite: {fileID: 6998681854070186983, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1311865483, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 5.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 5.aseprite"
|
||||
sourceIndex: 5
|
||||
- sprite: {fileID: 4876995554275767483, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -127897218, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 6.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 6.aseprite"
|
||||
sourceIndex: 6
|
||||
- sprite: {fileID: 4876995554275767483, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 2097211279, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 7.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 7.aseprite"
|
||||
sourceIndex: 7
|
||||
- sprite: {fileID: -1351993313840321639, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1750020038, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 8.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 8.aseprite"
|
||||
sourceIndex: 8
|
||||
- sprite: {fileID: -1351993313840321639, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 242499730, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 9.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 9.aseprite"
|
||||
sourceIndex: 9
|
||||
- sprite: {fileID: 2953902384930482259, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -345723938, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 10.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 10.aseprite"
|
||||
sourceIndex: 10
|
||||
- sprite: {fileID: 2953902384930482259, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -225466995, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 11.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 11.aseprite"
|
||||
sourceIndex: 11
|
||||
- sprite: {fileID: -8223510296345293682, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1197766663, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 12.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 12.aseprite"
|
||||
sourceIndex: 12
|
||||
- sprite: {fileID: -8223510296345293682, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -122112883, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 13.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 13.aseprite"
|
||||
sourceIndex: 13
|
||||
- sprite: {fileID: 3051864550455069342, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1850433033, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 14.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 14.aseprite"
|
||||
sourceIndex: 14
|
||||
- sprite: {fileID: 3051864550455069342, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -126566680, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 15.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 15.aseprite"
|
||||
sourceIndex: 15
|
||||
- sprite: {fileID: 651861321318766745, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -675809634, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 16.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 16.aseprite"
|
||||
sourceIndex: 16
|
||||
- sprite: {fileID: 651861321318766745, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1660958210, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 17.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 17.aseprite"
|
||||
sourceIndex: 17
|
||||
- sprite: {fileID: 6360117332621625605, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1487325629, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 18.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 18.aseprite"
|
||||
sourceIndex: 18
|
||||
- sprite: {fileID: 2110206911040411466, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1348725402, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 19.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 19.aseprite"
|
||||
sourceIndex: 19
|
||||
- sprite: {fileID: -8552977822448111447, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -459077972, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 20.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 20.aseprite"
|
||||
sourceIndex: 20
|
||||
- sprite: {fileID: -2421474681753995496, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1340036015, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 21.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 21.aseprite"
|
||||
sourceIndex: 21
|
||||
- sprite: {fileID: -7492713014907810856, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 243863421, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 22.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 22.aseprite"
|
||||
sourceIndex: 22
|
||||
- sprite: {fileID: -7492713014907810856, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -843151036, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 23.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 23.aseprite"
|
||||
sourceIndex: 23
|
||||
- sprite: {fileID: -7720457564735758752, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -2125577238, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 24.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 24.aseprite"
|
||||
sourceIndex: 24
|
||||
- sprite: {fileID: -7720457564735758752, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1214599644, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 25.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 25.aseprite"
|
||||
sourceIndex: 25
|
||||
- sprite: {fileID: 1880112101706155564, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1425693306, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 26.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 26.aseprite"
|
||||
sourceIndex: 26
|
||||
- sprite: {fileID: -3623330345461600317, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 156535619, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 27.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 27.aseprite"
|
||||
sourceIndex: 27
|
||||
- sprite: {fileID: -4821937940866556909, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -171496837, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 28.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 28.aseprite"
|
||||
sourceIndex: 28
|
||||
- sprite: {fileID: -4821937940866556909, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1856768746, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 29.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 29.aseprite"
|
||||
sourceIndex: 29
|
||||
- sprite: {fileID: -1230447193968539563, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1997184234, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 30.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 30.aseprite"
|
||||
sourceIndex: 30
|
||||
- sprite: {fileID: -1230447193968539563, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -791780188, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 31.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 31.aseprite"
|
||||
sourceIndex: 31
|
||||
- sprite: {fileID: -3452787567901838671, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 349163604, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 32.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 32.aseprite"
|
||||
sourceIndex: 32
|
||||
- sprite: {fileID: 2122325496977185700, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 976052101, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 33.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 33.aseprite"
|
||||
sourceIndex: 33
|
||||
- sprite: {fileID: -3452787567901838671, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1121699258, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 34.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 34.aseprite"
|
||||
sourceIndex: 34
|
||||
- sprite: {fileID: -3452787567901838671, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1630996947, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 35.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 35.aseprite"
|
||||
sourceIndex: 35
|
||||
- sprite: {fileID: -3838368664758933209, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 743051906, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 36.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 36.aseprite"
|
||||
sourceIndex: 36
|
||||
- sprite: {fileID: -3838368664758933209, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 867729767, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 37.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 37.aseprite"
|
||||
sourceIndex: 37
|
||||
- sprite: {fileID: -3838368664758933209, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1393316141, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 38.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 38.aseprite"
|
||||
sourceIndex: 38
|
||||
- sprite: {fileID: -3838368664758933209, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -31726791, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 39.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 39.aseprite"
|
||||
sourceIndex: 39
|
||||
- sprite: {fileID: -8974752115445585213, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 948510867, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 40.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 40.aseprite"
|
||||
sourceIndex: 40
|
||||
- sprite: {fileID: -8974752115445585213, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1388676038, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 41.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 41.aseprite"
|
||||
sourceIndex: 41
|
||||
- sprite: {fileID: -8974752115445585213, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -119360074, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 42.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 42.aseprite"
|
||||
sourceIndex: 42
|
||||
- sprite: {fileID: -8974752115445585213, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1367469597, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 43.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 43.aseprite"
|
||||
sourceIndex: 43
|
||||
- sprite: {fileID: 862258456695450341, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -659839448, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 200
|
||||
frameName: "\u68C0\u7D22 44.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 44.aseprite"
|
||||
sourceIndex: 44
|
||||
- sprite: {fileID: -5458642827783654469, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1966371428, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 200
|
||||
frameName: "\u68C0\u7D22 45.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 45.aseprite"
|
||||
sourceIndex: 45
|
||||
- sprite: {fileID: 4197853090659475812, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -282229650, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 200
|
||||
frameName: "\u68C0\u7D22 46.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 46.aseprite"
|
||||
sourceIndex: 46
|
||||
- sprite: {fileID: -1155378306054861757, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1093358863, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 200
|
||||
frameName: "\u68C0\u7D22 47.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 47.aseprite"
|
||||
sourceIndex: 47
|
||||
- sprite: {fileID: -1204860713, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 492557654, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 48.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 48.aseprite"
|
||||
sourceIndex: 48
|
||||
- sprite: {fileID: -1204860713, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1027775630, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 49.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 49.aseprite"
|
||||
sourceIndex: 49
|
||||
- sprite: {fileID: 2080999944, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 480031666, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 50.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 50.aseprite"
|
||||
sourceIndex: 50
|
||||
- sprite: {fileID: 433384928, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1866608668, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 51.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 51.aseprite"
|
||||
sourceIndex: 51
|
||||
- sprite: {fileID: -804306678, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -6198359, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 52.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 52.aseprite"
|
||||
sourceIndex: 52
|
||||
- sprite: {fileID: 472963922, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1797269849, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 53.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 53.aseprite"
|
||||
sourceIndex: 53
|
||||
- sprite: {fileID: 318794721, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 111881738, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 54.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 54.aseprite"
|
||||
sourceIndex: 54
|
||||
- sprite: {fileID: 318794721, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -408735183, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 55.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 55.aseprite"
|
||||
sourceIndex: 55
|
||||
- sprite: {fileID: 1203749929, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1501946279, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 56.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 56.aseprite"
|
||||
sourceIndex: 56
|
||||
- sprite: {fileID: 1203749929, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1313030664, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 57.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 57.aseprite"
|
||||
sourceIndex: 57
|
||||
- sprite: {fileID: 1203749929, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1750040965, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 58.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 58.aseprite"
|
||||
sourceIndex: 58
|
||||
- sprite: {fileID: 1203749929, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1504143884, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 59.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 59.aseprite"
|
||||
sourceIndex: 59
|
||||
- sprite: {fileID: -1984404506, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1501118800, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 60.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 60.aseprite"
|
||||
sourceIndex: 60
|
||||
- sprite: {fileID: 1047793495, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 904547507, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 61.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 61.aseprite"
|
||||
sourceIndex: 61
|
||||
- sprite: {fileID: 174328586, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -913400871, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 62.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 62.aseprite"
|
||||
sourceIndex: 62
|
||||
- sprite: {fileID: 1047793495, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1051838451, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 63.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 63.aseprite"
|
||||
sourceIndex: 63
|
||||
- sprite: {fileID: -1198657009, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 763501950, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 64.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 64.aseprite"
|
||||
sourceIndex: 64
|
||||
- sprite: {fileID: -1198657009, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1197653475, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 65.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 65.aseprite"
|
||||
sourceIndex: 65
|
||||
- sprite: {fileID: -1198657009, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 791718236, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 66.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 66.aseprite"
|
||||
sourceIndex: 66
|
||||
- sprite: {fileID: -1198657009, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -163897732, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 67.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 67.aseprite"
|
||||
sourceIndex: 67
|
||||
- sprite: {fileID: -342147049, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1215937852, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 68.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 68.aseprite"
|
||||
sourceIndex: 68
|
||||
- sprite: {fileID: -342147049, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1449555021, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 69.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 69.aseprite"
|
||||
sourceIndex: 69
|
||||
- sprite: {fileID: -342147049, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 314772697, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 70.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 70.aseprite"
|
||||
sourceIndex: 70
|
||||
- sprite: {fileID: -342147049, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1243762998, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 71.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 71.aseprite"
|
||||
sourceIndex: 71
|
||||
- sprite: {fileID: 1733318757, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1165852085, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 72.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 72.aseprite"
|
||||
sourceIndex: 72
|
||||
- sprite: {fileID: 1733318757, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -111638770, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 73.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 73.aseprite"
|
||||
sourceIndex: 73
|
||||
- sprite: {fileID: 1733318757, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -451272891, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 74.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 74.aseprite"
|
||||
sourceIndex: 74
|
||||
- sprite: {fileID: 1733318757, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -1843965549, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 50
|
||||
frameName: "\u68C0\u7D22 75.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 75.aseprite"
|
||||
sourceIndex: 75
|
||||
- sprite: {fileID: -84262779, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -822097726, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 200
|
||||
frameName: "\u68C0\u7D22 76.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 76.aseprite"
|
||||
sourceIndex: 76
|
||||
- sprite: {fileID: 1947069765, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 576137929, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 200
|
||||
frameName: "\u68C0\u7D22 77.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 77.aseprite"
|
||||
sourceIndex: 77
|
||||
- sprite: {fileID: 1547981314, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: -314263957, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 200
|
||||
frameName: "\u68C0\u7D22 78.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 78.aseprite"
|
||||
sourceIndex: 78
|
||||
- sprite: {fileID: 1904593827, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
- sprite: {fileID: 1140765657, guid: 060544baeb316214698dd0ea788a63dd, type: 3}
|
||||
durationMs: 200
|
||||
frameName: "\u68C0\u7D22 79.aseprite"
|
||||
frameName: "\u68C0\u7D22(1) 79.aseprite"
|
||||
sourceIndex: 79
|
||||
speed: 1
|
||||
defaultEndBehavior: 2
|
||||
@@ -348,5 +348,5 @@ MonoBehaviour:
|
||||
asepriteJson: {fileID: 4900000, guid: 9281f1c256bc53140a36bb9439d2d5d6, type: 3}
|
||||
pivot: {x: 0.5, y: 0.5}
|
||||
manageSpriteSlicing: 1
|
||||
lastSourceHash: a0c976cb23f6f387b5a0d81c36299682ec4e5b14a0894eb63b5aaf19fc228739
|
||||
lastSourceHash: e24b62891974cbe19bc0868bcfa298b82c6d4f485faea653b802122dd6ea79a1
|
||||
lastImportedTagName: intro
|
||||
|
||||
@@ -648,8 +648,7 @@
|
||||
"size": { "w": 6144, "h": 4320 },
|
||||
"scale": "1",
|
||||
"frameTags": [
|
||||
{ "name": "intro", "from": 0, "to": 47, "direction": "forward", "color": "#000000ff" },
|
||||
{ "name": "loop", "from": 48, "to": 79, "direction": "forward", "color": "#000000ff" }
|
||||
{ "name": "intro", "from": 0, "to": 79, "direction": "forward", "color": "#000000ff" }
|
||||
],
|
||||
"layers": [
|
||||
{ "name": "black", "opacity": 89, "blendMode": "normal" },
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -24,7 +24,7 @@ MonoBehaviour:
|
||||
- m_Version: 1
|
||||
m_Start: 0
|
||||
m_ClipIn: 0
|
||||
m_Asset: {fileID: 3051057393504210916}
|
||||
m_Asset: {fileID: -2259439808282263793}
|
||||
m_Duration: 5.2
|
||||
m_TimeScale: 1
|
||||
m_ParentTrack: {fileID: -5039998276998606052}
|
||||
@@ -92,6 +92,21 @@ MonoBehaviour:
|
||||
m_DisplayName: "\u68C0\u7D22"
|
||||
m_Markers:
|
||||
m_Objects: []
|
||||
--- !u!114 &-2259439808282263793
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: c908631f9d7446ac86914dce3f1927af, type: 3}
|
||||
m_Name: FrameAnimationTimelineClip
|
||||
m_EditorClassIdentifier:
|
||||
frameClip: {fileID: 11400000, guid: dc9666f5991e1be4bb0e5f149055f91a, type: 2}
|
||||
synchronizedDurationSource: {fileID: 11400000, guid: dc9666f5991e1be4bb0e5f149055f91a, type: 2}
|
||||
hasSynchronizedDuration: 1
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -113,18 +128,3 @@ MonoBehaviour:
|
||||
m_ScenePreview: 1
|
||||
m_DurationMode: 0
|
||||
m_MarkerTrack: {fileID: 0}
|
||||
--- !u!114 &3051057393504210916
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: c908631f9d7446ac86914dce3f1927af, type: 3}
|
||||
m_Name: FrameAnimationTimelineClip
|
||||
m_EditorClassIdentifier:
|
||||
frameClip: {fileID: 11400000, guid: dc9666f5991e1be4bb0e5f149055f91a, type: 2}
|
||||
synchronizedDurationSource: {fileID: 11400000, guid: dc9666f5991e1be4bb0e5f149055f91a, type: 2}
|
||||
hasSynchronizedDuration: 1
|
||||
|
||||
@@ -11141,7 +11141,7 @@ MeshRenderer:
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: -6659093157667844055, guid: f242fb3dde1933640859f1c54591c9c8, type: 2}
|
||||
- {fileID: 5536230373871310787, guid: 1625bd86098eb0843b1a69eb1b3354e4, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
@@ -11185,8 +11185,8 @@ MonoBehaviour:
|
||||
m_Calls: []
|
||||
m_text: "\u5F85\u529E\u6E05\u5355"
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: f242fb3dde1933640859f1c54591c9c8, type: 2}
|
||||
m_sharedMaterial: {fileID: -6659093157667844055, guid: f242fb3dde1933640859f1c54591c9c8, type: 2}
|
||||
m_fontAsset: {fileID: 11400000, guid: 1625bd86098eb0843b1a69eb1b3354e4, type: 2}
|
||||
m_sharedMaterial: {fileID: 5536230373871310787, guid: 1625bd86098eb0843b1a69eb1b3354e4, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
|
||||
+807
-878
File diff suppressed because it is too large
Load Diff
@@ -89,6 +89,7 @@ namespace AibisDream.FrameAnimation
|
||||
private bool hasStarted;
|
||||
private bool hasCompleted;
|
||||
private bool hasCompletedFirstTerminalLoopCycle;
|
||||
private SeekIndex seekIndex;
|
||||
|
||||
public string PlayableId => plan.PlayableId;
|
||||
public string CurrentClipId => CurrentStep?.Clip != null ? CurrentStep.Clip.Id : string.Empty;
|
||||
@@ -140,10 +141,49 @@ namespace AibisDream.FrameAnimation
|
||||
|
||||
internal FrameAnimationSessionEvaluation Seek(double realSeconds, Action<Sprite> applySprite)
|
||||
{
|
||||
Restart(applySprite);
|
||||
return realSeconds <= 0d
|
||||
? FrameAnimationSessionEvaluation.Running
|
||||
: Evaluate(realSeconds, 1f, applySprite);
|
||||
if (!TryGetSeekIndex(out var index, out var error))
|
||||
{
|
||||
hasStarted = true;
|
||||
hasCompleted = true;
|
||||
return FrameAnimationSessionEvaluation.Failed(error.Code, error.Message);
|
||||
}
|
||||
|
||||
hasStarted = true;
|
||||
hasCompleted = false;
|
||||
hasCompletedFirstTerminalLoopCycle = false;
|
||||
|
||||
var clampedSeconds = Math.Max(0d, realSeconds);
|
||||
var terminalStepIndex = index.Steps.Length - 1;
|
||||
var terminalStep = index.Steps[terminalStepIndex];
|
||||
if (terminalStep.EndBehavior == FrameClipEndBehavior.Loop &&
|
||||
clampedSeconds + Epsilon >= terminalStep.StartSeconds)
|
||||
{
|
||||
SeekTerminalLoop(terminalStepIndex, terminalStep, clampedSeconds);
|
||||
ApplyCurrentFrame(applySprite);
|
||||
return FrameAnimationSessionEvaluation.Running;
|
||||
}
|
||||
|
||||
if (!double.IsPositiveInfinity(index.TotalDurationSeconds) &&
|
||||
clampedSeconds + Epsilon >= index.TotalDurationSeconds)
|
||||
{
|
||||
stepIndex = terminalStepIndex;
|
||||
frameIndex = terminalStep.FrameEndSeconds.Length - 1;
|
||||
frameElapsedSeconds = 0d;
|
||||
hasCompleted = true;
|
||||
ApplyCurrentFrame(applySprite);
|
||||
return FrameAnimationSessionEvaluation.Completed(terminalStep.EndBehavior);
|
||||
}
|
||||
|
||||
stepIndex = FindFirstBoundaryAfter(index.StepEndSeconds, clampedSeconds);
|
||||
if (stepIndex < 0 || stepIndex >= index.Steps.Length)
|
||||
{
|
||||
stepIndex = terminalStepIndex;
|
||||
}
|
||||
|
||||
var seekStep = index.Steps[stepIndex];
|
||||
SeekWithinStep(seekStep, clampedSeconds - seekStep.StartSeconds);
|
||||
ApplyCurrentFrame(applySprite);
|
||||
return FrameAnimationSessionEvaluation.Running;
|
||||
}
|
||||
|
||||
public FrameAnimationSessionEvaluation Evaluate(
|
||||
@@ -273,6 +313,169 @@ namespace AibisDream.FrameAnimation
|
||||
return clip.TotalDurationMs / 1000d;
|
||||
}
|
||||
|
||||
private bool TryGetSeekIndex(
|
||||
out SeekIndex index,
|
||||
out FrameAnimationPlaybackError error)
|
||||
{
|
||||
if (seekIndex != null)
|
||||
{
|
||||
index = seekIndex;
|
||||
error = FrameAnimationPlaybackError.None;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (plan.Steps == null || plan.Steps.Count == 0)
|
||||
{
|
||||
index = null;
|
||||
error = new FrameAnimationPlaybackError(
|
||||
FrameAnimationPlaybackErrorCode.InvalidPlayableData,
|
||||
"播放计划不包含任何可播放 Step。");
|
||||
return false;
|
||||
}
|
||||
|
||||
var steps = new SeekStep[plan.Steps.Count];
|
||||
var stepEndSeconds = new double[steps.Length];
|
||||
var elapsedSeconds = 0d;
|
||||
for (var currentStepIndex = 0; currentStepIndex < steps.Length; currentStepIndex++)
|
||||
{
|
||||
var resolvedStep = plan.Steps[currentStepIndex];
|
||||
if (resolvedStep?.Clip == null || resolvedStep.Clip.FrameCount <= 0)
|
||||
{
|
||||
index = null;
|
||||
error = new FrameAnimationPlaybackError(
|
||||
FrameAnimationPlaybackErrorCode.InvalidPlayableData,
|
||||
"播放期间 Clip 或 Frame 数据失效。");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FrameAnimationValueUtility.IsValidSpeed(resolvedStep.PlaybackSpeed))
|
||||
{
|
||||
index = null;
|
||||
error = new FrameAnimationPlaybackError(
|
||||
FrameAnimationPlaybackErrorCode.InvalidSpeed,
|
||||
"播放期间有效速度变为无效值。");
|
||||
return false;
|
||||
}
|
||||
|
||||
var frameEndSeconds = new double[resolvedStep.Clip.FrameCount];
|
||||
var stepDurationSeconds = 0d;
|
||||
for (var currentFrameIndex = 0;
|
||||
currentFrameIndex < resolvedStep.Clip.FrameCount;
|
||||
currentFrameIndex++)
|
||||
{
|
||||
var frame = resolvedStep.Clip.Frames[currentFrameIndex];
|
||||
if (frame == null || frame.DurationMs <= 0)
|
||||
{
|
||||
index = null;
|
||||
error = new FrameAnimationPlaybackError(
|
||||
FrameAnimationPlaybackErrorCode.InvalidPlayableData,
|
||||
"播放期间 Frame 数据失效或 durationMs 不再有效。");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resolvedStep.PlaybackSpeed == 0f)
|
||||
{
|
||||
frameEndSeconds[currentFrameIndex] = double.PositiveInfinity;
|
||||
}
|
||||
else
|
||||
{
|
||||
stepDurationSeconds += frame.DurationMs / 1000d / resolvedStep.PlaybackSpeed;
|
||||
frameEndSeconds[currentFrameIndex] = stepDurationSeconds;
|
||||
}
|
||||
}
|
||||
|
||||
if (resolvedStep.PlaybackSpeed == 0f)
|
||||
{
|
||||
stepDurationSeconds = double.PositiveInfinity;
|
||||
}
|
||||
|
||||
steps[currentStepIndex] = new SeekStep(
|
||||
elapsedSeconds,
|
||||
stepDurationSeconds,
|
||||
resolvedStep.PlaybackSpeed,
|
||||
resolvedStep.TerminalEndBehavior,
|
||||
frameEndSeconds);
|
||||
elapsedSeconds += stepDurationSeconds;
|
||||
stepEndSeconds[currentStepIndex] = elapsedSeconds;
|
||||
}
|
||||
|
||||
seekIndex = new SeekIndex(steps, stepEndSeconds, elapsedSeconds);
|
||||
index = seekIndex;
|
||||
error = FrameAnimationPlaybackError.None;
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SeekTerminalLoop(
|
||||
int terminalStepIndex,
|
||||
SeekStep terminalStep,
|
||||
double realSeconds)
|
||||
{
|
||||
stepIndex = terminalStepIndex;
|
||||
if (terminalStep.PlaybackSpeed == 0f ||
|
||||
double.IsPositiveInfinity(terminalStep.DurationSeconds))
|
||||
{
|
||||
frameIndex = 0;
|
||||
frameElapsedSeconds = 0d;
|
||||
return;
|
||||
}
|
||||
|
||||
var terminalElapsedSeconds = Math.Max(0d, realSeconds - terminalStep.StartSeconds);
|
||||
hasCompletedFirstTerminalLoopCycle =
|
||||
terminalElapsedSeconds + Epsilon >= terminalStep.DurationSeconds;
|
||||
var localSeconds = terminalElapsedSeconds % terminalStep.DurationSeconds;
|
||||
if (localSeconds + Epsilon >= terminalStep.DurationSeconds)
|
||||
{
|
||||
localSeconds = 0d;
|
||||
}
|
||||
|
||||
SeekWithinStep(terminalStep, localSeconds);
|
||||
}
|
||||
|
||||
private void SeekWithinStep(SeekStep seekStep, double localRealSeconds)
|
||||
{
|
||||
if (seekStep.PlaybackSpeed == 0f)
|
||||
{
|
||||
frameIndex = 0;
|
||||
frameElapsedSeconds = 0d;
|
||||
return;
|
||||
}
|
||||
|
||||
var clampedLocalSeconds = Math.Max(0d, localRealSeconds);
|
||||
frameIndex = FindFirstBoundaryAfter(seekStep.FrameEndSeconds, clampedLocalSeconds);
|
||||
if (frameIndex < 0 || frameIndex >= seekStep.FrameEndSeconds.Length)
|
||||
{
|
||||
frameIndex = seekStep.FrameEndSeconds.Length - 1;
|
||||
}
|
||||
|
||||
var frameStartRealSeconds = frameIndex == 0
|
||||
? 0d
|
||||
: seekStep.FrameEndSeconds[frameIndex - 1];
|
||||
frameElapsedSeconds = Math.Max(
|
||||
0d,
|
||||
(clampedLocalSeconds - frameStartRealSeconds) * seekStep.PlaybackSpeed);
|
||||
}
|
||||
|
||||
private static int FindFirstBoundaryAfter(double[] boundaries, double seconds)
|
||||
{
|
||||
var low = 0;
|
||||
var high = boundaries.Length;
|
||||
var comparisonSeconds = seconds + Epsilon;
|
||||
while (low < high)
|
||||
{
|
||||
var middle = low + ((high - low) >> 1);
|
||||
if (boundaries[middle] > comparisonSeconds)
|
||||
{
|
||||
high = middle;
|
||||
}
|
||||
else
|
||||
{
|
||||
low = middle + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
private void ApplyCurrentFrame(Action<Sprite> applySprite)
|
||||
{
|
||||
var step = CurrentStep;
|
||||
@@ -283,5 +486,45 @@ namespace AibisDream.FrameAnimation
|
||||
|
||||
applySprite?.Invoke(step.Clip.Frames[frameIndex]?.Sprite);
|
||||
}
|
||||
|
||||
private sealed class SeekIndex
|
||||
{
|
||||
internal SeekStep[] Steps { get; }
|
||||
internal double[] StepEndSeconds { get; }
|
||||
internal double TotalDurationSeconds { get; }
|
||||
|
||||
internal SeekIndex(
|
||||
SeekStep[] steps,
|
||||
double[] stepEndSeconds,
|
||||
double totalDurationSeconds)
|
||||
{
|
||||
Steps = steps;
|
||||
StepEndSeconds = stepEndSeconds;
|
||||
TotalDurationSeconds = totalDurationSeconds;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class SeekStep
|
||||
{
|
||||
internal double StartSeconds { get; }
|
||||
internal double DurationSeconds { get; }
|
||||
internal float PlaybackSpeed { get; }
|
||||
internal FrameClipEndBehavior EndBehavior { get; }
|
||||
internal double[] FrameEndSeconds { get; }
|
||||
|
||||
internal SeekStep(
|
||||
double startSeconds,
|
||||
double durationSeconds,
|
||||
float playbackSpeed,
|
||||
FrameClipEndBehavior endBehavior,
|
||||
double[] frameEndSeconds)
|
||||
{
|
||||
StartSeconds = startSeconds;
|
||||
DurationSeconds = durationSeconds;
|
||||
PlaybackSpeed = playbackSpeed;
|
||||
EndBehavior = endBehavior;
|
||||
FrameEndSeconds = frameEndSeconds;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace AibisDream.FrameAnimation
|
||||
private FrameAnimationPlaybackSession session;
|
||||
private FrameAnimationPlaybackHandle activeHandle;
|
||||
private FrameAnimationPlaybackState state = FrameAnimationPlaybackState.Stopped;
|
||||
private Action<Sprite> applySpriteCallback;
|
||||
private bool _skipInitialPlayOnEnable;
|
||||
private bool hasStartedPlayback;
|
||||
|
||||
@@ -100,7 +101,7 @@ namespace AibisDream.FrameAnimation
|
||||
return;
|
||||
}
|
||||
|
||||
var evaluation = session.Evaluate(Time.deltaTime, speed, ApplySprite);
|
||||
var evaluation = session.Evaluate(Time.deltaTime, speed, ApplySpriteCallback);
|
||||
if (evaluation.IsFailed)
|
||||
{
|
||||
FailActive(evaluation.Error.Code, evaluation.Error.Message);
|
||||
@@ -255,7 +256,7 @@ namespace AibisDream.FrameAnimation
|
||||
session = new FrameAnimationPlaybackSession(plan);
|
||||
activeHandle = handle;
|
||||
state = FrameAnimationPlaybackState.Playing;
|
||||
session.Start(ApplySprite);
|
||||
session.Start(ApplySpriteCallback);
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -332,7 +333,7 @@ namespace AibisDream.FrameAnimation
|
||||
return;
|
||||
}
|
||||
|
||||
var evaluation = session.Evaluate(deltaTimeSeconds, speed, ApplySprite);
|
||||
var evaluation = session.Evaluate(deltaTimeSeconds, speed, ApplySpriteCallback);
|
||||
if (evaluation.IsFailed)
|
||||
{
|
||||
FailActive(evaluation.Error.Code, evaluation.Error.Message);
|
||||
@@ -399,7 +400,7 @@ namespace AibisDream.FrameAnimation
|
||||
state = FrameAnimationPlaybackState.Playing;
|
||||
target = resolvedTarget;
|
||||
target.Enabled = true;
|
||||
session.Start(ApplySprite);
|
||||
session.Start(ApplySpriteCallback);
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -517,12 +518,15 @@ namespace AibisDream.FrameAnimation
|
||||
|
||||
private void ApplySprite(Sprite sprite)
|
||||
{
|
||||
if (target != null && target.IsValid)
|
||||
if (target != null && target.IsValid && target.Sprite != sprite)
|
||||
{
|
||||
target.Sprite = sprite;
|
||||
}
|
||||
}
|
||||
|
||||
private Action<Sprite> ApplySpriteCallback =>
|
||||
applySpriteCallback ??= ApplySprite;
|
||||
|
||||
private bool ShouldWaitForFirstPass(FrameAnimationPlaybackHandle playbackHandle)
|
||||
{
|
||||
if (playbackHandle.IsCompleted || activeHandle != playbackHandle || session == null)
|
||||
@@ -559,12 +563,15 @@ namespace AibisDream.FrameAnimation
|
||||
case FrameClipEndBehavior.Clear:
|
||||
if (target != null && target.IsValid)
|
||||
{
|
||||
target.Enabled = true;
|
||||
target.Sprite = null;
|
||||
if (!target.Enabled)
|
||||
{
|
||||
target.Enabled = true;
|
||||
}
|
||||
ApplySprite(null);
|
||||
}
|
||||
break;
|
||||
case FrameClipEndBehavior.HideTarget:
|
||||
if (target != null && target.IsValid)
|
||||
if (target != null && target.IsValid && target.Enabled)
|
||||
{
|
||||
target.Enabled = false;
|
||||
}
|
||||
@@ -579,11 +586,17 @@ namespace AibisDream.FrameAnimation
|
||||
case FrameAnimationStopMode.HoldCurrentFrame:
|
||||
break;
|
||||
case FrameAnimationStopMode.Clear:
|
||||
target.Enabled = true;
|
||||
target.Sprite = null;
|
||||
if (!target.Enabled)
|
||||
{
|
||||
target.Enabled = true;
|
||||
}
|
||||
ApplySprite(null);
|
||||
break;
|
||||
case FrameAnimationStopMode.HideTarget:
|
||||
target.Enabled = false;
|
||||
if (target.Enabled)
|
||||
{
|
||||
target.Enabled = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace AibisDream.FrameAnimation
|
||||
private FrameAnimationPlaybackSession session;
|
||||
private FrameAnimationPlaybackHandle activeHandle;
|
||||
private FrameAnimationPlaybackState state = FrameAnimationPlaybackState.Stopped;
|
||||
private Action<Sprite> applySpriteCallback;
|
||||
private bool skipInitialPlayOnEnable;
|
||||
private bool timelineControlled;
|
||||
private FrameClip timelineClip;
|
||||
@@ -130,7 +131,7 @@ namespace AibisDream.FrameAnimation
|
||||
session = new FrameAnimationPlaybackSession(plan);
|
||||
activeHandle = handle;
|
||||
state = FrameAnimationPlaybackState.Playing;
|
||||
session.Start(ApplySprite);
|
||||
session.Start(ApplySpriteCallback);
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -251,12 +252,14 @@ namespace AibisDream.FrameAnimation
|
||||
|
||||
timelineClip = value;
|
||||
session = new FrameAnimationPlaybackSession(plan);
|
||||
session.Start(ApplySprite);
|
||||
}
|
||||
|
||||
target.Enabled = true;
|
||||
if (!target.Enabled)
|
||||
{
|
||||
target.Enabled = true;
|
||||
}
|
||||
state = FrameAnimationPlaybackState.Playing;
|
||||
var evaluation = session.Seek(Math.Max(0d, timeSeconds), ApplySprite);
|
||||
var evaluation = session.Seek(Math.Max(0d, timeSeconds), ApplySpriteCallback);
|
||||
if (evaluation.IsFailed)
|
||||
{
|
||||
session = null;
|
||||
@@ -299,6 +302,13 @@ namespace AibisDream.FrameAnimation
|
||||
return SampleTimeline(value, Math.Max(0d, duration - 0.000001d));
|
||||
}
|
||||
|
||||
if (value.DefaultEndBehavior == FrameClipEndBehavior.Clear ||
|
||||
value.DefaultEndBehavior == FrameClipEndBehavior.HideTarget)
|
||||
{
|
||||
ApplyEndBehavior(value.DefaultEndBehavior);
|
||||
return FrameAnimationPlaybackError.None;
|
||||
}
|
||||
|
||||
var sampleError = SampleTimeline(value, GetEffectiveClipDurationSeconds(value));
|
||||
if (sampleError.Code == FrameAnimationPlaybackErrorCode.None)
|
||||
{
|
||||
@@ -310,8 +320,11 @@ namespace AibisDream.FrameAnimation
|
||||
internal void RestoreTimelineBaseline()
|
||||
{
|
||||
if (!timelineControlled || target == null || !target.IsValid) return;
|
||||
target.Sprite = timelineBaselineSprite;
|
||||
target.Enabled = timelineBaselineEnabled;
|
||||
ApplySprite(timelineBaselineSprite);
|
||||
if (target.Enabled != timelineBaselineEnabled)
|
||||
{
|
||||
target.Enabled = timelineBaselineEnabled;
|
||||
}
|
||||
session = null;
|
||||
timelineClip = null;
|
||||
state = FrameAnimationPlaybackState.Stopped;
|
||||
@@ -364,7 +377,7 @@ namespace AibisDream.FrameAnimation
|
||||
return;
|
||||
}
|
||||
|
||||
var evaluation = session.Evaluate(deltaTimeSeconds, speed, ApplySprite);
|
||||
var evaluation = session.Evaluate(deltaTimeSeconds, speed, ApplySpriteCallback);
|
||||
if (evaluation.IsFailed) FailActive(evaluation.Error.Code, evaluation.Error.Message);
|
||||
else if (evaluation.IsCompleted) CompleteNaturally(evaluation.EndBehavior);
|
||||
}
|
||||
@@ -386,7 +399,7 @@ namespace AibisDream.FrameAnimation
|
||||
state = FrameAnimationPlaybackState.Playing;
|
||||
target = resolvedTarget;
|
||||
target.Enabled = true;
|
||||
session.Start(ApplySprite);
|
||||
session.Start(ApplySpriteCallback);
|
||||
return handle;
|
||||
}
|
||||
|
||||
@@ -525,9 +538,15 @@ namespace AibisDream.FrameAnimation
|
||||
|
||||
private void ApplySprite(Sprite sprite)
|
||||
{
|
||||
if (target != null && target.IsValid) target.Sprite = sprite;
|
||||
if (target != null && target.IsValid && target.Sprite != sprite)
|
||||
{
|
||||
target.Sprite = sprite;
|
||||
}
|
||||
}
|
||||
|
||||
private Action<Sprite> ApplySpriteCallback =>
|
||||
applySpriteCallback ??= ApplySprite;
|
||||
|
||||
private bool ShouldWaitForFirstPass(FrameAnimationPlaybackHandle playbackHandle)
|
||||
{
|
||||
return !playbackHandle.IsCompleted && activeHandle == playbackHandle && session != null &&
|
||||
@@ -556,12 +575,18 @@ namespace AibisDream.FrameAnimation
|
||||
case FrameClipEndBehavior.Clear:
|
||||
if (target != null && target.IsValid)
|
||||
{
|
||||
target.Enabled = true;
|
||||
target.Sprite = null;
|
||||
if (!target.Enabled)
|
||||
{
|
||||
target.Enabled = true;
|
||||
}
|
||||
ApplySprite(null);
|
||||
}
|
||||
break;
|
||||
case FrameClipEndBehavior.HideTarget:
|
||||
if (target != null && target.IsValid) target.Enabled = false;
|
||||
if (target != null && target.IsValid && target.Enabled)
|
||||
{
|
||||
target.Enabled = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -571,11 +596,17 @@ namespace AibisDream.FrameAnimation
|
||||
switch (mode)
|
||||
{
|
||||
case FrameAnimationStopMode.Clear:
|
||||
target.Enabled = true;
|
||||
target.Sprite = null;
|
||||
if (!target.Enabled)
|
||||
{
|
||||
target.Enabled = true;
|
||||
}
|
||||
ApplySprite(null);
|
||||
break;
|
||||
case FrameAnimationStopMode.HideTarget:
|
||||
target.Enabled = false;
|
||||
if (target.Enabled)
|
||||
{
|
||||
target.Enabled = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,6 @@ namespace AibisDream.FrameAnimation.Timeline
|
||||
var clipInfo = clips[activeIndex];
|
||||
terminalClip = clipInfo.Asset?.FrameClip;
|
||||
var localTime = playable.GetInput(activeIndex).GetTime();
|
||||
localTime = NormalizeLoopTime(terminalClip, localTime);
|
||||
ReportError(currentPlayer.SampleTimeline(terminalClip, localTime), currentPlayer);
|
||||
return;
|
||||
}
|
||||
@@ -177,21 +176,6 @@ namespace AibisDream.FrameAnimation.Timeline
|
||||
return selected;
|
||||
}
|
||||
|
||||
private static double NormalizeLoopTime(FrameClip clip, double localTime)
|
||||
{
|
||||
if (clip == null || clip.DefaultEndBehavior != FrameClipEndBehavior.Loop)
|
||||
{
|
||||
return Math.Max(0d, localTime);
|
||||
}
|
||||
|
||||
var duration = FrameAnimationTimelineClip.GetEffectiveDuration(clip);
|
||||
if (duration <= 0d)
|
||||
{
|
||||
return 0d;
|
||||
}
|
||||
return Math.Max(0d, localTime) % duration;
|
||||
}
|
||||
|
||||
private void ReleaseCurrentPlayer()
|
||||
{
|
||||
if (currentPlayer != null)
|
||||
|
||||
@@ -128,6 +128,141 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
|
||||
Assert.That(session.CurrentFrameIndex, Is.EqualTo(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PlaybackSession_SeekSamplesVariableDurationsAtExactBoundaries()
|
||||
{
|
||||
var clip = CreateClip(
|
||||
"Variable",
|
||||
FrameClipEndBehavior.HoldLastFrame,
|
||||
1f,
|
||||
100,
|
||||
200,
|
||||
50);
|
||||
Assert.That(
|
||||
FrameAnimationResolver.TryResolveClip(
|
||||
clip,
|
||||
default,
|
||||
out var plan,
|
||||
out var error),
|
||||
Is.True,
|
||||
error.ToString());
|
||||
var session = new FrameAnimationPlaybackSession(plan);
|
||||
|
||||
AssertSeekFrame(session, -1d, 0, false);
|
||||
AssertSeekFrame(session, 0.099d, 0, false);
|
||||
AssertSeekFrame(session, 0.1d, 1, false);
|
||||
AssertSeekFrame(session, 0.299d, 1, false);
|
||||
AssertSeekFrame(session, 0.3d, 2, false);
|
||||
AssertSeekFrame(session, 0.35d, 2, true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PlaybackSession_SeekSupportsBackwardMovementAndMultipleStepSpeeds()
|
||||
{
|
||||
var intro = CreateClip(
|
||||
"Intro",
|
||||
FrameClipEndBehavior.HoldLastFrame,
|
||||
1f,
|
||||
100,
|
||||
100);
|
||||
var idle = CreateClip(
|
||||
"Idle",
|
||||
FrameClipEndBehavior.HoldLastFrame,
|
||||
1f,
|
||||
100,
|
||||
100);
|
||||
var plan = new ResolvedPlaybackPlan(
|
||||
"Flow",
|
||||
true,
|
||||
new[]
|
||||
{
|
||||
new ResolvedPlaybackStep(
|
||||
intro,
|
||||
"intro-node",
|
||||
2f,
|
||||
FrameClipEndBehavior.HoldLastFrame),
|
||||
new ResolvedPlaybackStep(
|
||||
idle,
|
||||
"idle-node",
|
||||
0.5f,
|
||||
FrameClipEndBehavior.Loop)
|
||||
});
|
||||
var session = new FrameAnimationPlaybackSession(plan);
|
||||
|
||||
AssertSeekFrame(session, 0.31d, 1, false);
|
||||
Assert.That(session.CurrentClipId, Is.EqualTo(idle.Id));
|
||||
Assert.That(session.CurrentNodeId, Is.EqualTo("idle-node"));
|
||||
|
||||
AssertSeekFrame(session, 0.5d, 0, false);
|
||||
Assert.That(session.HasCompletedFirstTerminalLoopCycle, Is.True);
|
||||
|
||||
AssertSeekFrame(session, 0.05d, 1, false);
|
||||
Assert.That(session.CurrentClipId, Is.EqualTo(intro.Id));
|
||||
Assert.That(session.CurrentNodeId, Is.EqualTo("intro-node"));
|
||||
Assert.That(session.HasCompletedFirstTerminalLoopCycle, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PlaybackSession_SeekHandlesLoopCyclesAndZeroSpeed()
|
||||
{
|
||||
var loop = CreateClip("Loop", FrameClipEndBehavior.Loop, 1f, 100, 200);
|
||||
Assert.That(
|
||||
FrameAnimationResolver.TryResolveClip(
|
||||
loop,
|
||||
default,
|
||||
out var loopPlan,
|
||||
out var loopError),
|
||||
Is.True,
|
||||
loopError.ToString());
|
||||
var loopSession = new FrameAnimationPlaybackSession(loopPlan);
|
||||
|
||||
AssertSeekFrame(loopSession, 0.299d, 1, false);
|
||||
Assert.That(loopSession.HasCompletedFirstTerminalLoopCycle, Is.False);
|
||||
AssertSeekFrame(loopSession, 0.3d, 0, false);
|
||||
Assert.That(loopSession.HasCompletedFirstTerminalLoopCycle, Is.True);
|
||||
AssertSeekFrame(loopSession, 0.4d, 1, false);
|
||||
|
||||
var stopped = CreateClip("Stopped", FrameClipEndBehavior.Loop, 0f, 100, 100);
|
||||
Assert.That(
|
||||
FrameAnimationResolver.TryResolveClip(
|
||||
stopped,
|
||||
default,
|
||||
out var stoppedPlan,
|
||||
out var stoppedError),
|
||||
Is.True,
|
||||
stoppedError.ToString());
|
||||
var stoppedSession = new FrameAnimationPlaybackSession(stoppedPlan);
|
||||
|
||||
AssertSeekFrame(stoppedSession, 100d, 0, false);
|
||||
Assert.That(stoppedSession.HasCompletedFirstTerminalLoopCycle, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PlaybackSession_SeekLongClipAppliesOnlyResolvedFrame()
|
||||
{
|
||||
var clip = CreateClip(
|
||||
"Long",
|
||||
FrameClipEndBehavior.HoldLastFrame,
|
||||
1f,
|
||||
Enumerable.Repeat(10, 1000).ToArray());
|
||||
Assert.That(
|
||||
FrameAnimationResolver.TryResolveClip(
|
||||
clip,
|
||||
default,
|
||||
out var plan,
|
||||
out var error),
|
||||
Is.True,
|
||||
error.ToString());
|
||||
var session = new FrameAnimationPlaybackSession(plan);
|
||||
var applyCount = 0;
|
||||
|
||||
var evaluation = session.Seek(9.999d, _ => applyCount++);
|
||||
|
||||
Assert.That(evaluation.IsCompleted, Is.False);
|
||||
Assert.That(session.CurrentFrameIndex, Is.EqualTo(999));
|
||||
Assert.That(applyCount, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EndBehavior_NodeOverrideHasHighestPrecedence()
|
||||
{
|
||||
@@ -180,6 +315,22 @@ namespace AibisDream.FrameAnimation.Tests.EditMode
|
||||
Assert.That(handle.Result.RequestId, Is.EqualTo(42));
|
||||
}
|
||||
|
||||
private static void AssertSeekFrame(
|
||||
FrameAnimationPlaybackSession session,
|
||||
double seconds,
|
||||
int expectedFrameIndex,
|
||||
bool expectedCompleted)
|
||||
{
|
||||
var applyCount = 0;
|
||||
var evaluation = session.Seek(seconds, _ => applyCount++);
|
||||
var snapshot = session.Snapshot;
|
||||
|
||||
Assert.That(evaluation.IsCompleted, Is.EqualTo(expectedCompleted));
|
||||
Assert.That(snapshot.FrameIndex, Is.EqualTo(expectedFrameIndex));
|
||||
Assert.That(snapshot.IsCompleted, Is.EqualTo(expectedCompleted));
|
||||
Assert.That(applyCount, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
private FrameClip CreateClip(
|
||||
string id,
|
||||
FrameClipEndBehavior endBehavior,
|
||||
|
||||
@@ -59,6 +59,97 @@ namespace AibisDream.FrameAnimation.Tests.PlayMode
|
||||
Assert.That(renderer.sprite, Is.SameAs(first));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator Director_RespectsClipInSpeedMultiplierAndBackwardSeek()
|
||||
{
|
||||
var first = CreateSprite(Color.red);
|
||||
var second = CreateSprite(Color.green);
|
||||
var third = CreateSprite(Color.blue);
|
||||
var clip = CreateClip(first, second, third);
|
||||
var playerObject = Track(new GameObject("Timeline Time Mapping"));
|
||||
var renderer = playerObject.AddComponent<SpriteRenderer>();
|
||||
var player = playerObject.AddComponent<FrameClipPlayer>();
|
||||
var setup = CreateTimeline(player, clip);
|
||||
setup.Clip.clipIn = 0.1d;
|
||||
setup.Clip.timeScale = 2d;
|
||||
|
||||
setup.Director.Play();
|
||||
setup.Director.time = 0.025d;
|
||||
setup.Director.Evaluate();
|
||||
yield return null;
|
||||
|
||||
Assert.That(renderer.sprite, Is.SameAs(second));
|
||||
|
||||
setup.Director.time = 0.075d;
|
||||
setup.Director.Evaluate();
|
||||
Assert.That(renderer.sprite, Is.SameAs(third));
|
||||
|
||||
setup.Director.time = 0d;
|
||||
setup.Director.Evaluate();
|
||||
Assert.That(renderer.sprite, Is.SameAs(second));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator Director_ExtendedLoopClipWrapsAtSourceDuration()
|
||||
{
|
||||
var first = CreateSprite(Color.yellow);
|
||||
var second = CreateSprite(Color.cyan);
|
||||
var clip = CreateClip(FrameClipEndBehavior.Loop, first, second);
|
||||
var playerObject = Track(new GameObject("Timeline Loop"));
|
||||
var renderer = playerObject.AddComponent<SpriteRenderer>();
|
||||
var player = playerObject.AddComponent<FrameClipPlayer>();
|
||||
var setup = CreateTimeline(player, clip);
|
||||
setup.Clip.duration = 0.6d;
|
||||
|
||||
setup.Director.Play();
|
||||
setup.Director.time = 0.25d;
|
||||
setup.Director.Evaluate();
|
||||
yield return null;
|
||||
|
||||
Assert.That(renderer.sprite, Is.SameAs(first));
|
||||
|
||||
setup.Director.time = 0.35d;
|
||||
setup.Director.Evaluate();
|
||||
Assert.That(renderer.sprite, Is.SameAs(second));
|
||||
}
|
||||
|
||||
[UnityTest]
|
||||
public IEnumerator Director_AppliesClearAndHideTerminalBehaviors()
|
||||
{
|
||||
var clearObject = Track(new GameObject("Timeline Clear"));
|
||||
var clearRenderer = clearObject.AddComponent<SpriteRenderer>();
|
||||
var clearPlayer = clearObject.AddComponent<FrameClipPlayer>();
|
||||
var clearSetup = CreateTimeline(
|
||||
clearPlayer,
|
||||
CreateClip(
|
||||
FrameClipEndBehavior.Clear,
|
||||
CreateSprite(Color.magenta)));
|
||||
|
||||
clearSetup.Director.Play();
|
||||
clearSetup.Director.time = clearSetup.Clip.duration;
|
||||
clearSetup.Director.Evaluate();
|
||||
yield return null;
|
||||
|
||||
Assert.That(clearRenderer.enabled, Is.True);
|
||||
Assert.That(clearRenderer.sprite, Is.Null);
|
||||
|
||||
var hideObject = Track(new GameObject("Timeline Hide"));
|
||||
var hideRenderer = hideObject.AddComponent<SpriteRenderer>();
|
||||
var hidePlayer = hideObject.AddComponent<FrameClipPlayer>();
|
||||
var hideSetup = CreateTimeline(
|
||||
hidePlayer,
|
||||
CreateClip(
|
||||
FrameClipEndBehavior.HideTarget,
|
||||
CreateSprite(Color.white)));
|
||||
|
||||
hideSetup.Director.Play();
|
||||
hideSetup.Director.time = hideSetup.Clip.duration;
|
||||
hideSetup.Director.Evaluate();
|
||||
yield return null;
|
||||
|
||||
Assert.That(hideRenderer.enabled, Is.False);
|
||||
}
|
||||
|
||||
private TimelineSetup CreateTimeline(FrameClipPlayer player, FrameClip clip)
|
||||
{
|
||||
var timeline = Track(ScriptableObject.CreateInstance<TimelineAsset>());
|
||||
@@ -72,10 +163,17 @@ namespace AibisDream.FrameAnimation.Tests.PlayMode
|
||||
var director = directorObject.AddComponent<PlayableDirector>();
|
||||
director.playableAsset = timeline;
|
||||
director.SetGenericBinding(track, player);
|
||||
return new TimelineSetup(director);
|
||||
return new TimelineSetup(director, timelineClip);
|
||||
}
|
||||
|
||||
private FrameClip CreateClip(params Sprite[] sprites)
|
||||
{
|
||||
return CreateClip(FrameClipEndBehavior.HoldLastFrame, sprites);
|
||||
}
|
||||
|
||||
private FrameClip CreateClip(
|
||||
FrameClipEndBehavior endBehavior,
|
||||
params Sprite[] sprites)
|
||||
{
|
||||
var clip = Track(ScriptableObject.CreateInstance<FrameClip>());
|
||||
var frames = new List<FrameAnimationFrame>();
|
||||
@@ -93,7 +191,7 @@ namespace AibisDream.FrameAnimation.Tests.PlayMode
|
||||
"Timeline",
|
||||
frames,
|
||||
1f,
|
||||
FrameClipEndBehavior.HoldLastFrame);
|
||||
endBehavior);
|
||||
return clip;
|
||||
}
|
||||
|
||||
@@ -116,12 +214,14 @@ namespace AibisDream.FrameAnimation.Tests.PlayMode
|
||||
|
||||
private readonly struct TimelineSetup
|
||||
{
|
||||
internal TimelineSetup(PlayableDirector director)
|
||||
internal TimelineSetup(PlayableDirector director, TimelineClip clip)
|
||||
{
|
||||
Director = director;
|
||||
Clip = clip;
|
||||
}
|
||||
|
||||
internal PlayableDirector Director { get; }
|
||||
internal TimelineClip Clip { get; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user