hzengine-core 0.1.2-dev
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.
- package/dist/async/index.js +162 -0
- package/dist/async/zeppos_timer.js +58 -0
- package/dist/audio/index.js +260 -0
- package/dist/config/index.js +57 -0
- package/dist/debug/index.js +8 -0
- package/dist/index.js +103 -0
- package/dist/platform/index.js +1 -0
- package/dist/plugins/basic_command/$.js +8 -0
- package/dist/plugins/basic_command/audio.js +40 -0
- package/dist/plugins/basic_command/basic.js +124 -0
- package/dist/plugins/basic_command/character.js +112 -0
- package/dist/plugins/basic_command/conditional.js +260 -0
- package/dist/plugins/basic_command/config.js +22 -0
- package/dist/plugins/basic_command/decorator.js +24 -0
- package/dist/plugins/basic_command/eval.js +67 -0
- package/dist/plugins/basic_command/img.js +249 -0
- package/dist/plugins/basic_command/index.js +22 -0
- package/dist/plugins/basic_command/menu.js +140 -0
- package/dist/plugins/global_gesture/index.js +25 -0
- package/dist/plugins/transform/animation.js +440 -0
- package/dist/plugins/transform/commands.js +38 -0
- package/dist/plugins/transform/example_profiles.js +32 -0
- package/dist/plugins/transform/hz_anime.js +211 -0
- package/dist/plugins/transform/index.js +93 -0
- package/dist/script/index.js +537 -0
- package/dist/script/readscript.js +15 -0
- package/dist/script/strtools.js +157 -0
- package/dist/storage/decorator.js +260 -0
- package/dist/storage/fs.js +96 -0
- package/dist/storage/index.js +442 -0
- package/dist/system/index.js +144 -0
- package/dist/ui/index.js +535 -0
- package/dist/utils/path.js +289 -0
- package/license.txt +202 -0
- package/package.json +26 -0
- package/src/async/index.ts +124 -0
- package/src/async/zeppos_timer.js +65 -0
- package/src/audio/index.ts +224 -0
- package/src/config/index.ts +80 -0
- package/src/debug/index.ts +11 -0
- package/src/index.ts +122 -0
- package/src/platform/index.ts +158 -0
- package/src/plugins/basic_command/$.ts +11 -0
- package/src/plugins/basic_command/audio.ts +53 -0
- package/src/plugins/basic_command/basic.ts +145 -0
- package/src/plugins/basic_command/character.ts +144 -0
- package/src/plugins/basic_command/conditional.ts +349 -0
- package/src/plugins/basic_command/config.ts +29 -0
- package/src/plugins/basic_command/decorator.ts +29 -0
- package/src/plugins/basic_command/eval.ts +88 -0
- package/src/plugins/basic_command/img.ts +317 -0
- package/src/plugins/basic_command/index.ts +24 -0
- package/src/plugins/basic_command/menu.ts +178 -0
- package/src/plugins/global_gesture/index.ts +29 -0
- package/src/plugins/transform/animation.ts +542 -0
- package/src/plugins/transform/commands.ts +53 -0
- package/src/plugins/transform/example_profiles.ts +36 -0
- package/src/plugins/transform/hz_anime.ts +214 -0
- package/src/plugins/transform/index.ts +141 -0
- package/src/plugins/transform/readme.md +1 -0
- package/src/script/index.ts +623 -0
- package/src/script/readscript.ts +17 -0
- package/src/script/strtools.ts +159 -0
- package/src/storage/decorator.ts +473 -0
- package/src/storage/fs.ts +104 -0
- package/src/storage/index.ts +541 -0
- package/src/system/index.ts +95 -0
- package/src/ui/index.ts +699 -0
- package/src/utils/path.js +338 -0
- package/tsconfig.json +111 -0
- package/types/async/index.d.ts +24 -0
- package/types/async/zeppos_timer.d.ts +14 -0
- package/types/audio/index.d.ts +64 -0
- package/types/config/index.d.ts +9 -0
- package/types/debug/index.d.ts +6 -0
- package/types/index.d.ts +41 -0
- package/types/platform/index.d.ts +134 -0
- package/types/plugins/basic_command/$.d.ts +2 -0
- package/types/plugins/basic_command/audio.d.ts +2 -0
- package/types/plugins/basic_command/basic.d.ts +3 -0
- package/types/plugins/basic_command/character.d.ts +2 -0
- package/types/plugins/basic_command/conditional.d.ts +2 -0
- package/types/plugins/basic_command/config.d.ts +2 -0
- package/types/plugins/basic_command/decorator.d.ts +2 -0
- package/types/plugins/basic_command/eval.d.ts +2 -0
- package/types/plugins/basic_command/img.d.ts +2 -0
- package/types/plugins/basic_command/index.d.ts +2 -0
- package/types/plugins/basic_command/menu.d.ts +2 -0
- package/types/plugins/global_gesture/index.d.ts +2 -0
- package/types/plugins/transform/animation.d.ts +131 -0
- package/types/plugins/transform/commands.d.ts +7 -0
- package/types/plugins/transform/example_profiles.d.ts +2 -0
- package/types/plugins/transform/hz_anime.d.ts +51 -0
- package/types/plugins/transform/index.d.ts +13 -0
- package/types/script/index.d.ts +123 -0
- package/types/script/readscript.d.ts +2 -0
- package/types/script/strtools.d.ts +31 -0
- package/types/storage/decorator.d.ts +41 -0
- package/types/storage/fs.d.ts +1 -0
- package/types/storage/index.d.ts +86 -0
- package/types/system/index.d.ts +35 -0
- package/types/ui/index.d.ts +167 -0
- package/types/utils/path.d.ts +84 -0
|
@@ -0,0 +1,542 @@
|
|
|
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
|
+
|
|
8
|
+
export class Animation<P extends Profile.PropsType = unknown> {
|
|
9
|
+
normalizedProfile: Profile.Track<P>;
|
|
10
|
+
initProps: Partial<P> = {};
|
|
11
|
+
activeRootTrack: ActiveTrackNode<P> | null = null;
|
|
12
|
+
lastTime: number = 0;
|
|
13
|
+
public onFrame: ((props: Partial<P>) => void) | null = null;
|
|
14
|
+
public onEnd: (() => void) | null = null;
|
|
15
|
+
customWrappers: Record<string, Wrapper> = {};
|
|
16
|
+
|
|
17
|
+
constructor(profile: Profile<P>, options?: Animation.Options<P>) {
|
|
18
|
+
this.normalizedProfile = Profile.normalize(profile);
|
|
19
|
+
console.log(`Animation: ${JSON.stringify(profile)}`);
|
|
20
|
+
|
|
21
|
+
if (options) {
|
|
22
|
+
options.initProps && (this.initProps = options.initProps);
|
|
23
|
+
options.wrappers && (this.customWrappers = options.wrappers);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
public onStop: ((animation: Animation<P>) => void) | null = null;
|
|
28
|
+
|
|
29
|
+
serialize(): Animation.Serialized {
|
|
30
|
+
return {
|
|
31
|
+
normalizedProfile: this.normalizedProfile,
|
|
32
|
+
initProps: this.initProps,
|
|
33
|
+
activeRootTrack: this.activeRootTrack?.serialize(),
|
|
34
|
+
lastTime: this.lastTime,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
static unserialize(
|
|
38
|
+
serialized: Animation.Serialized,
|
|
39
|
+
wrappers?: Record<string, Wrapper>
|
|
40
|
+
): Animation<unknown> {
|
|
41
|
+
let profile = serialized.normalizedProfile;
|
|
42
|
+
let animation = new Animation(profile, {
|
|
43
|
+
initProps: serialized.initProps,
|
|
44
|
+
wrappers,
|
|
45
|
+
});
|
|
46
|
+
animation.lastTime = serialized.lastTime;
|
|
47
|
+
serialized.activeRootTrack &&
|
|
48
|
+
(animation.activeRootTrack = ActiveTrackNode.unserialize(
|
|
49
|
+
animation,
|
|
50
|
+
serialized.activeRootTrack
|
|
51
|
+
));
|
|
52
|
+
return animation;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
timerCb(): void {}
|
|
56
|
+
|
|
57
|
+
init(): void {
|
|
58
|
+
this.activeRootTrack = new ActiveTrackNode(this, {
|
|
59
|
+
accessKeys: [],
|
|
60
|
+
index: 0,
|
|
61
|
+
initProps: this.initProps,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
goto(time: number) {
|
|
66
|
+
if (!this.activeRootTrack) {
|
|
67
|
+
this.init();
|
|
68
|
+
}
|
|
69
|
+
if (time < 0) time = 0;
|
|
70
|
+
if (time < this.lastTime) {
|
|
71
|
+
this.init(); // reset the tracknode
|
|
72
|
+
try {
|
|
73
|
+
this.activeRootTrack!.step(time);
|
|
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) this.onEnd();
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
if (this.activeRootTrack!.status !== ActiveTrackNode.Status.Pause) {
|
|
83
|
+
try {
|
|
84
|
+
this.activeRootTrack!.step(time - this.lastTime);
|
|
85
|
+
} catch (e) {
|
|
86
|
+
console.log(e);
|
|
87
|
+
this.activeRootTrack!.status = ActiveTrackNode.Status.Pause;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
this.lastTime = time;
|
|
92
|
+
|
|
93
|
+
if (this.onFrame) {
|
|
94
|
+
// console.log("on frame", JSON.stringify(this.calcProps()));
|
|
95
|
+
this.onFrame(this.calcProps());
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (this.activeRootTrack!.status === ActiveTrackNode.Status.Pause) {
|
|
99
|
+
if (this.onEnd) this.onEnd();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
step(delta_time: number) {
|
|
104
|
+
this.goto(this.lastTime + delta_time);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
calcProps(): Partial<P> {
|
|
108
|
+
return this.activeRootTrack!.calcProps();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
reverse(): void {}
|
|
112
|
+
|
|
113
|
+
stop(): void {}
|
|
114
|
+
|
|
115
|
+
_accessProfile(accessKeys: string[]): unknown {
|
|
116
|
+
let section: any = this.normalizedProfile;
|
|
117
|
+
for (let i = 0; i < accessKeys.length; i++) {
|
|
118
|
+
section = section[accessKeys[i]];
|
|
119
|
+
}
|
|
120
|
+
return section;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
_getWrapper(wrapper: string | Wrapper | undefined): Wrapper {
|
|
124
|
+
if (typeof wrapper === "string") {
|
|
125
|
+
return (
|
|
126
|
+
this.customWrappers[wrapper] ??
|
|
127
|
+
buildInWrappers[wrapper as keyof typeof buildInWrappers] ??
|
|
128
|
+
buildInWrappers.none
|
|
129
|
+
);
|
|
130
|
+
} else if (wrapper === undefined) {
|
|
131
|
+
return buildInWrappers.none;
|
|
132
|
+
} else return wrapper;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
_calcWrappedProps<P extends Profile.PropsType>(
|
|
136
|
+
former_props: Partial<P>,
|
|
137
|
+
props: Partial<P>,
|
|
138
|
+
wrapper: Wrapper | string | undefined,
|
|
139
|
+
progress: number
|
|
140
|
+
): Partial<P> {
|
|
141
|
+
let _former_props: any = { ...former_props };
|
|
142
|
+
let wrapper_func = this._getWrapper(wrapper);
|
|
143
|
+
let wraped_prog = wrapper_func(progress);
|
|
144
|
+
let res = { ..._former_props };
|
|
145
|
+
for (let key in props) {
|
|
146
|
+
if (typeof props[key] === "number") {
|
|
147
|
+
if (_former_props[key] == undefined) _former_props[key] = 0;
|
|
148
|
+
res[key] =
|
|
149
|
+
_former_props[key] + wraped_prog * (props[key] - _former_props[key]);
|
|
150
|
+
} else if (typeof props[key] === "boolean") {
|
|
151
|
+
if (_former_props[key] == undefined) _former_props[key] = false;
|
|
152
|
+
res[key] = wraped_prog === 1 ? props[key] : _former_props[key];
|
|
153
|
+
} else if (typeof props[key] === "string") {
|
|
154
|
+
if (_former_props[key] == undefined) _former_props[key] = "";
|
|
155
|
+
res[key] = wraped_prog === 1 ? props[key] : _former_props[key];
|
|
156
|
+
} else {
|
|
157
|
+
res[key] = props[key];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return res;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export namespace Animation {
|
|
165
|
+
export interface Options<P extends Profile.PropsType> {
|
|
166
|
+
// @ts-ignore
|
|
167
|
+
initProps?: Partial<P>;
|
|
168
|
+
wrappers?: Record<string, Wrapper>;
|
|
169
|
+
}
|
|
170
|
+
export interface Serialized {
|
|
171
|
+
normalizedProfile: Profile.Serialized;
|
|
172
|
+
initProps?: Partial<unknown>;
|
|
173
|
+
activeRootTrack?: ActiveTrackNode.Serialized;
|
|
174
|
+
lastTime: number;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export type Profile<P extends Profile.PropsType = unknown> =
|
|
179
|
+
| Profile.Section<P>
|
|
180
|
+
| Profile.Track<P>
|
|
181
|
+
| Profile.TrackList<P>;
|
|
182
|
+
|
|
183
|
+
export namespace Profile {
|
|
184
|
+
export type Serialized = Profile;
|
|
185
|
+
|
|
186
|
+
export type TrackList<P extends PropsType> = Track<P>[];
|
|
187
|
+
export type Track<P extends PropsType> = Section<P>[];
|
|
188
|
+
export type Section<P extends PropsType> = {
|
|
189
|
+
time?: number;
|
|
190
|
+
repeat?: number;
|
|
191
|
+
wrapper?: keyof typeof buildInWrappers | string | Wrapper;
|
|
192
|
+
frame?: Partial<P>;
|
|
193
|
+
syncs?: Profile<P>[];
|
|
194
|
+
asyncs?: Profile<P>[];
|
|
195
|
+
};
|
|
196
|
+
export type FrameItem = number | boolean | string;
|
|
197
|
+
export type PropsType = Record<string, FrameItem> | unknown;
|
|
198
|
+
export function normalize<P extends PropsType>(
|
|
199
|
+
profile: Profile<P>
|
|
200
|
+
): Track<P> {
|
|
201
|
+
if (!Array.isArray(profile)) {
|
|
202
|
+
// section
|
|
203
|
+
return [profile];
|
|
204
|
+
} else if (profile.length === 0) {
|
|
205
|
+
// empty track/tracklist
|
|
206
|
+
return [];
|
|
207
|
+
} else if (!Array.isArray(profile[0])) {
|
|
208
|
+
// track
|
|
209
|
+
return profile as Track<P>;
|
|
210
|
+
} else {
|
|
211
|
+
// tracklist
|
|
212
|
+
return [
|
|
213
|
+
{
|
|
214
|
+
syncs: profile,
|
|
215
|
+
},
|
|
216
|
+
];
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export interface Timer<TimerIdType> {
|
|
222
|
+
init(animation: Animation): void;
|
|
223
|
+
// 回調時調用animation.timerCallback
|
|
224
|
+
setTimeout(timeout?: number): TimerIdType;
|
|
225
|
+
clearTimeout(timerId: TimerIdType): void;
|
|
226
|
+
setInterval(interval?: number): TimerIdType;
|
|
227
|
+
clearInterval(timerId: TimerIdType): void;
|
|
228
|
+
getTime(): number; // in ms
|
|
229
|
+
setOption?(option: Timer.Options): void;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export namespace Timer {
|
|
233
|
+
export interface Options {
|
|
234
|
+
fps?: number;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export class ActiveTrackNode<P extends Profile.PropsType> {
|
|
239
|
+
accessKeys: string[];
|
|
240
|
+
currentIndex: number | null;
|
|
241
|
+
repeated: number = 0;
|
|
242
|
+
status: ActiveTrackNode.Status = ActiveTrackNode.Status.Playing;
|
|
243
|
+
now_time: number = 0;
|
|
244
|
+
#currentSection: Profile.Section<P> | null = null;
|
|
245
|
+
#currentIndex: number | null = null;
|
|
246
|
+
get currentSection() {
|
|
247
|
+
if (this.#currentSection === null) {
|
|
248
|
+
if (this.currentIndex === null) {
|
|
249
|
+
this.#currentSection = this.animation._accessProfile(
|
|
250
|
+
this.accessKeys
|
|
251
|
+
) as Profile.Section<P>;
|
|
252
|
+
} else {
|
|
253
|
+
this.#currentSection = this.currentTrack![this.currentIndex!];
|
|
254
|
+
}
|
|
255
|
+
this.#currentIndex = this.currentIndex;
|
|
256
|
+
} else if (this.currentIndex !== this.#currentIndex) {
|
|
257
|
+
this.#currentSection = this.currentTrack![this.currentIndex!];
|
|
258
|
+
this.#currentIndex = this.currentIndex;
|
|
259
|
+
}
|
|
260
|
+
return this.#currentSection;
|
|
261
|
+
}
|
|
262
|
+
#currentTrack: Profile.Track<P> | null = null;
|
|
263
|
+
get currentTrack() {
|
|
264
|
+
if (this.#currentTrack === null && this.currentIndex !== null) {
|
|
265
|
+
this.#currentTrack = this.animation._accessProfile(
|
|
266
|
+
this.accessKeys
|
|
267
|
+
) as Profile.Track<P>;
|
|
268
|
+
}
|
|
269
|
+
return this.#currentTrack;
|
|
270
|
+
}
|
|
271
|
+
lastProps: Partial<P> = {};
|
|
272
|
+
nowProps: Partial<P> = {};
|
|
273
|
+
constructor(
|
|
274
|
+
public animation: Animation,
|
|
275
|
+
{
|
|
276
|
+
accessKeys,
|
|
277
|
+
index,
|
|
278
|
+
initProps,
|
|
279
|
+
}: {
|
|
280
|
+
accessKeys: string[];
|
|
281
|
+
index: number | null;
|
|
282
|
+
initProps: Partial<P>;
|
|
283
|
+
}
|
|
284
|
+
) {
|
|
285
|
+
this.accessKeys = accessKeys;
|
|
286
|
+
this.currentIndex = index;
|
|
287
|
+
|
|
288
|
+
this.lastProps = { ...initProps };
|
|
289
|
+
this.nowProps = { ...initProps };
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
serialize(): ActiveTrackNode.Serialized {
|
|
293
|
+
return {
|
|
294
|
+
accessKeys: this.accessKeys,
|
|
295
|
+
currentIndex: this.currentIndex,
|
|
296
|
+
repeated: this.repeated,
|
|
297
|
+
status: this.status,
|
|
298
|
+
now_time: this.now_time,
|
|
299
|
+
lastProps: this.lastProps,
|
|
300
|
+
nowProps: this.nowProps,
|
|
301
|
+
activeSyncs: this.activeSyncs.map((sync) => sync.serialize()),
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
static unserialize<P>(
|
|
305
|
+
animation: Animation,
|
|
306
|
+
serialized: ActiveTrackNode.Serialized
|
|
307
|
+
): ActiveTrackNode<P> {
|
|
308
|
+
let node = new ActiveTrackNode(animation, {
|
|
309
|
+
accessKeys: serialized.accessKeys,
|
|
310
|
+
index: serialized.currentIndex,
|
|
311
|
+
initProps: serialized.lastProps,
|
|
312
|
+
});
|
|
313
|
+
node.lastProps = serialized.lastProps;
|
|
314
|
+
node.nowProps = serialized.nowProps;
|
|
315
|
+
node.status = serialized.status;
|
|
316
|
+
node.repeated = serialized.repeated;
|
|
317
|
+
node.now_time = serialized.now_time;
|
|
318
|
+
|
|
319
|
+
node.activeSyncs = serialized.activeSyncs.map((sync) =>
|
|
320
|
+
ActiveTrackNode.unserialize<P>(animation, sync)
|
|
321
|
+
);
|
|
322
|
+
return node;
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
*
|
|
326
|
+
* @param delta_time
|
|
327
|
+
* @returns 剩餘的時間
|
|
328
|
+
*/
|
|
329
|
+
step(delta_time: number): number {
|
|
330
|
+
// console.log(`node step: ${delta_time}`);
|
|
331
|
+
|
|
332
|
+
// if (this.status === ActiveTrackNode.Status.Pause) return delta_time;
|
|
333
|
+
// because we should proceed async list
|
|
334
|
+
// normal
|
|
335
|
+
if(!this.currentSection) {
|
|
336
|
+
this.status = ActiveTrackNode.Status.Pause;
|
|
337
|
+
return delta_time;
|
|
338
|
+
}
|
|
339
|
+
while (true) {
|
|
340
|
+
// constant field: time, wrapper, frame
|
|
341
|
+
// instant filed: syncs, asyncs
|
|
342
|
+
if (this.status === ActiveTrackNode.Status.Playing) {
|
|
343
|
+
if (
|
|
344
|
+
this.currentSection.time === undefined ||
|
|
345
|
+
this.currentSection.time <= 0
|
|
346
|
+
) {
|
|
347
|
+
this.nowProps = { ...this.nowProps, ...this.currentSection.frame };
|
|
348
|
+
} else {
|
|
349
|
+
if (this.now_time + delta_time >= this.currentSection.time) {
|
|
350
|
+
// this.now_time = this.currentSection.time
|
|
351
|
+
delta_time -= this.currentSection.time - this.now_time;
|
|
352
|
+
this.nowProps = { ...this.nowProps, ...this.currentSection.frame };
|
|
353
|
+
} else {
|
|
354
|
+
this.now_time += delta_time;
|
|
355
|
+
delta_time = 0;
|
|
356
|
+
// calc
|
|
357
|
+
let progress = this.now_time / this.currentSection.time;
|
|
358
|
+
// console.log(`progress: ${progress}`);
|
|
359
|
+
this.nowProps = this.animation._calcWrappedProps(
|
|
360
|
+
this.lastProps,
|
|
361
|
+
this.currentSection.frame ?? {},
|
|
362
|
+
this.currentSection.wrapper,
|
|
363
|
+
progress
|
|
364
|
+
);
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// sync async
|
|
370
|
+
if (this.currentSection.syncs && this.currentSection.syncs.length > 0) {
|
|
371
|
+
this.initSyncs();
|
|
372
|
+
this.status = ActiveTrackNode.Status.WaitingSyncs;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// step and check sync
|
|
377
|
+
if (this.status === ActiveTrackNode.Status.WaitingSyncs) {
|
|
378
|
+
delta_time = this.stepSyncs(delta_time); // returns lefted time
|
|
379
|
+
this.nowProps = Object.assign(this.nowProps, this.getSyncsProps());
|
|
380
|
+
if (this.checkSyncsFinished()) {
|
|
381
|
+
this.status = ActiveTrackNode.Status.Playing;
|
|
382
|
+
this.activeSyncs = [];
|
|
383
|
+
} else {
|
|
384
|
+
// debug
|
|
385
|
+
if (delta_time !== 0)
|
|
386
|
+
throw "syncs not finished while lefted time != 0. may be bugs";
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// check repeat , finish
|
|
392
|
+
if (this.currentSection.repeat !== undefined) {
|
|
393
|
+
this.repeated++;
|
|
394
|
+
if (this.repeated >= this.currentSection.repeat) {
|
|
395
|
+
// finish and proceed next section
|
|
396
|
+
// TODO
|
|
397
|
+
if (this._switchNextSection()) continue;
|
|
398
|
+
else break;
|
|
399
|
+
} else {
|
|
400
|
+
// continue this section
|
|
401
|
+
this.now_time = 0;
|
|
402
|
+
this.nowProps = { ...this.lastProps };
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
} else {
|
|
406
|
+
if (this._switchNextSection()) continue;
|
|
407
|
+
else break;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// waiting syncs
|
|
412
|
+
|
|
413
|
+
return delta_time;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
calcProps(): Partial<P> {
|
|
417
|
+
return this.nowProps;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
_switchNextSection(): boolean {
|
|
421
|
+
if (
|
|
422
|
+
this.currentIndex === null ||
|
|
423
|
+
this.currentTrack!.length === this.currentIndex + 1
|
|
424
|
+
) {
|
|
425
|
+
// already reach the end
|
|
426
|
+
this.status = ActiveTrackNode.Status.Pause;
|
|
427
|
+
return false;
|
|
428
|
+
} else {
|
|
429
|
+
this.lastProps = { ...this.nowProps };
|
|
430
|
+
this.repeated = 0;
|
|
431
|
+
this.now_time = 0;
|
|
432
|
+
this.currentIndex++;
|
|
433
|
+
return true;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
activeSyncs: ActiveTrackNode<P>[] = [];
|
|
438
|
+
|
|
439
|
+
initSyncs() {
|
|
440
|
+
// console.log("init syncs");
|
|
441
|
+
|
|
442
|
+
let activeSyncs: ActiveTrackNode<P>[] = [];
|
|
443
|
+
// if (this.currentSection.syncs == null) return;
|
|
444
|
+
let subprofile = this.currentSection.syncs!;
|
|
445
|
+
let activeTrackNode;
|
|
446
|
+
if (Array.isArray(subprofile)) {
|
|
447
|
+
if (subprofile.length > 0 && Array.isArray(subprofile[0])) {
|
|
448
|
+
// tracklist
|
|
449
|
+
for (let j = 0; j < subprofile.length; ++j) {
|
|
450
|
+
activeTrackNode = new ActiveTrackNode(this.animation, {
|
|
451
|
+
accessKeys: [
|
|
452
|
+
...this.accessKeys,
|
|
453
|
+
"" + this.currentIndex,
|
|
454
|
+
"syncs",
|
|
455
|
+
"" + j,
|
|
456
|
+
],
|
|
457
|
+
index: 0,
|
|
458
|
+
initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
|
|
459
|
+
});
|
|
460
|
+
activeSyncs.push(activeTrackNode);
|
|
461
|
+
}
|
|
462
|
+
} else {
|
|
463
|
+
// Track
|
|
464
|
+
activeTrackNode = new ActiveTrackNode(this.animation, {
|
|
465
|
+
accessKeys: [...this.accessKeys, "" + this.currentIndex, "syncs"],
|
|
466
|
+
index: 0,
|
|
467
|
+
initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
|
|
468
|
+
});
|
|
469
|
+
activeSyncs.push(activeTrackNode);
|
|
470
|
+
console
|
|
471
|
+
.log
|
|
472
|
+
// "create subtrack=" + JSON.stringify(activeTrackNode.serialize())
|
|
473
|
+
();
|
|
474
|
+
}
|
|
475
|
+
} else {
|
|
476
|
+
// section
|
|
477
|
+
activeTrackNode = new ActiveTrackNode(this.animation, {
|
|
478
|
+
accessKeys: [...this.accessKeys, "" + this.currentIndex, "syncs"],
|
|
479
|
+
index: null,
|
|
480
|
+
initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
|
|
481
|
+
});
|
|
482
|
+
activeSyncs.push(activeTrackNode);
|
|
483
|
+
}
|
|
484
|
+
// activeTrackNode?.step(0); // TODO
|
|
485
|
+
|
|
486
|
+
this.activeSyncs = activeSyncs;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
stepSyncs(delta_time: number): number {
|
|
490
|
+
let lefted_time = delta_time;
|
|
491
|
+
for (let i = 0; i < this.activeSyncs.length; ++i) {
|
|
492
|
+
lefted_time = Math.min(this.activeSyncs[i].step(delta_time), lefted_time);
|
|
493
|
+
}
|
|
494
|
+
return lefted_time;
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
checkSyncsFinished(): boolean {
|
|
498
|
+
for (let i = 0; i < this.activeSyncs.length; ++i) {
|
|
499
|
+
if (this.activeSyncs[i].status !== ActiveTrackNode.Status.Pause)
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
return true;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
getSyncsProps() {
|
|
506
|
+
let res: Partial<P> = {};
|
|
507
|
+
for (let i = 0; i < this.activeSyncs.length; ++i) {
|
|
508
|
+
Object.assign(res, this.activeSyncs[i].calcProps());
|
|
509
|
+
}
|
|
510
|
+
return res;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export namespace ActiveTrackNode {
|
|
515
|
+
export enum Status {
|
|
516
|
+
Playing,
|
|
517
|
+
WaitingSyncs,
|
|
518
|
+
Pause,
|
|
519
|
+
}
|
|
520
|
+
export interface Serialized {
|
|
521
|
+
accessKeys: string[];
|
|
522
|
+
currentIndex: number | null;
|
|
523
|
+
repeated: number;
|
|
524
|
+
status: ActiveTrackNode.Status;
|
|
525
|
+
now_time: number;
|
|
526
|
+
lastProps: Partial<unknown>;
|
|
527
|
+
nowProps: Partial<unknown>;
|
|
528
|
+
activeSyncs: ActiveTrackNode.Serialized[];
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// Map a number from [0, 1] (progress time percentage) to [0, 1] (animation parameter value percentage).
|
|
533
|
+
export type Wrapper = (x: number) => number;
|
|
534
|
+
|
|
535
|
+
const buildInWrappers = {
|
|
536
|
+
none: (x: number) => (x < 1 ? 0 : 1),
|
|
537
|
+
linear: (x: number) => x,
|
|
538
|
+
easeout: (x: number) => Math.pow(x, 3),
|
|
539
|
+
easein: (x: number) => 1 - Math.pow(1 - x, 3),
|
|
540
|
+
easeinout: (x: number) =>
|
|
541
|
+
x < 0.5 ? 0.5 * Math.pow(x, 3) : 1 - 0.5 * Math.pow(1 - x, 3),
|
|
542
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { HZEngineCore, Script } from "../../index.js";
|
|
2
|
+
|
|
3
|
+
export function registerHzscriptCommands(core: HZEngineCore) {
|
|
4
|
+
core.script.use((ctx, next) => {
|
|
5
|
+
if (ctx.rawtext.trim().split(" ")[0] !== "transition") return next();
|
|
6
|
+
if (ctx.rawtext.includes(`"`))
|
|
7
|
+
throw `Transition Command: cannot have quotes in transition command`;
|
|
8
|
+
if (ctx.slicedArgs.length !== 4)
|
|
9
|
+
throw `Transition Command: incorrect amount of args`;
|
|
10
|
+
if (ctx.slicedArgs[1].isQuoted || ctx.slicedArgs[1].isSquared)
|
|
11
|
+
throw `Transition Command: invalid transition name type`;
|
|
12
|
+
let transitionName = ctx.slicedArgs[1].str;
|
|
13
|
+
if (
|
|
14
|
+
ctx.slicedArgs[2].isQuoted ||
|
|
15
|
+
ctx.slicedArgs[2].isSquared ||
|
|
16
|
+
ctx.slicedArgs[2].str !== "="
|
|
17
|
+
) {
|
|
18
|
+
throw `the third arg of transition command should be "="`;
|
|
19
|
+
}
|
|
20
|
+
let tuple_str = Script.Utils.joinSlicedArgs(ctx.slicedArgs.slice(3));
|
|
21
|
+
let tuple = Script.Utils.parseTuple(tuple_str);
|
|
22
|
+
if (tuple.length !== 2) {
|
|
23
|
+
throw `thransition tuple must have 2 args`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
let inTransforms: string[] = (tuple[0] as string).startsWith("[")
|
|
27
|
+
? Script.Utils.parseArray((tuple[0] as string)) as string[]
|
|
28
|
+
: [(tuple[0] as string)];
|
|
29
|
+
let outTransforms: string[] = (tuple[1] as string).startsWith("[")
|
|
30
|
+
? Script.Utils.parseArray((tuple[1] as string)) as string[]
|
|
31
|
+
: [(tuple[1] as string)];
|
|
32
|
+
|
|
33
|
+
let transitionMap = getTransitionMap(core);
|
|
34
|
+
transitionMap[transitionName] = {
|
|
35
|
+
inTransforms,
|
|
36
|
+
outTransforms,
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getTransitionMap(core: HZEngineCore) {
|
|
42
|
+
return core.storage.getSaveableData(
|
|
43
|
+
core.storage.archiveData,
|
|
44
|
+
true,
|
|
45
|
+
"script",
|
|
46
|
+
"transitionMap"
|
|
47
|
+
) as unknown as Record<string, TransitionData>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type TransitionData = {
|
|
51
|
+
inTransforms: string[];
|
|
52
|
+
outTransforms: string[];
|
|
53
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Profile } from "./animation.js";
|
|
2
|
+
|
|
3
|
+
export const ExampleProfile1: Profile = [
|
|
4
|
+
[ // alpha
|
|
5
|
+
{
|
|
6
|
+
frame: {
|
|
7
|
+
alpha: 0,
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
time: 0.5,
|
|
12
|
+
wrapper: "easein",
|
|
13
|
+
frame: {
|
|
14
|
+
alpha: 1,
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
[ // x
|
|
19
|
+
{
|
|
20
|
+
frame: {
|
|
21
|
+
xalign: -1,
|
|
22
|
+
xanchor: -1,
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
time: 1.0,
|
|
27
|
+
wrapper: "easein",
|
|
28
|
+
frame: {
|
|
29
|
+
xalign: 1,
|
|
30
|
+
xanchor: 1,
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
]
|
|
35
|
+
]
|
|
36
|
+
|