hzengine-core 0.1.2-dev → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,440 +1,430 @@
1
- /**
2
- * animation.js
3
- * @description A library for providing multi-track animations for HZEngine. 一个用于在HZEngine中提供简单动画的库
4
- * @date 2024/10/2
5
- * @author CuberQAQ
6
- */
7
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
- };
12
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
13
- if (kind === "m") throw new TypeError("Private method is not writable");
14
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
15
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
16
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
17
- };
18
- var _ActiveTrackNode_currentSection, _ActiveTrackNode_currentIndex, _ActiveTrackNode_currentTrack;
19
- export class Animation {
20
- constructor(profile, options) {
21
- this.initProps = {};
22
- this.activeRootTrack = null;
23
- this.lastTime = 0;
24
- this.onFrame = null;
25
- this.onEnd = null;
26
- this.customWrappers = {};
27
- this.onStop = null;
28
- this.normalizedProfile = Profile.normalize(profile);
29
- console.log(`Animation: ${JSON.stringify(profile)}`);
30
- if (options) {
31
- options.initProps && (this.initProps = options.initProps);
32
- options.wrappers && (this.customWrappers = options.wrappers);
33
- }
34
- }
35
- serialize() {
36
- var _a;
37
- return {
38
- normalizedProfile: this.normalizedProfile,
39
- initProps: this.initProps,
40
- activeRootTrack: (_a = this.activeRootTrack) === null || _a === void 0 ? void 0 : _a.serialize(),
41
- lastTime: this.lastTime,
42
- };
43
- }
44
- static unserialize(serialized, wrappers) {
45
- let profile = serialized.normalizedProfile;
46
- let animation = new Animation(profile, {
47
- initProps: serialized.initProps,
48
- wrappers,
49
- });
50
- animation.lastTime = serialized.lastTime;
51
- serialized.activeRootTrack &&
52
- (animation.activeRootTrack = ActiveTrackNode.unserialize(animation, serialized.activeRootTrack));
53
- return animation;
54
- }
55
- timerCb() { }
56
- init() {
57
- this.activeRootTrack = new ActiveTrackNode(this, {
58
- accessKeys: [],
59
- index: 0,
60
- initProps: this.initProps,
61
- });
62
- }
63
- goto(time) {
64
- if (!this.activeRootTrack) {
65
- this.init();
66
- }
67
- if (time < 0)
68
- time = 0;
69
- if (time < this.lastTime) {
70
- this.init(); // reset the tracknode
71
- try {
72
- this.activeRootTrack.step(time);
73
- }
74
- catch (e) {
75
- console.log(e);
76
- this.activeRootTrack.status = ActiveTrackNode.Status.Pause;
77
- }
78
- if (this.activeRootTrack.status === ActiveTrackNode.Status.Pause) {
79
- if (this.onEnd)
80
- this.onEnd();
81
- }
82
- }
83
- else {
84
- if (this.activeRootTrack.status !== ActiveTrackNode.Status.Pause) {
85
- try {
86
- this.activeRootTrack.step(time - this.lastTime);
87
- }
88
- catch (e) {
89
- console.log(e);
90
- this.activeRootTrack.status = ActiveTrackNode.Status.Pause;
91
- }
92
- }
93
- }
94
- this.lastTime = time;
95
- if (this.onFrame) {
96
- // console.log("on frame", JSON.stringify(this.calcProps()));
97
- this.onFrame(this.calcProps());
98
- }
99
- if (this.activeRootTrack.status === ActiveTrackNode.Status.Pause) {
100
- if (this.onEnd)
101
- this.onEnd();
102
- }
103
- }
104
- step(delta_time) {
105
- this.goto(this.lastTime + delta_time);
106
- }
107
- calcProps() {
108
- return this.activeRootTrack.calcProps();
109
- }
110
- reverse() { }
111
- stop() { }
112
- _accessProfile(accessKeys) {
113
- let section = this.normalizedProfile;
114
- for (let i = 0; i < accessKeys.length; i++) {
115
- section = section[accessKeys[i]];
116
- }
117
- return section;
118
- }
119
- _getWrapper(wrapper) {
120
- var _a, _b;
121
- if (typeof wrapper === "string") {
122
- return ((_b = (_a = this.customWrappers[wrapper]) !== null && _a !== void 0 ? _a : buildInWrappers[wrapper]) !== null && _b !== void 0 ? _b : buildInWrappers.none);
123
- }
124
- else if (wrapper === undefined) {
125
- return buildInWrappers.none;
126
- }
127
- else
128
- return wrapper;
129
- }
130
- _calcWrappedProps(former_props, props, wrapper, progress) {
131
- let _former_props = Object.assign({}, former_props);
132
- let wrapper_func = this._getWrapper(wrapper);
133
- let wraped_prog = wrapper_func(progress);
134
- let res = Object.assign({}, _former_props);
135
- for (let key in props) {
136
- if (typeof props[key] === "number") {
137
- if (_former_props[key] == undefined)
138
- _former_props[key] = 0;
139
- res[key] =
140
- _former_props[key] + wraped_prog * (props[key] - _former_props[key]);
141
- }
142
- else if (typeof props[key] === "boolean") {
143
- if (_former_props[key] == undefined)
144
- _former_props[key] = false;
145
- res[key] = wraped_prog === 1 ? props[key] : _former_props[key];
146
- }
147
- else if (typeof props[key] === "string") {
148
- if (_former_props[key] == undefined)
149
- _former_props[key] = "";
150
- res[key] = wraped_prog === 1 ? props[key] : _former_props[key];
151
- }
152
- else {
153
- res[key] = props[key];
154
- }
155
- }
156
- return res;
157
- }
158
- }
159
- export var Profile;
160
- (function (Profile) {
161
- function normalize(profile) {
162
- if (!Array.isArray(profile)) {
163
- // section
164
- return [profile];
165
- }
166
- else if (profile.length === 0) {
167
- // empty track/tracklist
168
- return [];
169
- }
170
- else if (!Array.isArray(profile[0])) {
171
- // track
172
- return profile;
173
- }
174
- else {
175
- // tracklist
176
- return [
177
- {
178
- syncs: profile,
179
- },
180
- ];
181
- }
182
- }
183
- Profile.normalize = normalize;
184
- })(Profile || (Profile = {}));
185
- export class ActiveTrackNode {
186
- get currentSection() {
187
- if (__classPrivateFieldGet(this, _ActiveTrackNode_currentSection, "f") === null) {
188
- if (this.currentIndex === null) {
189
- __classPrivateFieldSet(this, _ActiveTrackNode_currentSection, this.animation._accessProfile(this.accessKeys), "f");
190
- }
191
- else {
192
- __classPrivateFieldSet(this, _ActiveTrackNode_currentSection, this.currentTrack[this.currentIndex], "f");
193
- }
194
- __classPrivateFieldSet(this, _ActiveTrackNode_currentIndex, this.currentIndex, "f");
195
- }
196
- else if (this.currentIndex !== __classPrivateFieldGet(this, _ActiveTrackNode_currentIndex, "f")) {
197
- __classPrivateFieldSet(this, _ActiveTrackNode_currentSection, this.currentTrack[this.currentIndex], "f");
198
- __classPrivateFieldSet(this, _ActiveTrackNode_currentIndex, this.currentIndex, "f");
199
- }
200
- return __classPrivateFieldGet(this, _ActiveTrackNode_currentSection, "f");
201
- }
202
- get currentTrack() {
203
- if (__classPrivateFieldGet(this, _ActiveTrackNode_currentTrack, "f") === null && this.currentIndex !== null) {
204
- __classPrivateFieldSet(this, _ActiveTrackNode_currentTrack, this.animation._accessProfile(this.accessKeys), "f");
205
- }
206
- return __classPrivateFieldGet(this, _ActiveTrackNode_currentTrack, "f");
207
- }
208
- constructor(animation, { accessKeys, index, initProps, }) {
209
- this.animation = animation;
210
- this.repeated = 0;
211
- this.status = ActiveTrackNode.Status.Playing;
212
- this.now_time = 0;
213
- _ActiveTrackNode_currentSection.set(this, null);
214
- _ActiveTrackNode_currentIndex.set(this, null);
215
- _ActiveTrackNode_currentTrack.set(this, null);
216
- this.lastProps = {};
217
- this.nowProps = {};
218
- this.activeSyncs = [];
219
- this.accessKeys = accessKeys;
220
- this.currentIndex = index;
221
- this.lastProps = Object.assign({}, initProps);
222
- this.nowProps = Object.assign({}, initProps);
223
- }
224
- serialize() {
225
- return {
226
- accessKeys: this.accessKeys,
227
- currentIndex: this.currentIndex,
228
- repeated: this.repeated,
229
- status: this.status,
230
- now_time: this.now_time,
231
- lastProps: this.lastProps,
232
- nowProps: this.nowProps,
233
- activeSyncs: this.activeSyncs.map((sync) => sync.serialize()),
234
- };
235
- }
236
- static unserialize(animation, serialized) {
237
- let node = new ActiveTrackNode(animation, {
238
- accessKeys: serialized.accessKeys,
239
- index: serialized.currentIndex,
240
- initProps: serialized.lastProps,
241
- });
242
- node.lastProps = serialized.lastProps;
243
- node.nowProps = serialized.nowProps;
244
- node.status = serialized.status;
245
- node.repeated = serialized.repeated;
246
- node.now_time = serialized.now_time;
247
- node.activeSyncs = serialized.activeSyncs.map((sync) => ActiveTrackNode.unserialize(animation, sync));
248
- return node;
249
- }
250
- /**
251
- *
252
- * @param delta_time
253
- * @returns 剩餘的時間
254
- */
255
- step(delta_time) {
256
- // console.log(`node step: ${delta_time}`);
257
- var _a;
258
- // if (this.status === ActiveTrackNode.Status.Pause) return delta_time;
259
- // because we should proceed async list
260
- // normal
261
- if (!this.currentSection) {
262
- this.status = ActiveTrackNode.Status.Pause;
263
- return delta_time;
264
- }
265
- while (true) {
266
- // constant field: time, wrapper, frame
267
- // instant filed: syncs, asyncs
268
- if (this.status === ActiveTrackNode.Status.Playing) {
269
- if (this.currentSection.time === undefined ||
270
- this.currentSection.time <= 0) {
271
- this.nowProps = Object.assign(Object.assign({}, this.nowProps), this.currentSection.frame);
272
- }
273
- else {
274
- if (this.now_time + delta_time >= this.currentSection.time) {
275
- // this.now_time = this.currentSection.time
276
- delta_time -= this.currentSection.time - this.now_time;
277
- this.nowProps = Object.assign(Object.assign({}, this.nowProps), this.currentSection.frame);
278
- }
279
- else {
280
- this.now_time += delta_time;
281
- delta_time = 0;
282
- // calc
283
- let progress = this.now_time / this.currentSection.time;
284
- // console.log(`progress: ${progress}`);
285
- this.nowProps = this.animation._calcWrappedProps(this.lastProps, (_a = this.currentSection.frame) !== null && _a !== void 0 ? _a : {}, this.currentSection.wrapper, progress);
286
- break;
287
- }
288
- }
289
- // sync async
290
- if (this.currentSection.syncs && this.currentSection.syncs.length > 0) {
291
- this.initSyncs();
292
- this.status = ActiveTrackNode.Status.WaitingSyncs;
293
- }
294
- }
295
- // step and check sync
296
- if (this.status === ActiveTrackNode.Status.WaitingSyncs) {
297
- delta_time = this.stepSyncs(delta_time); // returns lefted time
298
- this.nowProps = Object.assign(this.nowProps, this.getSyncsProps());
299
- if (this.checkSyncsFinished()) {
300
- this.status = ActiveTrackNode.Status.Playing;
301
- this.activeSyncs = [];
302
- }
303
- else {
304
- // debug
305
- if (delta_time !== 0)
306
- throw "syncs not finished while lefted time != 0. may be bugs";
307
- break;
308
- }
309
- }
310
- // check repeat , finish
311
- if (this.currentSection.repeat !== undefined) {
312
- this.repeated++;
313
- if (this.repeated >= this.currentSection.repeat) {
314
- // finish and proceed next section
315
- // TODO
316
- if (this._switchNextSection())
317
- continue;
318
- else
319
- break;
320
- }
321
- else {
322
- // continue this section
323
- this.now_time = 0;
324
- this.nowProps = Object.assign({}, this.lastProps);
325
- continue;
326
- }
327
- }
328
- else {
329
- if (this._switchNextSection())
330
- continue;
331
- else
332
- break;
333
- }
334
- }
335
- // waiting syncs
336
- return delta_time;
337
- }
338
- calcProps() {
339
- return this.nowProps;
340
- }
341
- _switchNextSection() {
342
- if (this.currentIndex === null ||
343
- this.currentTrack.length === this.currentIndex + 1) {
344
- // already reach the end
345
- this.status = ActiveTrackNode.Status.Pause;
346
- return false;
347
- }
348
- else {
349
- this.lastProps = Object.assign({}, this.nowProps);
350
- this.repeated = 0;
351
- this.now_time = 0;
352
- this.currentIndex++;
353
- return true;
354
- }
355
- }
356
- initSyncs() {
357
- // console.log("init syncs");
358
- let activeSyncs = [];
359
- // if (this.currentSection.syncs == null) return;
360
- let subprofile = this.currentSection.syncs;
361
- let activeTrackNode;
362
- if (Array.isArray(subprofile)) {
363
- if (subprofile.length > 0 && Array.isArray(subprofile[0])) {
364
- // tracklist
365
- for (let j = 0; j < subprofile.length; ++j) {
366
- activeTrackNode = new ActiveTrackNode(this.animation, {
367
- accessKeys: [
368
- ...this.accessKeys,
369
- "" + this.currentIndex,
370
- "syncs",
371
- "" + j,
372
- ],
373
- index: 0,
374
- initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
375
- });
376
- activeSyncs.push(activeTrackNode);
377
- }
378
- }
379
- else {
380
- // Track
381
- activeTrackNode = new ActiveTrackNode(this.animation, {
382
- accessKeys: [...this.accessKeys, "" + this.currentIndex, "syncs"],
383
- index: 0,
384
- initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
385
- });
386
- activeSyncs.push(activeTrackNode);
387
- console
388
- .log();
389
- }
390
- }
391
- else {
392
- // section
393
- activeTrackNode = new ActiveTrackNode(this.animation, {
394
- accessKeys: [...this.accessKeys, "" + this.currentIndex, "syncs"],
395
- index: null,
396
- initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
397
- });
398
- activeSyncs.push(activeTrackNode);
399
- }
400
- // activeTrackNode?.step(0); // TODO
401
- this.activeSyncs = activeSyncs;
402
- }
403
- stepSyncs(delta_time) {
404
- let lefted_time = delta_time;
405
- for (let i = 0; i < this.activeSyncs.length; ++i) {
406
- lefted_time = Math.min(this.activeSyncs[i].step(delta_time), lefted_time);
407
- }
408
- return lefted_time;
409
- }
410
- checkSyncsFinished() {
411
- for (let i = 0; i < this.activeSyncs.length; ++i) {
412
- if (this.activeSyncs[i].status !== ActiveTrackNode.Status.Pause)
413
- return false;
414
- }
415
- return true;
416
- }
417
- getSyncsProps() {
418
- let res = {};
419
- for (let i = 0; i < this.activeSyncs.length; ++i) {
420
- Object.assign(res, this.activeSyncs[i].calcProps());
421
- }
422
- return res;
423
- }
424
- }
425
- _ActiveTrackNode_currentSection = new WeakMap(), _ActiveTrackNode_currentIndex = new WeakMap(), _ActiveTrackNode_currentTrack = new WeakMap();
426
- (function (ActiveTrackNode) {
427
- let Status;
428
- (function (Status) {
429
- Status[Status["Playing"] = 0] = "Playing";
430
- Status[Status["WaitingSyncs"] = 1] = "WaitingSyncs";
431
- Status[Status["Pause"] = 2] = "Pause";
432
- })(Status = ActiveTrackNode.Status || (ActiveTrackNode.Status = {}));
433
- })(ActiveTrackNode || (ActiveTrackNode = {}));
434
- const buildInWrappers = {
435
- none: (x) => (x < 1 ? 0 : 1),
436
- linear: (x) => x,
437
- easeout: (x) => Math.pow(x, 3),
438
- easein: (x) => 1 - Math.pow(1 - x, 3),
439
- easeinout: (x) => x < 0.5 ? 0.5 * Math.pow(x, 3) : 1 - 0.5 * Math.pow(1 - x, 3),
440
- };
1
+ /**
2
+ * animation.js
3
+ * @description A library for providing multi-track animations for HZEngine. 一个用于在HZEngine中提供简单动画的库
4
+ * @date 2024/10/2
5
+ * @author CuberQAQ
6
+ */
7
+ export class Animation {
8
+ normalizedProfile;
9
+ initProps = {};
10
+ activeRootTrack = null;
11
+ lastTime = 0;
12
+ onFrame = null;
13
+ onEnd = null;
14
+ customWrappers = {};
15
+ constructor(profile, options) {
16
+ this.normalizedProfile = Profile.normalize(profile);
17
+ console.log(`Animation: ${JSON.stringify(profile)}`);
18
+ if (options) {
19
+ options.initProps && (this.initProps = options.initProps);
20
+ options.wrappers && (this.customWrappers = options.wrappers);
21
+ }
22
+ }
23
+ onStop = null;
24
+ serialize() {
25
+ return {
26
+ normalizedProfile: this.normalizedProfile,
27
+ initProps: this.initProps,
28
+ activeRootTrack: this.activeRootTrack?.serialize(),
29
+ lastTime: this.lastTime,
30
+ };
31
+ }
32
+ static unserialize(serialized, wrappers) {
33
+ let profile = serialized.normalizedProfile;
34
+ let animation = new Animation(profile, {
35
+ initProps: serialized.initProps,
36
+ wrappers,
37
+ });
38
+ animation.lastTime = serialized.lastTime;
39
+ serialized.activeRootTrack &&
40
+ (animation.activeRootTrack = ActiveTrackNode.unserialize(animation, serialized.activeRootTrack));
41
+ return animation;
42
+ }
43
+ timerCb() { }
44
+ init() {
45
+ this.activeRootTrack = new ActiveTrackNode(this, {
46
+ accessKeys: [],
47
+ index: 0,
48
+ initProps: this.initProps,
49
+ });
50
+ }
51
+ goto(time) {
52
+ if (!this.activeRootTrack) {
53
+ this.init();
54
+ }
55
+ if (time < 0)
56
+ time = 0;
57
+ if (time < this.lastTime) {
58
+ this.init(); // reset the tracknode
59
+ try {
60
+ this.activeRootTrack.step(time);
61
+ }
62
+ catch (e) {
63
+ console.log(e);
64
+ this.activeRootTrack.status = ActiveTrackNode.Status.Pause;
65
+ }
66
+ if (this.activeRootTrack.status === ActiveTrackNode.Status.Pause) {
67
+ if (this.onEnd)
68
+ this.onEnd();
69
+ }
70
+ }
71
+ else {
72
+ if (this.activeRootTrack.status !== ActiveTrackNode.Status.Pause) {
73
+ try {
74
+ this.activeRootTrack.step(time - this.lastTime);
75
+ }
76
+ catch (e) {
77
+ console.log(e);
78
+ this.activeRootTrack.status = ActiveTrackNode.Status.Pause;
79
+ }
80
+ }
81
+ }
82
+ this.lastTime = time;
83
+ if (this.onFrame) {
84
+ // console.log("on frame", JSON.stringify(this.calcProps()));
85
+ this.onFrame(this.calcProps());
86
+ }
87
+ if (this.activeRootTrack.status === ActiveTrackNode.Status.Pause) {
88
+ if (this.onEnd)
89
+ this.onEnd();
90
+ }
91
+ }
92
+ step(delta_time) {
93
+ this.goto(this.lastTime + delta_time);
94
+ }
95
+ calcProps() {
96
+ return this.activeRootTrack.calcProps();
97
+ }
98
+ reverse() { }
99
+ stop() { }
100
+ _accessProfile(accessKeys) {
101
+ let section = this.normalizedProfile;
102
+ for (let i = 0; i < accessKeys.length; i++) {
103
+ section = section[accessKeys[i]];
104
+ }
105
+ return section;
106
+ }
107
+ _getWrapper(wrapper) {
108
+ if (typeof wrapper === "string") {
109
+ return (this.customWrappers[wrapper] ??
110
+ buildInWrappers[wrapper] ??
111
+ buildInWrappers.none);
112
+ }
113
+ else if (wrapper === undefined) {
114
+ return buildInWrappers.none;
115
+ }
116
+ else
117
+ return wrapper;
118
+ }
119
+ _calcWrappedProps(former_props, props, wrapper, progress) {
120
+ let _former_props = { ...former_props };
121
+ let wrapper_func = this._getWrapper(wrapper);
122
+ let wraped_prog = wrapper_func(progress);
123
+ let res = { ..._former_props };
124
+ for (let key in props) {
125
+ if (typeof props[key] === "number") {
126
+ if (_former_props[key] == undefined)
127
+ _former_props[key] = 0;
128
+ res[key] =
129
+ _former_props[key] + wraped_prog * (props[key] - _former_props[key]);
130
+ }
131
+ else if (typeof props[key] === "boolean") {
132
+ if (_former_props[key] == undefined)
133
+ _former_props[key] = false;
134
+ res[key] = wraped_prog === 1 ? props[key] : _former_props[key];
135
+ }
136
+ else if (typeof props[key] === "string") {
137
+ if (_former_props[key] == undefined)
138
+ _former_props[key] = "";
139
+ res[key] = wraped_prog === 1 ? props[key] : _former_props[key];
140
+ }
141
+ else {
142
+ res[key] = props[key];
143
+ }
144
+ }
145
+ return res;
146
+ }
147
+ }
148
+ export var Profile;
149
+ (function (Profile) {
150
+ function normalize(profile) {
151
+ if (!Array.isArray(profile)) {
152
+ // section
153
+ return [profile];
154
+ }
155
+ else if (profile.length === 0) {
156
+ // empty track/tracklist
157
+ return [];
158
+ }
159
+ else if (!Array.isArray(profile[0])) {
160
+ // track
161
+ return profile;
162
+ }
163
+ else {
164
+ // tracklist
165
+ return [
166
+ {
167
+ syncs: profile,
168
+ },
169
+ ];
170
+ }
171
+ }
172
+ Profile.normalize = normalize;
173
+ })(Profile || (Profile = {}));
174
+ export class ActiveTrackNode {
175
+ animation;
176
+ accessKeys;
177
+ currentIndex;
178
+ repeated = 0;
179
+ status = ActiveTrackNode.Status.Playing;
180
+ now_time = 0;
181
+ #currentSection = null;
182
+ #currentIndex = null;
183
+ get currentSection() {
184
+ if (this.#currentSection === null) {
185
+ if (this.currentIndex === null) {
186
+ this.#currentSection = this.animation._accessProfile(this.accessKeys);
187
+ }
188
+ else {
189
+ this.#currentSection = this.currentTrack[this.currentIndex];
190
+ }
191
+ this.#currentIndex = this.currentIndex;
192
+ }
193
+ else if (this.currentIndex !== this.#currentIndex) {
194
+ this.#currentSection = this.currentTrack[this.currentIndex];
195
+ this.#currentIndex = this.currentIndex;
196
+ }
197
+ return this.#currentSection;
198
+ }
199
+ #currentTrack = null;
200
+ get currentTrack() {
201
+ if (this.#currentTrack === null && this.currentIndex !== null) {
202
+ this.#currentTrack = this.animation._accessProfile(this.accessKeys);
203
+ }
204
+ return this.#currentTrack;
205
+ }
206
+ lastProps = {};
207
+ nowProps = {};
208
+ constructor(animation, { accessKeys, index, initProps, }) {
209
+ this.animation = animation;
210
+ this.accessKeys = accessKeys;
211
+ this.currentIndex = index;
212
+ this.lastProps = { ...initProps };
213
+ this.nowProps = { ...initProps };
214
+ }
215
+ serialize() {
216
+ return {
217
+ accessKeys: this.accessKeys,
218
+ currentIndex: this.currentIndex,
219
+ repeated: this.repeated,
220
+ status: this.status,
221
+ now_time: this.now_time,
222
+ lastProps: this.lastProps,
223
+ nowProps: this.nowProps,
224
+ activeSyncs: this.activeSyncs.map((sync) => sync.serialize()),
225
+ };
226
+ }
227
+ static unserialize(animation, serialized) {
228
+ let node = new ActiveTrackNode(animation, {
229
+ accessKeys: serialized.accessKeys,
230
+ index: serialized.currentIndex,
231
+ initProps: serialized.lastProps,
232
+ });
233
+ node.lastProps = serialized.lastProps;
234
+ node.nowProps = serialized.nowProps;
235
+ node.status = serialized.status;
236
+ node.repeated = serialized.repeated;
237
+ node.now_time = serialized.now_time;
238
+ node.activeSyncs = serialized.activeSyncs.map((sync) => ActiveTrackNode.unserialize(animation, sync));
239
+ return node;
240
+ }
241
+ /**
242
+ *
243
+ * @param delta_time
244
+ * @returns 剩餘的時間
245
+ */
246
+ step(delta_time) {
247
+ // console.log(`node step: ${delta_time}`);
248
+ // if (this.status === ActiveTrackNode.Status.Pause) return delta_time;
249
+ // because we should proceed async list
250
+ // normal
251
+ if (!this.currentSection) {
252
+ this.status = ActiveTrackNode.Status.Pause;
253
+ return delta_time;
254
+ }
255
+ while (true) {
256
+ // constant field: time, wrapper, frame
257
+ // instant filed: syncs, asyncs
258
+ if (this.status === ActiveTrackNode.Status.Playing) {
259
+ if (this.currentSection.time === undefined ||
260
+ this.currentSection.time <= 0) {
261
+ this.nowProps = { ...this.nowProps, ...this.currentSection.frame };
262
+ }
263
+ else {
264
+ if (this.now_time + delta_time >= this.currentSection.time) {
265
+ // this.now_time = this.currentSection.time
266
+ delta_time -= this.currentSection.time - this.now_time;
267
+ this.nowProps = { ...this.nowProps, ...this.currentSection.frame };
268
+ }
269
+ else {
270
+ this.now_time += delta_time;
271
+ delta_time = 0;
272
+ // calc
273
+ let progress = this.now_time / this.currentSection.time;
274
+ // console.log(`progress: ${progress}`);
275
+ this.nowProps = this.animation._calcWrappedProps(this.lastProps, this.currentSection.frame ?? {}, this.currentSection.wrapper, progress);
276
+ break;
277
+ }
278
+ }
279
+ // sync async
280
+ if (this.currentSection.syncs && this.currentSection.syncs.length > 0) {
281
+ this.initSyncs();
282
+ this.status = ActiveTrackNode.Status.WaitingSyncs;
283
+ }
284
+ }
285
+ // step and check sync
286
+ if (this.status === ActiveTrackNode.Status.WaitingSyncs) {
287
+ delta_time = this.stepSyncs(delta_time); // returns lefted time
288
+ this.nowProps = Object.assign(this.nowProps, this.getSyncsProps());
289
+ if (this.checkSyncsFinished()) {
290
+ this.status = ActiveTrackNode.Status.Playing;
291
+ this.activeSyncs = [];
292
+ }
293
+ else {
294
+ // debug
295
+ if (delta_time !== 0)
296
+ throw "syncs not finished while lefted time != 0. may be bugs";
297
+ break;
298
+ }
299
+ }
300
+ // check repeat , finish
301
+ if (this.currentSection.repeat !== undefined) {
302
+ this.repeated++;
303
+ if (this.repeated >= this.currentSection.repeat) {
304
+ // finish and proceed next section
305
+ // TODO
306
+ if (this._switchNextSection())
307
+ continue;
308
+ else
309
+ break;
310
+ }
311
+ else {
312
+ // continue this section
313
+ this.now_time = 0;
314
+ this.nowProps = { ...this.lastProps };
315
+ continue;
316
+ }
317
+ }
318
+ else {
319
+ if (this._switchNextSection())
320
+ continue;
321
+ else
322
+ break;
323
+ }
324
+ }
325
+ // waiting syncs
326
+ return delta_time;
327
+ }
328
+ calcProps() {
329
+ return this.nowProps;
330
+ }
331
+ _switchNextSection() {
332
+ if (this.currentIndex === null ||
333
+ this.currentTrack.length === this.currentIndex + 1) {
334
+ // already reach the end
335
+ this.status = ActiveTrackNode.Status.Pause;
336
+ return false;
337
+ }
338
+ else {
339
+ this.lastProps = { ...this.nowProps };
340
+ this.repeated = 0;
341
+ this.now_time = 0;
342
+ this.currentIndex++;
343
+ return true;
344
+ }
345
+ }
346
+ activeSyncs = [];
347
+ initSyncs() {
348
+ // console.log("init syncs");
349
+ let activeSyncs = [];
350
+ // if (this.currentSection.syncs == null) return;
351
+ let subprofile = this.currentSection.syncs;
352
+ let activeTrackNode;
353
+ if (Array.isArray(subprofile)) {
354
+ if (subprofile.length > 0 && Array.isArray(subprofile[0])) {
355
+ // tracklist
356
+ for (let j = 0; j < subprofile.length; ++j) {
357
+ activeTrackNode = new ActiveTrackNode(this.animation, {
358
+ accessKeys: [
359
+ ...this.accessKeys,
360
+ "" + this.currentIndex,
361
+ "syncs",
362
+ "" + j,
363
+ ],
364
+ index: 0,
365
+ initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
366
+ });
367
+ activeSyncs.push(activeTrackNode);
368
+ }
369
+ }
370
+ else {
371
+ // Track
372
+ activeTrackNode = new ActiveTrackNode(this.animation, {
373
+ accessKeys: [...this.accessKeys, "" + this.currentIndex, "syncs"],
374
+ index: 0,
375
+ initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
376
+ });
377
+ activeSyncs.push(activeTrackNode);
378
+ console
379
+ .log();
380
+ }
381
+ }
382
+ else {
383
+ // section
384
+ activeTrackNode = new ActiveTrackNode(this.animation, {
385
+ accessKeys: [...this.accessKeys, "" + this.currentIndex, "syncs"],
386
+ index: null,
387
+ initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
388
+ });
389
+ activeSyncs.push(activeTrackNode);
390
+ }
391
+ // activeTrackNode?.step(0); // TODO
392
+ this.activeSyncs = activeSyncs;
393
+ }
394
+ stepSyncs(delta_time) {
395
+ let lefted_time = delta_time;
396
+ for (let i = 0; i < this.activeSyncs.length; ++i) {
397
+ lefted_time = Math.min(this.activeSyncs[i].step(delta_time), lefted_time);
398
+ }
399
+ return lefted_time;
400
+ }
401
+ checkSyncsFinished() {
402
+ for (let i = 0; i < this.activeSyncs.length; ++i) {
403
+ if (this.activeSyncs[i].status !== ActiveTrackNode.Status.Pause)
404
+ return false;
405
+ }
406
+ return true;
407
+ }
408
+ getSyncsProps() {
409
+ let res = {};
410
+ for (let i = 0; i < this.activeSyncs.length; ++i) {
411
+ Object.assign(res, this.activeSyncs[i].calcProps());
412
+ }
413
+ return res;
414
+ }
415
+ }
416
+ (function (ActiveTrackNode) {
417
+ let Status;
418
+ (function (Status) {
419
+ Status[Status["Playing"] = 0] = "Playing";
420
+ Status[Status["WaitingSyncs"] = 1] = "WaitingSyncs";
421
+ Status[Status["Pause"] = 2] = "Pause";
422
+ })(Status = ActiveTrackNode.Status || (ActiveTrackNode.Status = {}));
423
+ })(ActiveTrackNode || (ActiveTrackNode = {}));
424
+ const buildInWrappers = {
425
+ none: (x) => (x < 1 ? 0 : 1),
426
+ linear: (x) => x,
427
+ easeout: (x) => Math.pow(x, 3),
428
+ easein: (x) => 1 - Math.pow(1 - x, 3),
429
+ easeinout: (x) => x < 0.5 ? 0.5 * Math.pow(x, 3) : 1 - 0.5 * Math.pow(1 - x, 3),
430
+ };