@eva/plugin-tween 2.1.0-beta.1 → 2.1.0-beta.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.
- package/dist/plugin-tween.cjs.js +351 -0
- package/dist/plugin-tween.cjs.prod.js +1 -0
- package/dist/plugin-tween.d.ts +99 -0
- package/dist/plugin-tween.esm.js +346 -0
- package/index.js +7 -0
- package/package.json +8 -7
- package/lib/Tween.ts +0 -206
- package/lib/TweenSystem.ts +0 -9
- package/lib/easing.ts +0 -48
- package/lib/index.ts +0 -4
- package/lib/path.ts +0 -75
- package/lib/types.ts +0 -37
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var eva_js = require('@eva/eva.js');
|
|
6
|
+
var pluginSignalBus = require('@eva/plugin-signal-bus');
|
|
7
|
+
|
|
8
|
+
/******************************************************************************
|
|
9
|
+
Copyright (c) Microsoft Corporation.
|
|
10
|
+
|
|
11
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
12
|
+
purpose with or without fee is hereby granted.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
15
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
16
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
17
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
18
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
19
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
20
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
21
|
+
***************************************************************************** */
|
|
22
|
+
|
|
23
|
+
function __decorate(decorators, target, key, desc) {
|
|
24
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
25
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
26
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
27
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
31
|
+
var e = new Error(message);
|
|
32
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const PI = Math.PI;
|
|
36
|
+
const c1 = 1.70158;
|
|
37
|
+
const c2 = c1 * 1.525;
|
|
38
|
+
const c3 = c1 + 1;
|
|
39
|
+
const c4 = (2 * PI) / 3;
|
|
40
|
+
const c5 = (2 * PI) / 4.5;
|
|
41
|
+
const n1 = 7.5625;
|
|
42
|
+
const d1 = 2.75;
|
|
43
|
+
function easeInBounce(x) {
|
|
44
|
+
return 1 - easeOutBounce(1 - x);
|
|
45
|
+
}
|
|
46
|
+
function easeOutBounce(x) {
|
|
47
|
+
if (x < 1 / d1)
|
|
48
|
+
return n1 * x * x;
|
|
49
|
+
if (x < 2 / d1)
|
|
50
|
+
return n1 * (x -= 1.5 / d1) * x + 0.75;
|
|
51
|
+
if (x < 2.5 / d1)
|
|
52
|
+
return n1 * (x -= 2.25 / d1) * x + 0.9375;
|
|
53
|
+
return n1 * (x -= 2.625 / d1) * x + 0.984375;
|
|
54
|
+
}
|
|
55
|
+
const Easing = {
|
|
56
|
+
linear: (t) => t,
|
|
57
|
+
easeInQuad: (t) => t * t,
|
|
58
|
+
easeOutQuad: (t) => 1 - (1 - t) * (1 - t),
|
|
59
|
+
easeInOutQuad: (t) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2),
|
|
60
|
+
easeInCubic: (t) => t * t * t,
|
|
61
|
+
easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),
|
|
62
|
+
easeInOutCubic: (t) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2),
|
|
63
|
+
easeInElastic: (t) => (t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * c4)),
|
|
64
|
+
easeOutElastic: (t) => (t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1),
|
|
65
|
+
easeInOutElastic: (t) => {
|
|
66
|
+
if (t === 0)
|
|
67
|
+
return 0;
|
|
68
|
+
if (t === 1)
|
|
69
|
+
return 1;
|
|
70
|
+
return t < 0.5
|
|
71
|
+
? -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * c5)) / 2
|
|
72
|
+
: (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * c5)) / 2 + 1;
|
|
73
|
+
},
|
|
74
|
+
easeInBack: (t) => c3 * t * t * t - c1 * t * t,
|
|
75
|
+
easeOutBack: (t) => 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2),
|
|
76
|
+
easeInOutBack: (t) => t < 0.5
|
|
77
|
+
? (Math.pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2
|
|
78
|
+
: (Math.pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2,
|
|
79
|
+
easeInBounce,
|
|
80
|
+
easeOutBounce,
|
|
81
|
+
easeInOutBounce: (t) => (t < 0.5 ? (1 - easeOutBounce(1 - 2 * t)) / 2 : (1 + easeOutBounce(2 * t - 1)) / 2),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
function bindPath(go, path) {
|
|
85
|
+
const parts = path.split('.');
|
|
86
|
+
if (parts[0] === 'transform') {
|
|
87
|
+
const obj = go.transform;
|
|
88
|
+
return diveIntoObject(obj, parts.slice(1));
|
|
89
|
+
}
|
|
90
|
+
if (parts[0] === 'components' && parts.length >= 3) {
|
|
91
|
+
const compName = parts[1];
|
|
92
|
+
const comp = findComponent(go, compName);
|
|
93
|
+
if (!comp)
|
|
94
|
+
return null;
|
|
95
|
+
return diveIntoObject(comp, parts.slice(2));
|
|
96
|
+
}
|
|
97
|
+
if (parts[0] === 'store' && parts.length >= 2) {
|
|
98
|
+
return bindStore(parts.slice(1).join('.'));
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
function diveIntoObject(root, keys) {
|
|
103
|
+
if (!root || keys.length === 0)
|
|
104
|
+
return null;
|
|
105
|
+
let parent = root;
|
|
106
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
107
|
+
const k = keys[i];
|
|
108
|
+
if (parent[k] == null)
|
|
109
|
+
return null;
|
|
110
|
+
parent = parent[k];
|
|
111
|
+
}
|
|
112
|
+
const last = keys[keys.length - 1];
|
|
113
|
+
return {
|
|
114
|
+
read: () => { var _a; return Number((_a = parent[last]) !== null && _a !== void 0 ? _a : 0); },
|
|
115
|
+
write: (v) => {
|
|
116
|
+
parent[last] = v;
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
function findComponent(go, name) {
|
|
121
|
+
var _a, _b;
|
|
122
|
+
const comps = go.components || [];
|
|
123
|
+
for (const c of comps) {
|
|
124
|
+
const cn = (_a = c === null || c === void 0 ? void 0 : c.constructor) === null || _a === void 0 ? void 0 : _a.componentName;
|
|
125
|
+
if (cn === name)
|
|
126
|
+
return c;
|
|
127
|
+
}
|
|
128
|
+
// 退路:Eva.js 部分版本支持 getComponent(name)
|
|
129
|
+
if (typeof go.getComponent === 'function') {
|
|
130
|
+
return (_b = go.getComponent(name)) !== null && _b !== void 0 ? _b : null;
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
function bindStore(key) {
|
|
135
|
+
// mx.store 是宿主全局,不强依赖
|
|
136
|
+
const mx = globalThis.mx;
|
|
137
|
+
if (!(mx === null || mx === void 0 ? void 0 : mx.store))
|
|
138
|
+
return null;
|
|
139
|
+
return {
|
|
140
|
+
read: () => { var _a, _b, _c; return Number((_c = (_b = (_a = mx.store).get) === null || _b === void 0 ? void 0 : _b.call(_a, key)) !== null && _c !== void 0 ? _c : 0); },
|
|
141
|
+
write: (v) => {
|
|
142
|
+
var _a, _b;
|
|
143
|
+
(_b = (_a = mx.store).update) === null || _b === void 0 ? void 0 : _b.call(_a, { [key]: v });
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Tween 组件 — Godot Tween 等价物。
|
|
150
|
+
*
|
|
151
|
+
* 与 plugin-transition 区别:
|
|
152
|
+
* - 不限制 target 类型(transform/Component/store 都行)
|
|
153
|
+
* - 内置 sequence 与 parallel 编排
|
|
154
|
+
* - 完成 emit 命名信号
|
|
155
|
+
*
|
|
156
|
+
* DSL 用法:
|
|
157
|
+
* ```json
|
|
158
|
+
* {
|
|
159
|
+
* "type": "Tween",
|
|
160
|
+
* "props": {
|
|
161
|
+
* "step": {
|
|
162
|
+
* "target": "components.RocketAimer.currentAngleDeg",
|
|
163
|
+
* "from": -60, "to": 60, "duration": 1500, "easing": "easeInOutQuad"
|
|
164
|
+
* },
|
|
165
|
+
* "yoyo": true, "loop": -1, "autostart": true
|
|
166
|
+
* }
|
|
167
|
+
* }
|
|
168
|
+
* ```
|
|
169
|
+
*/
|
|
170
|
+
exports.Tween = class Tween extends eva_js.Component {
|
|
171
|
+
constructor() {
|
|
172
|
+
super(...arguments);
|
|
173
|
+
this.steps = [];
|
|
174
|
+
this.parallel = false;
|
|
175
|
+
this.yoyo = false;
|
|
176
|
+
this.loop = 0;
|
|
177
|
+
this.autostart = false;
|
|
178
|
+
this.running = [];
|
|
179
|
+
this.isPlaying = false;
|
|
180
|
+
this.playedLoops = 0;
|
|
181
|
+
this.cursor = 0; // sequence 当前 step
|
|
182
|
+
this.direction = 1;
|
|
183
|
+
}
|
|
184
|
+
init(params) {
|
|
185
|
+
var _a, _b, _c, _d, _e;
|
|
186
|
+
if (!params)
|
|
187
|
+
return;
|
|
188
|
+
this.steps = params.step ? [params.step] : ((_a = params.steps) !== null && _a !== void 0 ? _a : []);
|
|
189
|
+
this.parallel = (_b = params.parallel) !== null && _b !== void 0 ? _b : false;
|
|
190
|
+
this.yoyo = (_c = params.yoyo) !== null && _c !== void 0 ? _c : false;
|
|
191
|
+
this.loop = (_d = params.loop) !== null && _d !== void 0 ? _d : 0;
|
|
192
|
+
this.autostart = (_e = params.autostart) !== null && _e !== void 0 ? _e : false;
|
|
193
|
+
this.signal = params.signal;
|
|
194
|
+
}
|
|
195
|
+
awake() {
|
|
196
|
+
if (this.autostart)
|
|
197
|
+
this.play();
|
|
198
|
+
}
|
|
199
|
+
/** 重新开始 */
|
|
200
|
+
play() {
|
|
201
|
+
this.buildRunning();
|
|
202
|
+
this.isPlaying = true;
|
|
203
|
+
this.playedLoops = 0;
|
|
204
|
+
this.cursor = 0;
|
|
205
|
+
this.direction = 1;
|
|
206
|
+
}
|
|
207
|
+
pause() {
|
|
208
|
+
this.isPlaying = false;
|
|
209
|
+
}
|
|
210
|
+
resume() {
|
|
211
|
+
if (this.running.length)
|
|
212
|
+
this.isPlaying = true;
|
|
213
|
+
}
|
|
214
|
+
stop() {
|
|
215
|
+
this.isPlaying = false;
|
|
216
|
+
this.running = [];
|
|
217
|
+
}
|
|
218
|
+
buildRunning() {
|
|
219
|
+
var _a, _b, _c, _d;
|
|
220
|
+
this.running = [];
|
|
221
|
+
for (const s of this.steps) {
|
|
222
|
+
const binding = bindPath(this.gameObject, s.target);
|
|
223
|
+
if (!binding) {
|
|
224
|
+
// eslint-disable-next-line no-console
|
|
225
|
+
console.warn(`[plugin-tween] binding miss: ${s.target}`);
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
const from = (_a = s.from) !== null && _a !== void 0 ? _a : binding.read();
|
|
229
|
+
this.running.push({
|
|
230
|
+
binding,
|
|
231
|
+
from,
|
|
232
|
+
to: s.to,
|
|
233
|
+
duration: Math.max(1, s.duration),
|
|
234
|
+
easing: (_c = Easing[((_b = s.easing) !== null && _b !== void 0 ? _b : 'linear')]) !== null && _c !== void 0 ? _c : Easing.linear,
|
|
235
|
+
delay: (_d = s.delay) !== null && _d !== void 0 ? _d : 0,
|
|
236
|
+
elapsed: 0,
|
|
237
|
+
done: false,
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
update(e) {
|
|
242
|
+
if (!this.isPlaying || this.running.length === 0)
|
|
243
|
+
return;
|
|
244
|
+
const dt = e.deltaTime;
|
|
245
|
+
if (this.parallel) {
|
|
246
|
+
this.advanceParallel(dt);
|
|
247
|
+
}
|
|
248
|
+
else {
|
|
249
|
+
this.advanceSequence(dt);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
advanceParallel(dt) {
|
|
253
|
+
let allDone = true;
|
|
254
|
+
for (const r of this.running) {
|
|
255
|
+
if (r.done)
|
|
256
|
+
continue;
|
|
257
|
+
this.tickStep(r, dt);
|
|
258
|
+
if (!r.done)
|
|
259
|
+
allDone = false;
|
|
260
|
+
}
|
|
261
|
+
if (allDone)
|
|
262
|
+
this.onCycleEnd();
|
|
263
|
+
}
|
|
264
|
+
advanceSequence(dt) {
|
|
265
|
+
while (dt > 0 && this.cursor < this.running.length) {
|
|
266
|
+
const r = this.running[this.cursor];
|
|
267
|
+
if (r.done) {
|
|
268
|
+
this.cursor++;
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
const before = r.elapsed;
|
|
272
|
+
this.tickStep(r, dt);
|
|
273
|
+
const used = r.elapsed - before;
|
|
274
|
+
dt -= used;
|
|
275
|
+
if (!r.done)
|
|
276
|
+
break;
|
|
277
|
+
this.cursor++;
|
|
278
|
+
}
|
|
279
|
+
if (this.cursor >= this.running.length)
|
|
280
|
+
this.onCycleEnd();
|
|
281
|
+
}
|
|
282
|
+
tickStep(r, dt) {
|
|
283
|
+
if (r.delay > 0) {
|
|
284
|
+
const used = Math.min(r.delay, dt);
|
|
285
|
+
r.delay -= used;
|
|
286
|
+
// 把延时算进 elapsed 不合适,留给 sequence 减 dt
|
|
287
|
+
// 这里直接消耗 dt 后返回
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
r.elapsed += dt;
|
|
291
|
+
const t = Math.min(1, r.elapsed / r.duration);
|
|
292
|
+
const v = r.from + (r.to - r.from) * r.easing(t);
|
|
293
|
+
r.binding.write(v);
|
|
294
|
+
if (t >= 1) {
|
|
295
|
+
r.done = true;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
onCycleEnd() {
|
|
299
|
+
this.playedLoops++;
|
|
300
|
+
const shouldLoop = this.loop === -1 || this.playedLoops <= this.loop;
|
|
301
|
+
if (this.yoyo) {
|
|
302
|
+
this.direction = (this.direction === 1 ? -1 : 1);
|
|
303
|
+
// yoyo:反向重置
|
|
304
|
+
for (const r of this.running) {
|
|
305
|
+
const a = r.from;
|
|
306
|
+
r.from = r.to;
|
|
307
|
+
r.to = a;
|
|
308
|
+
r.elapsed = 0;
|
|
309
|
+
r.done = false;
|
|
310
|
+
}
|
|
311
|
+
this.cursor = 0;
|
|
312
|
+
if (!shouldLoop && this.direction === 1) {
|
|
313
|
+
this.finish();
|
|
314
|
+
}
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
if (shouldLoop) {
|
|
318
|
+
for (const r of this.running) {
|
|
319
|
+
r.elapsed = 0;
|
|
320
|
+
r.done = false;
|
|
321
|
+
}
|
|
322
|
+
this.cursor = 0;
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
this.finish();
|
|
326
|
+
}
|
|
327
|
+
finish() {
|
|
328
|
+
this.isPlaying = false;
|
|
329
|
+
if (this.signal)
|
|
330
|
+
pluginSignalBus.getSignalBus().emit(this.signal, { component: this });
|
|
331
|
+
pluginSignalBus.getSignalBus().emit('tween:finish', { component: this });
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
exports.Tween.componentName = 'Tween';
|
|
335
|
+
exports.Tween = __decorate([
|
|
336
|
+
eva_js.decorators.componentObserver({})
|
|
337
|
+
], exports.Tween);
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Tween 没有跨实体编排,System 仅用于注册 plugin。
|
|
341
|
+
*/
|
|
342
|
+
class TweenSystem extends eva_js.System {
|
|
343
|
+
constructor() {
|
|
344
|
+
super(...arguments);
|
|
345
|
+
this.name = 'Tween';
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
TweenSystem.systemName = 'Tween';
|
|
349
|
+
|
|
350
|
+
exports.Easing = Easing;
|
|
351
|
+
exports.TweenSystem = TweenSystem;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=require("@eva/eva.js"),e=require("@eva/plugin-signal-bus");"function"==typeof SuppressedError&&SuppressedError;const n=Math.PI,i=1.70158,s=1.525*i,o=i+1,r=2*n/3,a=2*n/4.5,l=7.5625,u=2.75;function c(t){return t<1/u?l*t*t:t<2/u?l*(t-=1.5/u)*t+.75:t<2.5/u?l*(t-=2.25/u)*t+.9375:l*(t-=2.625/u)*t+.984375}const h={linear:t=>t,easeInQuad:t=>t*t,easeOutQuad:t=>1-(1-t)*(1-t),easeInOutQuad:t=>t<.5?2*t*t:1-Math.pow(-2*t+2,2)/2,easeInCubic:t=>t*t*t,easeOutCubic:t=>1-Math.pow(1-t,3),easeInOutCubic:t=>t<.5?4*t*t*t:1-Math.pow(-2*t+2,3)/2,easeInElastic:t=>0===t?0:1===t?1:-Math.pow(2,10*t-10)*Math.sin((10*t-10.75)*r),easeOutElastic:t=>0===t?0:1===t?1:Math.pow(2,-10*t)*Math.sin((10*t-.75)*r)+1,easeInOutElastic:t=>0===t?0:1===t?1:t<.5?-Math.pow(2,20*t-10)*Math.sin((20*t-11.125)*a)/2:Math.pow(2,-20*t+10)*Math.sin((20*t-11.125)*a)/2+1,easeInBack:t=>o*t*t*t-i*t*t,easeOutBack:t=>1+o*Math.pow(t-1,3)+i*Math.pow(t-1,2),easeInOutBack:t=>t<.5?Math.pow(2*t,2)*(7.189819*t-s)/2:(Math.pow(2*t-2,2)*((s+1)*(2*t-2)+s)+2)/2,easeInBounce:function(t){return 1-c(1-t)},easeOutBounce:c,easeInOutBounce:t=>t<.5?(1-c(1-2*t))/2:(1+c(2*t-1))/2};function p(t,e){const n=e.split(".");if("transform"===n[0]){return d(t.transform,n.slice(1))}if("components"===n[0]&&n.length>=3){const e=function(t,e){var n,i;const s=t.components||[];for(const t of s){if((null===(n=null==t?void 0:t.constructor)||void 0===n?void 0:n.componentName)===e)return t}if("function"==typeof t.getComponent)return null!==(i=t.getComponent(e))&&void 0!==i?i:null;return null}(t,n[1]);return e?d(e,n.slice(2)):null}return"store"===n[0]&&n.length>=2?function(t){const e=globalThis.mx;return(null==e?void 0:e.store)?{read:()=>{var n,i,s;return Number(null!==(s=null===(i=(n=e.store).get)||void 0===i?void 0:i.call(n,t))&&void 0!==s?s:0)},write:n=>{var i,s;null===(s=(i=e.store).update)||void 0===s||s.call(i,{[t]:n})}}:null}(n.slice(1).join(".")):null}function d(t,e){if(!t||0===e.length)return null;let n=t;for(let t=0;t<e.length-1;t++){const i=e[t];if(null==n[i])return null;n=n[i]}const i=e[e.length-1];return{read:()=>{var t;return Number(null!==(t=n[i])&&void 0!==t?t:0)},write:t=>{n[i]=t}}}exports.Tween=class extends t.Component{constructor(){super(...arguments),this.steps=[],this.parallel=!1,this.yoyo=!1,this.loop=0,this.autostart=!1,this.running=[],this.isPlaying=!1,this.playedLoops=0,this.cursor=0,this.direction=1}init(t){var e,n,i,s,o;t&&(this.steps=t.step?[t.step]:null!==(e=t.steps)&&void 0!==e?e:[],this.parallel=null!==(n=t.parallel)&&void 0!==n&&n,this.yoyo=null!==(i=t.yoyo)&&void 0!==i&&i,this.loop=null!==(s=t.loop)&&void 0!==s?s:0,this.autostart=null!==(o=t.autostart)&&void 0!==o&&o,this.signal=t.signal)}awake(){this.autostart&&this.play()}play(){this.buildRunning(),this.isPlaying=!0,this.playedLoops=0,this.cursor=0,this.direction=1}pause(){this.isPlaying=!1}resume(){this.running.length&&(this.isPlaying=!0)}stop(){this.isPlaying=!1,this.running=[]}buildRunning(){var t,e,n,i;this.running=[];for(const s of this.steps){const o=p(this.gameObject,s.target);if(!o){console.warn(`[plugin-tween] binding miss: ${s.target}`);continue}const r=null!==(t=s.from)&&void 0!==t?t:o.read();this.running.push({binding:o,from:r,to:s.to,duration:Math.max(1,s.duration),easing:null!==(n=h[null!==(e=s.easing)&&void 0!==e?e:"linear"])&&void 0!==n?n:h.linear,delay:null!==(i=s.delay)&&void 0!==i?i:0,elapsed:0,done:!1})}}update(t){if(!this.isPlaying||0===this.running.length)return;const e=t.deltaTime;this.parallel?this.advanceParallel(e):this.advanceSequence(e)}advanceParallel(t){let e=!0;for(const n of this.running)n.done||(this.tickStep(n,t),n.done||(e=!1));e&&this.onCycleEnd()}advanceSequence(t){for(;t>0&&this.cursor<this.running.length;){const e=this.running[this.cursor];if(e.done){this.cursor++;continue}const n=e.elapsed;this.tickStep(e,t);if(t-=e.elapsed-n,!e.done)break;this.cursor++}this.cursor>=this.running.length&&this.onCycleEnd()}tickStep(t,e){if(t.delay>0){const n=Math.min(t.delay,e);return void(t.delay-=n)}t.elapsed+=e;const n=Math.min(1,t.elapsed/t.duration),i=t.from+(t.to-t.from)*t.easing(n);t.binding.write(i),n>=1&&(t.done=!0)}onCycleEnd(){this.playedLoops++;const t=-1===this.loop||this.playedLoops<=this.loop;if(this.yoyo){this.direction=1===this.direction?-1:1;for(const t of this.running){const e=t.from;t.from=t.to,t.to=e,t.elapsed=0,t.done=!1}return this.cursor=0,void(t||1!==this.direction||this.finish())}if(t){for(const t of this.running)t.elapsed=0,t.done=!1;this.cursor=0}else this.finish()}finish(){this.isPlaying=!1,this.signal&&e.getSignalBus().emit(this.signal,{component:this}),e.getSignalBus().emit("tween:finish",{component:this})}},exports.Tween.componentName="Tween",exports.Tween=function(t,e,n,i){var s,o=arguments.length,r=o<3?e:null===i?i=Object.getOwnPropertyDescriptor(e,n):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)r=Reflect.decorate(t,e,n,i);else for(var a=t.length-1;a>=0;a--)(s=t[a])&&(r=(o<3?s(r):o>3?s(e,n,r):s(e,n))||r);return o>3&&r&&Object.defineProperty(e,n,r),r}([t.decorators.componentObserver({})],exports.Tween);class f extends t.System{constructor(){super(...arguments),this.name="Tween"}}f.systemName="Tween",exports.Easing=h,exports.TweenSystem=f;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { Component } from '@eva/eva.js';
|
|
2
|
+
import { System } from '@eva/eva.js';
|
|
3
|
+
|
|
4
|
+
export declare const Easing: Record<EasingName, (t: number) => number>;
|
|
5
|
+
|
|
6
|
+
export declare type EasingName = 'linear' | 'easeInQuad' | 'easeOutQuad' | 'easeInOutQuad' | 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic' | 'easeInElastic' | 'easeOutElastic' | 'easeInOutElastic' | 'easeInBack' | 'easeOutBack' | 'easeInOutBack' | 'easeInBounce' | 'easeOutBounce' | 'easeInOutBounce';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Tween 组件 — Godot Tween 等价物。
|
|
10
|
+
*
|
|
11
|
+
* 与 plugin-transition 区别:
|
|
12
|
+
* - 不限制 target 类型(transform/Component/store 都行)
|
|
13
|
+
* - 内置 sequence 与 parallel 编排
|
|
14
|
+
* - 完成 emit 命名信号
|
|
15
|
+
*
|
|
16
|
+
* DSL 用法:
|
|
17
|
+
* ```json
|
|
18
|
+
* {
|
|
19
|
+
* "type": "Tween",
|
|
20
|
+
* "props": {
|
|
21
|
+
* "step": {
|
|
22
|
+
* "target": "components.RocketAimer.currentAngleDeg",
|
|
23
|
+
* "from": -60, "to": 60, "duration": 1500, "easing": "easeInOutQuad"
|
|
24
|
+
* },
|
|
25
|
+
* "yoyo": true, "loop": -1, "autostart": true
|
|
26
|
+
* }
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare class Tween extends Component<TweenParams> {
|
|
31
|
+
static componentName: string;
|
|
32
|
+
private steps;
|
|
33
|
+
private parallel;
|
|
34
|
+
private yoyo;
|
|
35
|
+
private loop;
|
|
36
|
+
private autostart;
|
|
37
|
+
private signal?;
|
|
38
|
+
private running;
|
|
39
|
+
private isPlaying;
|
|
40
|
+
private playedLoops;
|
|
41
|
+
private cursor;
|
|
42
|
+
private direction;
|
|
43
|
+
init(params?: TweenParams): void;
|
|
44
|
+
awake(): void;
|
|
45
|
+
/** 重新开始 */
|
|
46
|
+
play(): void;
|
|
47
|
+
pause(): void;
|
|
48
|
+
resume(): void;
|
|
49
|
+
stop(): void;
|
|
50
|
+
private buildRunning;
|
|
51
|
+
update(e: {
|
|
52
|
+
deltaTime: number;
|
|
53
|
+
}): void;
|
|
54
|
+
private advanceParallel;
|
|
55
|
+
private advanceSequence;
|
|
56
|
+
private tickStep;
|
|
57
|
+
private onCycleEnd;
|
|
58
|
+
private finish;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export declare interface TweenParams {
|
|
62
|
+
/** 单步 = 一次性 to;steps = 多步序列 */
|
|
63
|
+
step?: TweenStep;
|
|
64
|
+
steps?: TweenStep[];
|
|
65
|
+
/** 是否并行执行 steps(默认 sequence) */
|
|
66
|
+
parallel?: boolean;
|
|
67
|
+
yoyo?: boolean;
|
|
68
|
+
/** -1 = 无限循环 */
|
|
69
|
+
loop?: number;
|
|
70
|
+
/** 是否自动开始 */
|
|
71
|
+
autostart?: boolean;
|
|
72
|
+
/** 完成后 emit 的信号 */
|
|
73
|
+
signal?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export declare interface TweenStep {
|
|
77
|
+
/** 目标路径,例如:
|
|
78
|
+
* - "transform.position.x"
|
|
79
|
+
* - "transform.rotation"
|
|
80
|
+
* - "components.RocketAimer.currentAngleDeg"
|
|
81
|
+
* - "store.score" (走 mx.store)
|
|
82
|
+
*/
|
|
83
|
+
target: string;
|
|
84
|
+
from?: number;
|
|
85
|
+
to: number;
|
|
86
|
+
duration: number;
|
|
87
|
+
easing?: EasingName;
|
|
88
|
+
delay?: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Tween 没有跨实体编排,System 仅用于注册 plugin。
|
|
93
|
+
*/
|
|
94
|
+
export declare class TweenSystem extends System {
|
|
95
|
+
static systemName: string;
|
|
96
|
+
readonly name = "Tween";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export { }
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
import { Component, decorators, System } from '@eva/eva.js';
|
|
2
|
+
import { getSignalBus } from '@eva/plugin-signal-bus';
|
|
3
|
+
|
|
4
|
+
/******************************************************************************
|
|
5
|
+
Copyright (c) Microsoft Corporation.
|
|
6
|
+
|
|
7
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
8
|
+
purpose with or without fee is hereby granted.
|
|
9
|
+
|
|
10
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
11
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
12
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
13
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
14
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
15
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
16
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
17
|
+
***************************************************************************** */
|
|
18
|
+
|
|
19
|
+
function __decorate(decorators, target, key, desc) {
|
|
20
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
21
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
22
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
23
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
27
|
+
var e = new Error(message);
|
|
28
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const PI = Math.PI;
|
|
32
|
+
const c1 = 1.70158;
|
|
33
|
+
const c2 = c1 * 1.525;
|
|
34
|
+
const c3 = c1 + 1;
|
|
35
|
+
const c4 = (2 * PI) / 3;
|
|
36
|
+
const c5 = (2 * PI) / 4.5;
|
|
37
|
+
const n1 = 7.5625;
|
|
38
|
+
const d1 = 2.75;
|
|
39
|
+
function easeInBounce(x) {
|
|
40
|
+
return 1 - easeOutBounce(1 - x);
|
|
41
|
+
}
|
|
42
|
+
function easeOutBounce(x) {
|
|
43
|
+
if (x < 1 / d1)
|
|
44
|
+
return n1 * x * x;
|
|
45
|
+
if (x < 2 / d1)
|
|
46
|
+
return n1 * (x -= 1.5 / d1) * x + 0.75;
|
|
47
|
+
if (x < 2.5 / d1)
|
|
48
|
+
return n1 * (x -= 2.25 / d1) * x + 0.9375;
|
|
49
|
+
return n1 * (x -= 2.625 / d1) * x + 0.984375;
|
|
50
|
+
}
|
|
51
|
+
const Easing = {
|
|
52
|
+
linear: (t) => t,
|
|
53
|
+
easeInQuad: (t) => t * t,
|
|
54
|
+
easeOutQuad: (t) => 1 - (1 - t) * (1 - t),
|
|
55
|
+
easeInOutQuad: (t) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2),
|
|
56
|
+
easeInCubic: (t) => t * t * t,
|
|
57
|
+
easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),
|
|
58
|
+
easeInOutCubic: (t) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2),
|
|
59
|
+
easeInElastic: (t) => (t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * c4)),
|
|
60
|
+
easeOutElastic: (t) => (t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1),
|
|
61
|
+
easeInOutElastic: (t) => {
|
|
62
|
+
if (t === 0)
|
|
63
|
+
return 0;
|
|
64
|
+
if (t === 1)
|
|
65
|
+
return 1;
|
|
66
|
+
return t < 0.5
|
|
67
|
+
? -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * c5)) / 2
|
|
68
|
+
: (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * c5)) / 2 + 1;
|
|
69
|
+
},
|
|
70
|
+
easeInBack: (t) => c3 * t * t * t - c1 * t * t,
|
|
71
|
+
easeOutBack: (t) => 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2),
|
|
72
|
+
easeInOutBack: (t) => t < 0.5
|
|
73
|
+
? (Math.pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2
|
|
74
|
+
: (Math.pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2,
|
|
75
|
+
easeInBounce,
|
|
76
|
+
easeOutBounce,
|
|
77
|
+
easeInOutBounce: (t) => (t < 0.5 ? (1 - easeOutBounce(1 - 2 * t)) / 2 : (1 + easeOutBounce(2 * t - 1)) / 2),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
function bindPath(go, path) {
|
|
81
|
+
const parts = path.split('.');
|
|
82
|
+
if (parts[0] === 'transform') {
|
|
83
|
+
const obj = go.transform;
|
|
84
|
+
return diveIntoObject(obj, parts.slice(1));
|
|
85
|
+
}
|
|
86
|
+
if (parts[0] === 'components' && parts.length >= 3) {
|
|
87
|
+
const compName = parts[1];
|
|
88
|
+
const comp = findComponent(go, compName);
|
|
89
|
+
if (!comp)
|
|
90
|
+
return null;
|
|
91
|
+
return diveIntoObject(comp, parts.slice(2));
|
|
92
|
+
}
|
|
93
|
+
if (parts[0] === 'store' && parts.length >= 2) {
|
|
94
|
+
return bindStore(parts.slice(1).join('.'));
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
function diveIntoObject(root, keys) {
|
|
99
|
+
if (!root || keys.length === 0)
|
|
100
|
+
return null;
|
|
101
|
+
let parent = root;
|
|
102
|
+
for (let i = 0; i < keys.length - 1; i++) {
|
|
103
|
+
const k = keys[i];
|
|
104
|
+
if (parent[k] == null)
|
|
105
|
+
return null;
|
|
106
|
+
parent = parent[k];
|
|
107
|
+
}
|
|
108
|
+
const last = keys[keys.length - 1];
|
|
109
|
+
return {
|
|
110
|
+
read: () => { var _a; return Number((_a = parent[last]) !== null && _a !== void 0 ? _a : 0); },
|
|
111
|
+
write: (v) => {
|
|
112
|
+
parent[last] = v;
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
function findComponent(go, name) {
|
|
117
|
+
var _a, _b;
|
|
118
|
+
const comps = go.components || [];
|
|
119
|
+
for (const c of comps) {
|
|
120
|
+
const cn = (_a = c === null || c === void 0 ? void 0 : c.constructor) === null || _a === void 0 ? void 0 : _a.componentName;
|
|
121
|
+
if (cn === name)
|
|
122
|
+
return c;
|
|
123
|
+
}
|
|
124
|
+
// 退路:Eva.js 部分版本支持 getComponent(name)
|
|
125
|
+
if (typeof go.getComponent === 'function') {
|
|
126
|
+
return (_b = go.getComponent(name)) !== null && _b !== void 0 ? _b : null;
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
function bindStore(key) {
|
|
131
|
+
// mx.store 是宿主全局,不强依赖
|
|
132
|
+
const mx = globalThis.mx;
|
|
133
|
+
if (!(mx === null || mx === void 0 ? void 0 : mx.store))
|
|
134
|
+
return null;
|
|
135
|
+
return {
|
|
136
|
+
read: () => { var _a, _b, _c; return Number((_c = (_b = (_a = mx.store).get) === null || _b === void 0 ? void 0 : _b.call(_a, key)) !== null && _c !== void 0 ? _c : 0); },
|
|
137
|
+
write: (v) => {
|
|
138
|
+
var _a, _b;
|
|
139
|
+
(_b = (_a = mx.store).update) === null || _b === void 0 ? void 0 : _b.call(_a, { [key]: v });
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Tween 组件 — Godot Tween 等价物。
|
|
146
|
+
*
|
|
147
|
+
* 与 plugin-transition 区别:
|
|
148
|
+
* - 不限制 target 类型(transform/Component/store 都行)
|
|
149
|
+
* - 内置 sequence 与 parallel 编排
|
|
150
|
+
* - 完成 emit 命名信号
|
|
151
|
+
*
|
|
152
|
+
* DSL 用法:
|
|
153
|
+
* ```json
|
|
154
|
+
* {
|
|
155
|
+
* "type": "Tween",
|
|
156
|
+
* "props": {
|
|
157
|
+
* "step": {
|
|
158
|
+
* "target": "components.RocketAimer.currentAngleDeg",
|
|
159
|
+
* "from": -60, "to": 60, "duration": 1500, "easing": "easeInOutQuad"
|
|
160
|
+
* },
|
|
161
|
+
* "yoyo": true, "loop": -1, "autostart": true
|
|
162
|
+
* }
|
|
163
|
+
* }
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
let Tween = class Tween extends Component {
|
|
167
|
+
constructor() {
|
|
168
|
+
super(...arguments);
|
|
169
|
+
this.steps = [];
|
|
170
|
+
this.parallel = false;
|
|
171
|
+
this.yoyo = false;
|
|
172
|
+
this.loop = 0;
|
|
173
|
+
this.autostart = false;
|
|
174
|
+
this.running = [];
|
|
175
|
+
this.isPlaying = false;
|
|
176
|
+
this.playedLoops = 0;
|
|
177
|
+
this.cursor = 0; // sequence 当前 step
|
|
178
|
+
this.direction = 1;
|
|
179
|
+
}
|
|
180
|
+
init(params) {
|
|
181
|
+
var _a, _b, _c, _d, _e;
|
|
182
|
+
if (!params)
|
|
183
|
+
return;
|
|
184
|
+
this.steps = params.step ? [params.step] : ((_a = params.steps) !== null && _a !== void 0 ? _a : []);
|
|
185
|
+
this.parallel = (_b = params.parallel) !== null && _b !== void 0 ? _b : false;
|
|
186
|
+
this.yoyo = (_c = params.yoyo) !== null && _c !== void 0 ? _c : false;
|
|
187
|
+
this.loop = (_d = params.loop) !== null && _d !== void 0 ? _d : 0;
|
|
188
|
+
this.autostart = (_e = params.autostart) !== null && _e !== void 0 ? _e : false;
|
|
189
|
+
this.signal = params.signal;
|
|
190
|
+
}
|
|
191
|
+
awake() {
|
|
192
|
+
if (this.autostart)
|
|
193
|
+
this.play();
|
|
194
|
+
}
|
|
195
|
+
/** 重新开始 */
|
|
196
|
+
play() {
|
|
197
|
+
this.buildRunning();
|
|
198
|
+
this.isPlaying = true;
|
|
199
|
+
this.playedLoops = 0;
|
|
200
|
+
this.cursor = 0;
|
|
201
|
+
this.direction = 1;
|
|
202
|
+
}
|
|
203
|
+
pause() {
|
|
204
|
+
this.isPlaying = false;
|
|
205
|
+
}
|
|
206
|
+
resume() {
|
|
207
|
+
if (this.running.length)
|
|
208
|
+
this.isPlaying = true;
|
|
209
|
+
}
|
|
210
|
+
stop() {
|
|
211
|
+
this.isPlaying = false;
|
|
212
|
+
this.running = [];
|
|
213
|
+
}
|
|
214
|
+
buildRunning() {
|
|
215
|
+
var _a, _b, _c, _d;
|
|
216
|
+
this.running = [];
|
|
217
|
+
for (const s of this.steps) {
|
|
218
|
+
const binding = bindPath(this.gameObject, s.target);
|
|
219
|
+
if (!binding) {
|
|
220
|
+
// eslint-disable-next-line no-console
|
|
221
|
+
console.warn(`[plugin-tween] binding miss: ${s.target}`);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
const from = (_a = s.from) !== null && _a !== void 0 ? _a : binding.read();
|
|
225
|
+
this.running.push({
|
|
226
|
+
binding,
|
|
227
|
+
from,
|
|
228
|
+
to: s.to,
|
|
229
|
+
duration: Math.max(1, s.duration),
|
|
230
|
+
easing: (_c = Easing[((_b = s.easing) !== null && _b !== void 0 ? _b : 'linear')]) !== null && _c !== void 0 ? _c : Easing.linear,
|
|
231
|
+
delay: (_d = s.delay) !== null && _d !== void 0 ? _d : 0,
|
|
232
|
+
elapsed: 0,
|
|
233
|
+
done: false,
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
update(e) {
|
|
238
|
+
if (!this.isPlaying || this.running.length === 0)
|
|
239
|
+
return;
|
|
240
|
+
const dt = e.deltaTime;
|
|
241
|
+
if (this.parallel) {
|
|
242
|
+
this.advanceParallel(dt);
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
this.advanceSequence(dt);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
advanceParallel(dt) {
|
|
249
|
+
let allDone = true;
|
|
250
|
+
for (const r of this.running) {
|
|
251
|
+
if (r.done)
|
|
252
|
+
continue;
|
|
253
|
+
this.tickStep(r, dt);
|
|
254
|
+
if (!r.done)
|
|
255
|
+
allDone = false;
|
|
256
|
+
}
|
|
257
|
+
if (allDone)
|
|
258
|
+
this.onCycleEnd();
|
|
259
|
+
}
|
|
260
|
+
advanceSequence(dt) {
|
|
261
|
+
while (dt > 0 && this.cursor < this.running.length) {
|
|
262
|
+
const r = this.running[this.cursor];
|
|
263
|
+
if (r.done) {
|
|
264
|
+
this.cursor++;
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
const before = r.elapsed;
|
|
268
|
+
this.tickStep(r, dt);
|
|
269
|
+
const used = r.elapsed - before;
|
|
270
|
+
dt -= used;
|
|
271
|
+
if (!r.done)
|
|
272
|
+
break;
|
|
273
|
+
this.cursor++;
|
|
274
|
+
}
|
|
275
|
+
if (this.cursor >= this.running.length)
|
|
276
|
+
this.onCycleEnd();
|
|
277
|
+
}
|
|
278
|
+
tickStep(r, dt) {
|
|
279
|
+
if (r.delay > 0) {
|
|
280
|
+
const used = Math.min(r.delay, dt);
|
|
281
|
+
r.delay -= used;
|
|
282
|
+
// 把延时算进 elapsed 不合适,留给 sequence 减 dt
|
|
283
|
+
// 这里直接消耗 dt 后返回
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
r.elapsed += dt;
|
|
287
|
+
const t = Math.min(1, r.elapsed / r.duration);
|
|
288
|
+
const v = r.from + (r.to - r.from) * r.easing(t);
|
|
289
|
+
r.binding.write(v);
|
|
290
|
+
if (t >= 1) {
|
|
291
|
+
r.done = true;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
onCycleEnd() {
|
|
295
|
+
this.playedLoops++;
|
|
296
|
+
const shouldLoop = this.loop === -1 || this.playedLoops <= this.loop;
|
|
297
|
+
if (this.yoyo) {
|
|
298
|
+
this.direction = (this.direction === 1 ? -1 : 1);
|
|
299
|
+
// yoyo:反向重置
|
|
300
|
+
for (const r of this.running) {
|
|
301
|
+
const a = r.from;
|
|
302
|
+
r.from = r.to;
|
|
303
|
+
r.to = a;
|
|
304
|
+
r.elapsed = 0;
|
|
305
|
+
r.done = false;
|
|
306
|
+
}
|
|
307
|
+
this.cursor = 0;
|
|
308
|
+
if (!shouldLoop && this.direction === 1) {
|
|
309
|
+
this.finish();
|
|
310
|
+
}
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (shouldLoop) {
|
|
314
|
+
for (const r of this.running) {
|
|
315
|
+
r.elapsed = 0;
|
|
316
|
+
r.done = false;
|
|
317
|
+
}
|
|
318
|
+
this.cursor = 0;
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
this.finish();
|
|
322
|
+
}
|
|
323
|
+
finish() {
|
|
324
|
+
this.isPlaying = false;
|
|
325
|
+
if (this.signal)
|
|
326
|
+
getSignalBus().emit(this.signal, { component: this });
|
|
327
|
+
getSignalBus().emit('tween:finish', { component: this });
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
Tween.componentName = 'Tween';
|
|
331
|
+
Tween = __decorate([
|
|
332
|
+
decorators.componentObserver({})
|
|
333
|
+
], Tween);
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Tween 没有跨实体编排,System 仅用于注册 plugin。
|
|
337
|
+
*/
|
|
338
|
+
class TweenSystem extends System {
|
|
339
|
+
constructor() {
|
|
340
|
+
super(...arguments);
|
|
341
|
+
this.name = 'Tween';
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
TweenSystem.systemName = 'Tween';
|
|
345
|
+
|
|
346
|
+
export { Easing, Tween, TweenSystem };
|
package/index.js
ADDED
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eva/plugin-tween",
|
|
3
|
-
"version": "2.1.0-beta.
|
|
3
|
+
"version": "2.1.0-beta.3",
|
|
4
4
|
"description": "Godot Tween 等价物 — 任意字段补间(transform / 自定义 Component / mx.store),支持 sequence/parallel/yoyo/loop。",
|
|
5
|
-
"main": "
|
|
6
|
-
"module": "
|
|
7
|
-
"types": "
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"module": "dist/plugin-tween.esm.js",
|
|
7
|
+
"types": "dist/plugin-tween.d.ts",
|
|
8
8
|
"files": [
|
|
9
|
-
"
|
|
9
|
+
"index.js",
|
|
10
|
+
"dist"
|
|
10
11
|
],
|
|
11
12
|
"keywords": [
|
|
12
13
|
"eva.js",
|
|
@@ -16,7 +17,7 @@
|
|
|
16
17
|
],
|
|
17
18
|
"license": "MIT",
|
|
18
19
|
"dependencies": {
|
|
19
|
-
"@eva/eva.js": "2.1.0-beta.
|
|
20
|
-
"@eva/plugin-signal-bus": "2.1.0-beta.
|
|
20
|
+
"@eva/eva.js": "2.1.0-beta.3",
|
|
21
|
+
"@eva/plugin-signal-bus": "2.1.0-beta.3"
|
|
21
22
|
}
|
|
22
23
|
}
|
package/lib/Tween.ts
DELETED
|
@@ -1,206 +0,0 @@
|
|
|
1
|
-
import { Component, decorators } from '@eva/eva.js';
|
|
2
|
-
import { getSignalBus } from '@eva/plugin-signal-bus';
|
|
3
|
-
import { Easing } from './easing';
|
|
4
|
-
import { bindPath, PathBinding } from './path';
|
|
5
|
-
import type { TweenParams, TweenStep, EasingName } from './types';
|
|
6
|
-
|
|
7
|
-
interface RunningStep {
|
|
8
|
-
binding: PathBinding;
|
|
9
|
-
from: number;
|
|
10
|
-
to: number;
|
|
11
|
-
duration: number;
|
|
12
|
-
easing: (t: number) => number;
|
|
13
|
-
delay: number;
|
|
14
|
-
elapsed: number;
|
|
15
|
-
done: boolean;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Tween 组件 — Godot Tween 等价物。
|
|
20
|
-
*
|
|
21
|
-
* 与 plugin-transition 区别:
|
|
22
|
-
* - 不限制 target 类型(transform/Component/store 都行)
|
|
23
|
-
* - 内置 sequence 与 parallel 编排
|
|
24
|
-
* - 完成 emit 命名信号
|
|
25
|
-
*
|
|
26
|
-
* DSL 用法:
|
|
27
|
-
* ```json
|
|
28
|
-
* {
|
|
29
|
-
* "type": "Tween",
|
|
30
|
-
* "props": {
|
|
31
|
-
* "step": {
|
|
32
|
-
* "target": "components.RocketAimer.currentAngleDeg",
|
|
33
|
-
* "from": -60, "to": 60, "duration": 1500, "easing": "easeInOutQuad"
|
|
34
|
-
* },
|
|
35
|
-
* "yoyo": true, "loop": -1, "autostart": true
|
|
36
|
-
* }
|
|
37
|
-
* }
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
|
-
@decorators.componentObserver({})
|
|
41
|
-
export class Tween extends Component<TweenParams> {
|
|
42
|
-
static componentName = 'Tween';
|
|
43
|
-
|
|
44
|
-
private steps: TweenStep[] = [];
|
|
45
|
-
private parallel = false;
|
|
46
|
-
private yoyo = false;
|
|
47
|
-
private loop = 0;
|
|
48
|
-
private autostart = false;
|
|
49
|
-
private signal?: string;
|
|
50
|
-
|
|
51
|
-
private running: RunningStep[] = [];
|
|
52
|
-
private isPlaying = false;
|
|
53
|
-
private playedLoops = 0;
|
|
54
|
-
private cursor = 0; // sequence 当前 step
|
|
55
|
-
private direction: 1 | -1 = 1;
|
|
56
|
-
|
|
57
|
-
init(params?: TweenParams) {
|
|
58
|
-
if (!params) return;
|
|
59
|
-
this.steps = params.step ? [params.step] : (params.steps ?? []);
|
|
60
|
-
this.parallel = params.parallel ?? false;
|
|
61
|
-
this.yoyo = params.yoyo ?? false;
|
|
62
|
-
this.loop = params.loop ?? 0;
|
|
63
|
-
this.autostart = params.autostart ?? false;
|
|
64
|
-
this.signal = params.signal;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
awake() {
|
|
68
|
-
if (this.autostart) this.play();
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** 重新开始 */
|
|
72
|
-
play() {
|
|
73
|
-
this.buildRunning();
|
|
74
|
-
this.isPlaying = true;
|
|
75
|
-
this.playedLoops = 0;
|
|
76
|
-
this.cursor = 0;
|
|
77
|
-
this.direction = 1;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
pause() {
|
|
81
|
-
this.isPlaying = false;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
resume() {
|
|
85
|
-
if (this.running.length) this.isPlaying = true;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
stop() {
|
|
89
|
-
this.isPlaying = false;
|
|
90
|
-
this.running = [];
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
private buildRunning() {
|
|
94
|
-
this.running = [];
|
|
95
|
-
for (const s of this.steps) {
|
|
96
|
-
const binding = bindPath(this.gameObject, s.target);
|
|
97
|
-
if (!binding) {
|
|
98
|
-
// eslint-disable-next-line no-console
|
|
99
|
-
console.warn(`[plugin-tween] binding miss: ${s.target}`);
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
const from = s.from ?? binding.read();
|
|
103
|
-
this.running.push({
|
|
104
|
-
binding,
|
|
105
|
-
from,
|
|
106
|
-
to: s.to,
|
|
107
|
-
duration: Math.max(1, s.duration),
|
|
108
|
-
easing: Easing[(s.easing ?? 'linear') as EasingName] ?? Easing.linear,
|
|
109
|
-
delay: s.delay ?? 0,
|
|
110
|
-
elapsed: 0,
|
|
111
|
-
done: false,
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
update(e: { deltaTime: number }) {
|
|
117
|
-
if (!this.isPlaying || this.running.length === 0) return;
|
|
118
|
-
const dt = e.deltaTime;
|
|
119
|
-
|
|
120
|
-
if (this.parallel) {
|
|
121
|
-
this.advanceParallel(dt);
|
|
122
|
-
} else {
|
|
123
|
-
this.advanceSequence(dt);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
private advanceParallel(dt: number) {
|
|
128
|
-
let allDone = true;
|
|
129
|
-
for (const r of this.running) {
|
|
130
|
-
if (r.done) continue;
|
|
131
|
-
this.tickStep(r, dt);
|
|
132
|
-
if (!r.done) allDone = false;
|
|
133
|
-
}
|
|
134
|
-
if (allDone) this.onCycleEnd();
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
private advanceSequence(dt: number) {
|
|
138
|
-
while (dt > 0 && this.cursor < this.running.length) {
|
|
139
|
-
const r = this.running[this.cursor];
|
|
140
|
-
if (r.done) {
|
|
141
|
-
this.cursor++;
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
const before = r.elapsed;
|
|
145
|
-
this.tickStep(r, dt);
|
|
146
|
-
const used = r.elapsed - before;
|
|
147
|
-
dt -= used;
|
|
148
|
-
if (!r.done) break;
|
|
149
|
-
this.cursor++;
|
|
150
|
-
}
|
|
151
|
-
if (this.cursor >= this.running.length) this.onCycleEnd();
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
private tickStep(r: RunningStep, dt: number) {
|
|
155
|
-
if (r.delay > 0) {
|
|
156
|
-
const used = Math.min(r.delay, dt);
|
|
157
|
-
r.delay -= used;
|
|
158
|
-
// 把延时算进 elapsed 不合适,留给 sequence 减 dt
|
|
159
|
-
// 这里直接消耗 dt 后返回
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
r.elapsed += dt;
|
|
163
|
-
const t = Math.min(1, r.elapsed / r.duration);
|
|
164
|
-
const v = r.from + (r.to - r.from) * r.easing(t);
|
|
165
|
-
r.binding.write(v);
|
|
166
|
-
if (t >= 1) {
|
|
167
|
-
r.done = true;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
private onCycleEnd() {
|
|
172
|
-
this.playedLoops++;
|
|
173
|
-
const shouldLoop = this.loop === -1 || this.playedLoops <= this.loop;
|
|
174
|
-
if (this.yoyo) {
|
|
175
|
-
this.direction = (this.direction === 1 ? -1 : 1) as 1 | -1;
|
|
176
|
-
// yoyo:反向重置
|
|
177
|
-
for (const r of this.running) {
|
|
178
|
-
const a = r.from;
|
|
179
|
-
r.from = r.to;
|
|
180
|
-
r.to = a;
|
|
181
|
-
r.elapsed = 0;
|
|
182
|
-
r.done = false;
|
|
183
|
-
}
|
|
184
|
-
this.cursor = 0;
|
|
185
|
-
if (!shouldLoop && this.direction === 1) {
|
|
186
|
-
this.finish();
|
|
187
|
-
}
|
|
188
|
-
return;
|
|
189
|
-
}
|
|
190
|
-
if (shouldLoop) {
|
|
191
|
-
for (const r of this.running) {
|
|
192
|
-
r.elapsed = 0;
|
|
193
|
-
r.done = false;
|
|
194
|
-
}
|
|
195
|
-
this.cursor = 0;
|
|
196
|
-
return;
|
|
197
|
-
}
|
|
198
|
-
this.finish();
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
private finish() {
|
|
202
|
-
this.isPlaying = false;
|
|
203
|
-
if (this.signal) getSignalBus().emit(this.signal, { component: this });
|
|
204
|
-
getSignalBus().emit('tween:finish', { component: this });
|
|
205
|
-
}
|
|
206
|
-
}
|
package/lib/TweenSystem.ts
DELETED
package/lib/easing.ts
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import type { EasingName } from './types';
|
|
2
|
-
|
|
3
|
-
const PI = Math.PI;
|
|
4
|
-
const c1 = 1.70158;
|
|
5
|
-
const c2 = c1 * 1.525;
|
|
6
|
-
const c3 = c1 + 1;
|
|
7
|
-
const c4 = (2 * PI) / 3;
|
|
8
|
-
const c5 = (2 * PI) / 4.5;
|
|
9
|
-
const n1 = 7.5625;
|
|
10
|
-
const d1 = 2.75;
|
|
11
|
-
|
|
12
|
-
function easeInBounce(x: number): number {
|
|
13
|
-
return 1 - easeOutBounce(1 - x);
|
|
14
|
-
}
|
|
15
|
-
function easeOutBounce(x: number): number {
|
|
16
|
-
if (x < 1 / d1) return n1 * x * x;
|
|
17
|
-
if (x < 2 / d1) return n1 * (x -= 1.5 / d1) * x + 0.75;
|
|
18
|
-
if (x < 2.5 / d1) return n1 * (x -= 2.25 / d1) * x + 0.9375;
|
|
19
|
-
return n1 * (x -= 2.625 / d1) * x + 0.984375;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export const Easing: Record<EasingName, (t: number) => number> = {
|
|
23
|
-
linear: (t) => t,
|
|
24
|
-
easeInQuad: (t) => t * t,
|
|
25
|
-
easeOutQuad: (t) => 1 - (1 - t) * (1 - t),
|
|
26
|
-
easeInOutQuad: (t) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2),
|
|
27
|
-
easeInCubic: (t) => t * t * t,
|
|
28
|
-
easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),
|
|
29
|
-
easeInOutCubic: (t) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2),
|
|
30
|
-
easeInElastic: (t) => (t === 0 ? 0 : t === 1 ? 1 : -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * c4)),
|
|
31
|
-
easeOutElastic: (t) => (t === 0 ? 0 : t === 1 ? 1 : Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1),
|
|
32
|
-
easeInOutElastic: (t) => {
|
|
33
|
-
if (t === 0) return 0;
|
|
34
|
-
if (t === 1) return 1;
|
|
35
|
-
return t < 0.5
|
|
36
|
-
? -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * c5)) / 2
|
|
37
|
-
: (Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * c5)) / 2 + 1;
|
|
38
|
-
},
|
|
39
|
-
easeInBack: (t) => c3 * t * t * t - c1 * t * t,
|
|
40
|
-
easeOutBack: (t) => 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2),
|
|
41
|
-
easeInOutBack: (t) =>
|
|
42
|
-
t < 0.5
|
|
43
|
-
? (Math.pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2)) / 2
|
|
44
|
-
: (Math.pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2,
|
|
45
|
-
easeInBounce,
|
|
46
|
-
easeOutBounce,
|
|
47
|
-
easeInOutBounce: (t) => (t < 0.5 ? (1 - easeOutBounce(1 - 2 * t)) / 2 : (1 + easeOutBounce(2 * t - 1)) / 2),
|
|
48
|
-
};
|
package/lib/index.ts
DELETED
package/lib/path.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import type { Component, GameObject } from '@eva/eva.js';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 把字符串路径解析成 (target, key) 二元组,以便就地写入。
|
|
5
|
-
*
|
|
6
|
-
* 支持:
|
|
7
|
-
* - "transform.position.x"
|
|
8
|
-
* - "transform.rotation"
|
|
9
|
-
* - "components.<ComponentName>.<key>" // 通过 componentName 找
|
|
10
|
-
* - "store.<keyPath>" // 走 mx.store(若存在)
|
|
11
|
-
*/
|
|
12
|
-
export interface PathBinding {
|
|
13
|
-
read(): number;
|
|
14
|
-
write(v: number): void;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function bindPath(go: GameObject, path: string): PathBinding | null {
|
|
18
|
-
const parts = path.split('.');
|
|
19
|
-
if (parts[0] === 'transform') {
|
|
20
|
-
const obj = go.transform as any;
|
|
21
|
-
return diveIntoObject(obj, parts.slice(1));
|
|
22
|
-
}
|
|
23
|
-
if (parts[0] === 'components' && parts.length >= 3) {
|
|
24
|
-
const compName = parts[1];
|
|
25
|
-
const comp = findComponent(go, compName);
|
|
26
|
-
if (!comp) return null;
|
|
27
|
-
return diveIntoObject(comp as any, parts.slice(2));
|
|
28
|
-
}
|
|
29
|
-
if (parts[0] === 'store' && parts.length >= 2) {
|
|
30
|
-
return bindStore(parts.slice(1).join('.'));
|
|
31
|
-
}
|
|
32
|
-
return null;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function diveIntoObject(root: any, keys: string[]): PathBinding | null {
|
|
36
|
-
if (!root || keys.length === 0) return null;
|
|
37
|
-
let parent = root;
|
|
38
|
-
for (let i = 0; i < keys.length - 1; i++) {
|
|
39
|
-
const k = keys[i];
|
|
40
|
-
if (parent[k] == null) return null;
|
|
41
|
-
parent = parent[k];
|
|
42
|
-
}
|
|
43
|
-
const last = keys[keys.length - 1];
|
|
44
|
-
return {
|
|
45
|
-
read: () => Number(parent[last] ?? 0),
|
|
46
|
-
write: (v: number) => {
|
|
47
|
-
parent[last] = v;
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function findComponent(go: GameObject, name: string): Component | null {
|
|
53
|
-
const comps: any[] = (go as any).components || [];
|
|
54
|
-
for (const c of comps) {
|
|
55
|
-
const cn = c?.constructor?.componentName;
|
|
56
|
-
if (cn === name) return c;
|
|
57
|
-
}
|
|
58
|
-
// 退路:Eva.js 部分版本支持 getComponent(name)
|
|
59
|
-
if (typeof (go as any).getComponent === 'function') {
|
|
60
|
-
return ((go as any).getComponent(name) as Component) ?? null;
|
|
61
|
-
}
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function bindStore(key: string): PathBinding | null {
|
|
66
|
-
// mx.store 是宿主全局,不强依赖
|
|
67
|
-
const mx: any = (globalThis as any).mx;
|
|
68
|
-
if (!mx?.store) return null;
|
|
69
|
-
return {
|
|
70
|
-
read: () => Number(mx.store.get?.(key) ?? 0),
|
|
71
|
-
write: (v: number) => {
|
|
72
|
-
mx.store.update?.({ [key]: v });
|
|
73
|
-
},
|
|
74
|
-
};
|
|
75
|
-
}
|
package/lib/types.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
export type EasingName =
|
|
2
|
-
| 'linear'
|
|
3
|
-
| 'easeInQuad' | 'easeOutQuad' | 'easeInOutQuad'
|
|
4
|
-
| 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic'
|
|
5
|
-
| 'easeInElastic' | 'easeOutElastic' | 'easeInOutElastic'
|
|
6
|
-
| 'easeInBack' | 'easeOutBack' | 'easeInOutBack'
|
|
7
|
-
| 'easeInBounce' | 'easeOutBounce' | 'easeInOutBounce';
|
|
8
|
-
|
|
9
|
-
export interface TweenStep {
|
|
10
|
-
/** 目标路径,例如:
|
|
11
|
-
* - "transform.position.x"
|
|
12
|
-
* - "transform.rotation"
|
|
13
|
-
* - "components.RocketAimer.currentAngleDeg"
|
|
14
|
-
* - "store.score" (走 mx.store)
|
|
15
|
-
*/
|
|
16
|
-
target: string;
|
|
17
|
-
from?: number;
|
|
18
|
-
to: number;
|
|
19
|
-
duration: number;
|
|
20
|
-
easing?: EasingName;
|
|
21
|
-
delay?: number;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export interface TweenParams {
|
|
25
|
-
/** 单步 = 一次性 to;steps = 多步序列 */
|
|
26
|
-
step?: TweenStep;
|
|
27
|
-
steps?: TweenStep[];
|
|
28
|
-
/** 是否并行执行 steps(默认 sequence) */
|
|
29
|
-
parallel?: boolean;
|
|
30
|
-
yoyo?: boolean;
|
|
31
|
-
/** -1 = 无限循环 */
|
|
32
|
-
loop?: number;
|
|
33
|
-
/** 是否自动开始 */
|
|
34
|
-
autostart?: boolean;
|
|
35
|
-
/** 完成后 emit 的信号 */
|
|
36
|
-
signal?: string;
|
|
37
|
-
}
|