* refactor: reorganize package structure and decouple framework packages ## Package Structure Reorganization - Reorganized 55 packages into categorized subdirectories: - packages/framework/ - Generic framework (Laya/Cocos compatible) - packages/engine/ - ESEngine core modules - packages/rendering/ - Rendering modules (WASM dependent) - packages/physics/ - Physics modules - packages/streaming/ - World streaming - packages/network-ext/ - Network extensions - packages/editor/ - Editor framework and plugins - packages/rust/ - Rust WASM engine - packages/tools/ - Build tools and SDK ## Framework Package Decoupling - Decoupled behavior-tree and blueprint packages from ESEngine dependencies - Created abstracted interfaces (IBTAssetManager, IBehaviorTreeAssetContent) - ESEngine-specific code moved to esengine/ subpath exports - Framework packages now usable with Cocos/Laya without ESEngine ## CI Configuration - Updated CI to only type-check and lint framework packages - Added type-check:framework and lint:framework scripts ## Breaking Changes - Package import paths changed due to directory reorganization - ESEngine integrations now use subpath imports (e.g., '@esengine/behavior-tree/esengine') * fix: update es-engine file path after directory reorganization * docs: update README to focus on framework over engine * ci: only build framework packages, remove Rust/WASM dependencies * fix: remove esengine subpath from behavior-tree and blueprint builds ESEngine integration code will only be available in full engine builds. Framework packages are now purely engine-agnostic. * fix: move network-protocols to framework, build both in CI * fix: update workflow paths from packages/core to packages/framework/core * fix: exclude esengine folder from type-check in behavior-tree and blueprint * fix: update network tsconfig references to new paths * fix: add test:ci:framework to only test framework packages in CI * fix: only build core and math npm packages in CI * fix: exclude test files from CodeQL and fix string escaping security issue
860 lines
30 KiB
TypeScript
860 lines
30 KiB
TypeScript
import { EventDispatcher } from '../events/EventDispatcher';
|
|
import type { GComponent } from './GComponent';
|
|
import type { GObject } from './GObject';
|
|
import { GTween } from '../tween/GTween';
|
|
import type { GTweener } from '../tween/GTweener';
|
|
import { EEaseType } from '../tween/EaseType';
|
|
import { ByteBuffer } from '../utils/ByteBuffer';
|
|
import type { SimpleHandler } from '../display/MovieClip';
|
|
|
|
/**
|
|
* Transition action types
|
|
* 过渡动画动作类型
|
|
*/
|
|
export const enum ETransitionActionType {
|
|
XY = 0,
|
|
Size = 1,
|
|
Scale = 2,
|
|
Pivot = 3,
|
|
Alpha = 4,
|
|
Rotation = 5,
|
|
Color = 6,
|
|
Animation = 7,
|
|
Visible = 8,
|
|
Sound = 9,
|
|
Transition = 10,
|
|
Shake = 11,
|
|
ColorFilter = 12,
|
|
Skew = 13,
|
|
Text = 14,
|
|
Icon = 15,
|
|
Unknown = 16
|
|
}
|
|
|
|
/**
|
|
* Transition item value
|
|
* 过渡项值
|
|
*/
|
|
interface ITransitionValue {
|
|
f1?: number;
|
|
f2?: number;
|
|
f3?: number;
|
|
f4?: number;
|
|
b1?: boolean;
|
|
b2?: boolean;
|
|
b3?: boolean;
|
|
visible?: boolean;
|
|
playing?: boolean;
|
|
frame?: number;
|
|
sound?: string;
|
|
volume?: number;
|
|
transName?: string;
|
|
playTimes?: number;
|
|
trans?: Transition;
|
|
stopTime?: number;
|
|
amplitude?: number;
|
|
duration?: number;
|
|
offsetX?: number;
|
|
offsetY?: number;
|
|
lastOffsetX?: number;
|
|
lastOffsetY?: number;
|
|
text?: string;
|
|
audioClip?: string;
|
|
flag?: boolean;
|
|
}
|
|
|
|
/**
|
|
* Tween config
|
|
* 补间配置
|
|
*/
|
|
interface ITweenConfig {
|
|
duration: number;
|
|
easeType: EEaseType;
|
|
repeat: number;
|
|
yoyo: boolean;
|
|
startValue: ITransitionValue;
|
|
endValue: ITransitionValue;
|
|
endLabel?: string;
|
|
endHook?: SimpleHandler;
|
|
}
|
|
|
|
/**
|
|
* Transition item
|
|
* 过渡项
|
|
*/
|
|
interface ITransitionItem {
|
|
time: number;
|
|
targetId: string;
|
|
type: ETransitionActionType;
|
|
tweenConfig?: ITweenConfig;
|
|
label?: string;
|
|
value: ITransitionValue;
|
|
hook?: SimpleHandler;
|
|
tweener?: GTweener;
|
|
target?: GObject;
|
|
displayLockToken: number;
|
|
}
|
|
|
|
/** Options flags */
|
|
const OPTION_AUTO_STOP_DISABLED = 2;
|
|
const OPTION_AUTO_STOP_AT_END = 4;
|
|
|
|
/**
|
|
* Transition
|
|
*
|
|
* Animation transition system for UI components.
|
|
* Supports keyframe animations, tweening, and chained transitions.
|
|
*
|
|
* UI 组件的动画过渡系统,支持关键帧动画、补间和链式过渡
|
|
*/
|
|
export class Transition extends EventDispatcher {
|
|
/** Transition name | 过渡动画名称 */
|
|
public name: string = '';
|
|
|
|
private _owner: GComponent;
|
|
private _ownerBaseX: number = 0;
|
|
private _ownerBaseY: number = 0;
|
|
private _items: ITransitionItem[] = [];
|
|
private _totalTimes: number = 0;
|
|
private _totalTasks: number = 0;
|
|
private _playing: boolean = false;
|
|
private _paused: boolean = false;
|
|
private _onComplete: SimpleHandler | null = null;
|
|
private _options: number = 0;
|
|
private _reversed: boolean = false;
|
|
private _totalDuration: number = 0;
|
|
private _autoPlay: boolean = false;
|
|
private _autoPlayTimes: number = 1;
|
|
private _autoPlayDelay: number = 0;
|
|
private _timeScale: number = 1;
|
|
private _startTime: number = 0;
|
|
private _endTime: number = -1;
|
|
|
|
constructor(owner: GComponent) {
|
|
super();
|
|
this._owner = owner;
|
|
}
|
|
|
|
public get owner(): GComponent {
|
|
return this._owner;
|
|
}
|
|
|
|
public get playing(): boolean {
|
|
return this._playing;
|
|
}
|
|
|
|
public get autoPlay(): boolean {
|
|
return this._autoPlay;
|
|
}
|
|
|
|
public set autoPlay(value: boolean) {
|
|
this.setAutoPlay(value, this._autoPlayTimes, this._autoPlayDelay);
|
|
}
|
|
|
|
public get autoPlayRepeat(): number {
|
|
return this._autoPlayTimes;
|
|
}
|
|
|
|
public get autoPlayDelay(): number {
|
|
return this._autoPlayDelay;
|
|
}
|
|
|
|
public get timeScale(): number {
|
|
return this._timeScale;
|
|
}
|
|
|
|
public set timeScale(value: number) {
|
|
if (this._timeScale !== value) {
|
|
this._timeScale = value;
|
|
if (this._playing) {
|
|
for (const item of this._items) {
|
|
if (item.tweener) {
|
|
item.tweener.setTimeScale(value);
|
|
} else if (item.type === ETransitionActionType.Transition && item.value.trans) {
|
|
item.value.trans.timeScale = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public play(
|
|
onComplete?: SimpleHandler,
|
|
times: number = 1,
|
|
delay: number = 0,
|
|
startTime: number = 0,
|
|
endTime: number = -1
|
|
): void {
|
|
this._play(onComplete || null, times, delay, startTime, endTime, false);
|
|
}
|
|
|
|
public playReverse(
|
|
onComplete?: SimpleHandler,
|
|
times: number = 1,
|
|
delay: number = 0,
|
|
startTime: number = 0,
|
|
endTime: number = -1
|
|
): void {
|
|
this._play(onComplete || null, times, delay, startTime, endTime, true);
|
|
}
|
|
|
|
public changePlayTimes(value: number): void {
|
|
this._totalTimes = value;
|
|
}
|
|
|
|
public setAutoPlay(value: boolean, times: number = -1, delay: number = 0): void {
|
|
if (this._autoPlay !== value) {
|
|
this._autoPlay = value;
|
|
this._autoPlayTimes = times;
|
|
this._autoPlayDelay = delay;
|
|
|
|
if (this._autoPlay) {
|
|
if (this._owner.onStage) {
|
|
this.play(undefined, this._autoPlayTimes, this._autoPlayDelay);
|
|
}
|
|
} else {
|
|
if (!this._owner.onStage) {
|
|
this.stop(false, true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public _play(
|
|
onComplete: SimpleHandler | null,
|
|
times: number,
|
|
delay: number,
|
|
startTime: number,
|
|
endTime: number,
|
|
reversed: boolean
|
|
): void {
|
|
this.stop(true, true);
|
|
|
|
this._totalTimes = times;
|
|
this._reversed = reversed;
|
|
this._startTime = startTime;
|
|
this._endTime = endTime;
|
|
this._playing = true;
|
|
this._paused = false;
|
|
this._onComplete = onComplete;
|
|
|
|
for (const item of this._items) {
|
|
if (!item.target) {
|
|
if (item.targetId) {
|
|
item.target = this._owner.getChildById(item.targetId) ?? undefined;
|
|
} else {
|
|
item.target = this._owner;
|
|
}
|
|
} else if (item.target !== this._owner && item.target.parent !== this._owner) {
|
|
item.target = undefined;
|
|
}
|
|
|
|
if (item.target && item.type === ETransitionActionType.Transition) {
|
|
let trans = (item.target as GComponent).getTransition(item.value.transName || '');
|
|
if (trans === this) trans = null;
|
|
if (trans) {
|
|
if (item.value.playTimes === 0) {
|
|
for (let j = this._items.indexOf(item) - 1; j >= 0; j--) {
|
|
const item2 = this._items[j];
|
|
if (item2.type === ETransitionActionType.Transition && item2.value.trans === trans) {
|
|
item2.value.stopTime = item.time - item2.time;
|
|
trans = null;
|
|
break;
|
|
}
|
|
}
|
|
if (trans) item.value.stopTime = 0;
|
|
} else {
|
|
item.value.stopTime = -1;
|
|
}
|
|
}
|
|
item.value.trans = trans ?? undefined;
|
|
}
|
|
}
|
|
|
|
if (delay === 0) {
|
|
this.onDelayedPlay();
|
|
} else {
|
|
GTween.delayedCall(delay).setTarget(this).onComplete(() => this.onDelayedPlay());
|
|
}
|
|
}
|
|
|
|
public stop(bSetToComplete: boolean = true, bProcessCallback: boolean = false): void {
|
|
if (!this._playing) return;
|
|
|
|
this._playing = false;
|
|
this._totalTasks = 0;
|
|
this._totalTimes = 0;
|
|
const handler = this._onComplete;
|
|
this._onComplete = null;
|
|
|
|
GTween.kill(this);
|
|
|
|
const cnt = this._items.length;
|
|
if (this._reversed) {
|
|
for (let i = cnt - 1; i >= 0; i--) {
|
|
const item = this._items[i];
|
|
if (item.target) this.stopItem(item, bSetToComplete);
|
|
}
|
|
} else {
|
|
for (let i = 0; i < cnt; i++) {
|
|
const item = this._items[i];
|
|
if (item.target) this.stopItem(item, bSetToComplete);
|
|
}
|
|
}
|
|
|
|
if (bProcessCallback && handler) {
|
|
if (typeof handler === 'function') handler();
|
|
else if (typeof handler.run === 'function') handler.run();
|
|
}
|
|
}
|
|
|
|
private stopItem(item: ITransitionItem, bSetToComplete: boolean): void {
|
|
if (item.tweener) {
|
|
item.tweener.kill(bSetToComplete);
|
|
item.tweener = undefined;
|
|
|
|
if (item.type === ETransitionActionType.Shake && !bSetToComplete && item.target) {
|
|
item.target.x -= item.value.lastOffsetX || 0;
|
|
item.target.y -= item.value.lastOffsetY || 0;
|
|
}
|
|
}
|
|
|
|
if (item.type === ETransitionActionType.Transition && item.value.trans) {
|
|
item.value.trans.stop(bSetToComplete, false);
|
|
}
|
|
}
|
|
|
|
public pause(): void {
|
|
if (!this._playing || this._paused) return;
|
|
this._paused = true;
|
|
|
|
const tweener = GTween.getTween(this);
|
|
if (tweener) tweener.setPaused(true);
|
|
|
|
for (const item of this._items) {
|
|
if (!item.target) continue;
|
|
if (item.type === ETransitionActionType.Transition && item.value.trans) {
|
|
item.value.trans.pause();
|
|
}
|
|
if (item.tweener) item.tweener.setPaused(true);
|
|
}
|
|
}
|
|
|
|
public resume(): void {
|
|
if (!this._playing || !this._paused) return;
|
|
this._paused = false;
|
|
|
|
const tweener = GTween.getTween(this);
|
|
if (tweener) tweener.setPaused(false);
|
|
|
|
for (const item of this._items) {
|
|
if (!item.target) continue;
|
|
if (item.type === ETransitionActionType.Transition && item.value.trans) {
|
|
item.value.trans.resume();
|
|
}
|
|
if (item.tweener) item.tweener.setPaused(false);
|
|
}
|
|
}
|
|
|
|
public setValue(label: string, ...values: any[]): void {
|
|
for (const item of this._items) {
|
|
if (item.label === label) {
|
|
const value = item.tweenConfig ? item.tweenConfig.startValue : item.value;
|
|
this.setItemValue(item.type, value, values);
|
|
return;
|
|
} else if (item.tweenConfig?.endLabel === label) {
|
|
this.setItemValue(item.type, item.tweenConfig.endValue, values);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private setItemValue(type: ETransitionActionType, value: ITransitionValue, args: any[]): void {
|
|
switch (type) {
|
|
case ETransitionActionType.XY:
|
|
case ETransitionActionType.Size:
|
|
case ETransitionActionType.Pivot:
|
|
case ETransitionActionType.Scale:
|
|
case ETransitionActionType.Skew:
|
|
value.b1 = value.b2 = true;
|
|
value.f1 = parseFloat(args[0]);
|
|
value.f2 = parseFloat(args[1]);
|
|
break;
|
|
case ETransitionActionType.Alpha:
|
|
case ETransitionActionType.Rotation:
|
|
case ETransitionActionType.Color:
|
|
value.f1 = parseFloat(args[0]);
|
|
break;
|
|
case ETransitionActionType.Animation:
|
|
value.frame = parseInt(args[0]);
|
|
if (args.length > 1) value.playing = args[1];
|
|
break;
|
|
case ETransitionActionType.Visible:
|
|
value.visible = args[0];
|
|
break;
|
|
case ETransitionActionType.Sound:
|
|
value.sound = args[0];
|
|
if (args.length > 1) value.volume = parseFloat(args[1]);
|
|
break;
|
|
case ETransitionActionType.Transition:
|
|
value.transName = args[0];
|
|
if (args.length > 1) value.playTimes = parseInt(args[1]);
|
|
break;
|
|
case ETransitionActionType.Shake:
|
|
value.amplitude = parseFloat(args[0]);
|
|
if (args.length > 1) value.duration = parseFloat(args[1]);
|
|
break;
|
|
case ETransitionActionType.ColorFilter:
|
|
value.f1 = parseFloat(args[0]);
|
|
value.f2 = parseFloat(args[1]);
|
|
value.f3 = parseFloat(args[2]);
|
|
value.f4 = parseFloat(args[3]);
|
|
break;
|
|
case ETransitionActionType.Text:
|
|
case ETransitionActionType.Icon:
|
|
value.text = args[0];
|
|
break;
|
|
}
|
|
}
|
|
|
|
public setTarget(label: string, target: GObject): void {
|
|
for (const item of this._items) {
|
|
if (item.label === label) {
|
|
item.targetId = target.id;
|
|
item.target = target;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public setHook(label: string, callback: SimpleHandler): void {
|
|
for (const item of this._items) {
|
|
if (item.label === label) {
|
|
item.hook = callback;
|
|
return;
|
|
} else if (item.tweenConfig?.endLabel === label) {
|
|
item.tweenConfig.endHook = callback;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public clearHooks(): void {
|
|
for (const item of this._items) {
|
|
item.hook = undefined;
|
|
if (item.tweenConfig) item.tweenConfig.endHook = undefined;
|
|
}
|
|
}
|
|
|
|
public onOwnerAddedToStage(): void {
|
|
if (this._autoPlay && !this._playing) {
|
|
this.play(undefined, this._autoPlayTimes, this._autoPlayDelay);
|
|
}
|
|
}
|
|
|
|
public onOwnerRemovedFromStage(): void {
|
|
if ((this._options & OPTION_AUTO_STOP_DISABLED) === 0) {
|
|
this.stop((this._options & OPTION_AUTO_STOP_AT_END) !== 0, false);
|
|
}
|
|
}
|
|
|
|
private onDelayedPlay(): void {
|
|
this._ownerBaseX = this._owner.x;
|
|
this._ownerBaseY = this._owner.y;
|
|
this._totalTasks = 1;
|
|
|
|
const cnt = this._items.length;
|
|
for (let i = this._reversed ? cnt - 1 : 0; this._reversed ? i >= 0 : i < cnt; this._reversed ? i-- : i++) {
|
|
const item = this._items[i];
|
|
if (item.target) this.playItem(item);
|
|
}
|
|
|
|
this._totalTasks--;
|
|
this.checkAllComplete();
|
|
}
|
|
|
|
private playItem(item: ITransitionItem): void {
|
|
let time: number;
|
|
|
|
if (item.tweenConfig) {
|
|
time = this._reversed
|
|
? this._totalDuration - item.time - item.tweenConfig.duration
|
|
: item.time;
|
|
|
|
if (this._endTime === -1 || time < this._endTime) {
|
|
const startValue = this._reversed ? item.tweenConfig.endValue : item.tweenConfig.startValue;
|
|
const endValue = this._reversed ? item.tweenConfig.startValue : item.tweenConfig.endValue;
|
|
|
|
item.value.b1 = startValue.b1;
|
|
item.value.b2 = startValue.b2;
|
|
|
|
switch (item.type) {
|
|
case ETransitionActionType.XY:
|
|
case ETransitionActionType.Size:
|
|
case ETransitionActionType.Scale:
|
|
case ETransitionActionType.Skew:
|
|
item.tweener = GTween.to2(
|
|
startValue.f1 || 0, startValue.f2 || 0,
|
|
endValue.f1 || 0, endValue.f2 || 0,
|
|
item.tweenConfig.duration
|
|
);
|
|
break;
|
|
case ETransitionActionType.Alpha:
|
|
case ETransitionActionType.Rotation:
|
|
item.tweener = GTween.to(startValue.f1 || 0, endValue.f1 || 0, item.tweenConfig.duration);
|
|
break;
|
|
case ETransitionActionType.Color:
|
|
item.tweener = GTween.toColor(startValue.f1 || 0, endValue.f1 || 0, item.tweenConfig.duration);
|
|
break;
|
|
case ETransitionActionType.ColorFilter:
|
|
item.tweener = GTween.to4(
|
|
startValue.f1 || 0, startValue.f2 || 0, startValue.f3 || 0, startValue.f4 || 0,
|
|
endValue.f1 || 0, endValue.f2 || 0, endValue.f3 || 0, endValue.f4 || 0,
|
|
item.tweenConfig.duration
|
|
);
|
|
break;
|
|
}
|
|
|
|
if (item.tweener) {
|
|
item.tweener
|
|
.setDelay(time)
|
|
.setEase(item.tweenConfig.easeType)
|
|
.setRepeat(item.tweenConfig.repeat, item.tweenConfig.yoyo)
|
|
.setTimeScale(this._timeScale)
|
|
.setTarget(item)
|
|
.onStart(() => this.callHook(item, false))
|
|
.onUpdate(() => this.onTweenUpdate(item))
|
|
.onComplete(() => this.onTweenComplete(item));
|
|
|
|
if (this._endTime >= 0) item.tweener.setBreakpoint(this._endTime - time);
|
|
this._totalTasks++;
|
|
}
|
|
}
|
|
} else if (item.type === ETransitionActionType.Shake) {
|
|
time = this._reversed
|
|
? this._totalDuration - item.time - (item.value.duration || 0)
|
|
: item.time;
|
|
|
|
item.value.offsetX = item.value.offsetY = 0;
|
|
item.value.lastOffsetX = item.value.lastOffsetY = 0;
|
|
|
|
item.tweener = GTween.shake(0, 0, item.value.amplitude || 0, item.value.duration || 0)
|
|
.setDelay(time)
|
|
.setTimeScale(this._timeScale)
|
|
.setTarget(item)
|
|
.onUpdate(() => this.onTweenUpdate(item))
|
|
.onComplete(() => this.onTweenComplete(item));
|
|
|
|
if (this._endTime >= 0) item.tweener.setBreakpoint(this._endTime - item.time);
|
|
this._totalTasks++;
|
|
} else {
|
|
time = this._reversed ? this._totalDuration - item.time : item.time;
|
|
|
|
if (time <= this._startTime) {
|
|
this.applyValue(item);
|
|
this.callHook(item, false);
|
|
} else if (this._endTime === -1 || time <= this._endTime) {
|
|
this._totalTasks++;
|
|
item.tweener = GTween.delayedCall(time)
|
|
.setTimeScale(this._timeScale)
|
|
.setTarget(item)
|
|
.onComplete(() => {
|
|
item.tweener = undefined;
|
|
this._totalTasks--;
|
|
this.applyValue(item);
|
|
this.callHook(item, false);
|
|
this.checkAllComplete();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
private onTweenUpdate(item: ITransitionItem): void {
|
|
if (!item.tweener) return;
|
|
const tweener = item.tweener;
|
|
|
|
switch (item.type) {
|
|
case ETransitionActionType.XY:
|
|
case ETransitionActionType.Size:
|
|
case ETransitionActionType.Scale:
|
|
case ETransitionActionType.Skew:
|
|
item.value.f1 = tweener.value.x;
|
|
item.value.f2 = tweener.value.y;
|
|
break;
|
|
case ETransitionActionType.Alpha:
|
|
case ETransitionActionType.Rotation:
|
|
item.value.f1 = tweener.value.x;
|
|
break;
|
|
case ETransitionActionType.Color:
|
|
item.value.f1 = tweener.value.color;
|
|
break;
|
|
case ETransitionActionType.ColorFilter:
|
|
item.value.f1 = tweener.value.x;
|
|
item.value.f2 = tweener.value.y;
|
|
item.value.f3 = tweener.value.z;
|
|
item.value.f4 = tweener.value.w;
|
|
break;
|
|
case ETransitionActionType.Shake:
|
|
item.value.offsetX = tweener.deltaValue.x;
|
|
item.value.offsetY = tweener.deltaValue.y;
|
|
break;
|
|
}
|
|
this.applyValue(item);
|
|
}
|
|
|
|
private onTweenComplete(item: ITransitionItem): void {
|
|
item.tweener = undefined;
|
|
this._totalTasks--;
|
|
this.callHook(item, true);
|
|
this.checkAllComplete();
|
|
}
|
|
|
|
private checkAllComplete(): void {
|
|
if (this._playing && this._totalTasks === 0) {
|
|
if (this._totalTimes < 0) {
|
|
this.internalPlay();
|
|
} else {
|
|
this._totalTimes--;
|
|
if (this._totalTimes > 0) {
|
|
this.internalPlay();
|
|
} else {
|
|
this._playing = false;
|
|
const handler = this._onComplete;
|
|
this._onComplete = null;
|
|
if (handler) {
|
|
if (typeof handler === 'function') handler();
|
|
else if (typeof handler.run === 'function') handler.run();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private internalPlay(): void {
|
|
this._ownerBaseX = this._owner.x;
|
|
this._ownerBaseY = this._owner.y;
|
|
this._totalTasks = 1;
|
|
|
|
for (const item of this._items) {
|
|
if (item.target) this.playItem(item);
|
|
}
|
|
this._totalTasks--;
|
|
}
|
|
|
|
private callHook(item: ITransitionItem, tweenEnd: boolean): void {
|
|
const hook = tweenEnd ? item.tweenConfig?.endHook : item.hook;
|
|
if (hook) {
|
|
if (typeof hook === 'function') hook();
|
|
else if (typeof hook.run === 'function') hook.run();
|
|
}
|
|
}
|
|
|
|
private applyValue(item: ITransitionItem): void {
|
|
if (!item.target) return;
|
|
const value = item.value;
|
|
const target = item.target;
|
|
|
|
switch (item.type) {
|
|
case ETransitionActionType.XY:
|
|
if (target === this._owner) {
|
|
if (value.b1 && value.b2) target.setXY((value.f1 || 0) + this._ownerBaseX, (value.f2 || 0) + this._ownerBaseY);
|
|
else if (value.b1) target.x = (value.f1 || 0) + this._ownerBaseX;
|
|
else target.y = (value.f2 || 0) + this._ownerBaseY;
|
|
} else if (value.b3) {
|
|
if (value.b1 && value.b2) target.setXY((value.f1 || 0) * this._owner.width, (value.f2 || 0) * this._owner.height);
|
|
else if (value.b1) target.x = (value.f1 || 0) * this._owner.width;
|
|
else if (value.b2) target.y = (value.f2 || 0) * this._owner.height;
|
|
} else {
|
|
if (value.b1 && value.b2) target.setXY(value.f1 || 0, value.f2 || 0);
|
|
else if (value.b1) target.x = value.f1 || 0;
|
|
else if (value.b2) target.y = value.f2 || 0;
|
|
}
|
|
break;
|
|
case ETransitionActionType.Size:
|
|
if (!value.b1) value.f1 = target.width;
|
|
if (!value.b2) value.f2 = target.height;
|
|
target.setSize(value.f1 || 0, value.f2 || 0);
|
|
break;
|
|
case ETransitionActionType.Pivot:
|
|
target.setPivot(value.f1 || 0, value.f2 || 0, target.pivotAsAnchor);
|
|
break;
|
|
case ETransitionActionType.Alpha:
|
|
target.alpha = value.f1 || 0;
|
|
break;
|
|
case ETransitionActionType.Rotation:
|
|
target.rotation = value.f1 || 0;
|
|
break;
|
|
case ETransitionActionType.Scale:
|
|
target.setScale(value.f1 || 0, value.f2 || 0);
|
|
break;
|
|
case ETransitionActionType.Skew:
|
|
target.setSkew(value.f1 || 0, value.f2 || 0);
|
|
break;
|
|
case ETransitionActionType.Visible:
|
|
target.visible = value.visible || false;
|
|
break;
|
|
case ETransitionActionType.Transition:
|
|
if (this._playing && value.trans) {
|
|
this._totalTasks++;
|
|
const startTime = this._startTime > item.time ? this._startTime - item.time : 0;
|
|
let endTime = this._endTime >= 0 ? this._endTime - item.time : -1;
|
|
if (value.stopTime !== undefined && value.stopTime >= 0 && (endTime < 0 || endTime > value.stopTime)) {
|
|
endTime = value.stopTime;
|
|
}
|
|
value.trans.timeScale = this._timeScale;
|
|
value.trans._play(() => { this._totalTasks--; this.checkAllComplete(); }, value.playTimes || 1, 0, startTime, endTime, this._reversed);
|
|
}
|
|
break;
|
|
case ETransitionActionType.Shake:
|
|
target.x = target.x - (value.lastOffsetX || 0) + (value.offsetX || 0);
|
|
target.y = target.y - (value.lastOffsetY || 0) + (value.offsetY || 0);
|
|
value.lastOffsetX = value.offsetX;
|
|
value.lastOffsetY = value.offsetY;
|
|
break;
|
|
case ETransitionActionType.Text:
|
|
target.text = value.text || '';
|
|
break;
|
|
case ETransitionActionType.Icon:
|
|
target.icon = value.text || '';
|
|
break;
|
|
}
|
|
}
|
|
|
|
public setup(buffer: ByteBuffer): void {
|
|
this.name = buffer.readS();
|
|
this._options = buffer.getInt32();
|
|
this._autoPlay = buffer.readBool();
|
|
this._autoPlayTimes = buffer.getInt32();
|
|
this._autoPlayDelay = buffer.getFloat32();
|
|
|
|
const cnt = buffer.getInt16();
|
|
for (let i = 0; i < cnt; i++) {
|
|
const dataLen = buffer.getInt16();
|
|
const curPos = buffer.position;
|
|
|
|
buffer.seek(curPos, 0);
|
|
|
|
const item: ITransitionItem = {
|
|
type: buffer.readByte() as ETransitionActionType,
|
|
time: buffer.getFloat32(),
|
|
targetId: '',
|
|
value: {},
|
|
displayLockToken: 0
|
|
};
|
|
|
|
const targetId = buffer.getInt16();
|
|
if (targetId >= 0) {
|
|
const child = this._owner.getChildAt(targetId);
|
|
item.targetId = child?.id || '';
|
|
}
|
|
|
|
item.label = buffer.readS();
|
|
|
|
if (buffer.readBool()) {
|
|
buffer.seek(curPos, 1);
|
|
item.tweenConfig = {
|
|
duration: buffer.getFloat32(),
|
|
easeType: buffer.readByte() as EEaseType,
|
|
repeat: buffer.getInt32(),
|
|
yoyo: buffer.readBool(),
|
|
startValue: {},
|
|
endValue: {},
|
|
endLabel: buffer.readS()
|
|
};
|
|
|
|
buffer.seek(curPos, 2);
|
|
this.decodeValue(item.type, buffer, item.tweenConfig.startValue);
|
|
|
|
buffer.seek(curPos, 3);
|
|
this.decodeValue(item.type, buffer, item.tweenConfig.endValue);
|
|
} else {
|
|
buffer.seek(curPos, 2);
|
|
this.decodeValue(item.type, buffer, item.value);
|
|
}
|
|
|
|
this._items.push(item);
|
|
buffer.position = curPos + dataLen;
|
|
}
|
|
|
|
this._totalDuration = 0;
|
|
for (const item of this._items) {
|
|
let duration = item.time;
|
|
if (item.tweenConfig) duration += item.tweenConfig.duration * (item.tweenConfig.repeat + 1);
|
|
else if (item.type === ETransitionActionType.Shake) duration += item.value.duration || 0;
|
|
if (duration > this._totalDuration) this._totalDuration = duration;
|
|
}
|
|
}
|
|
|
|
private decodeValue(type: ETransitionActionType, buffer: ByteBuffer, value: ITransitionValue): void {
|
|
switch (type) {
|
|
case ETransitionActionType.XY:
|
|
case ETransitionActionType.Size:
|
|
case ETransitionActionType.Pivot:
|
|
case ETransitionActionType.Skew:
|
|
value.b1 = buffer.readBool();
|
|
value.b2 = buffer.readBool();
|
|
value.f1 = buffer.getFloat32();
|
|
value.f2 = buffer.getFloat32();
|
|
if (buffer.version >= 2 && type === ETransitionActionType.XY) value.b3 = buffer.readBool();
|
|
break;
|
|
case ETransitionActionType.Alpha:
|
|
case ETransitionActionType.Rotation:
|
|
value.f1 = buffer.getFloat32();
|
|
break;
|
|
case ETransitionActionType.Scale:
|
|
value.f1 = buffer.getFloat32();
|
|
value.f2 = buffer.getFloat32();
|
|
break;
|
|
case ETransitionActionType.Color:
|
|
value.f1 = buffer.readColor();
|
|
break;
|
|
case ETransitionActionType.Animation:
|
|
value.playing = buffer.readBool();
|
|
value.frame = buffer.getInt32();
|
|
break;
|
|
case ETransitionActionType.Visible:
|
|
value.visible = buffer.readBool();
|
|
break;
|
|
case ETransitionActionType.Sound:
|
|
value.sound = buffer.readS();
|
|
value.volume = buffer.getFloat32();
|
|
break;
|
|
case ETransitionActionType.Transition:
|
|
value.transName = buffer.readS();
|
|
value.playTimes = buffer.getInt32();
|
|
break;
|
|
case ETransitionActionType.Shake:
|
|
value.amplitude = buffer.getFloat32();
|
|
value.duration = buffer.getFloat32();
|
|
break;
|
|
case ETransitionActionType.ColorFilter:
|
|
value.f1 = buffer.getFloat32();
|
|
value.f2 = buffer.getFloat32();
|
|
value.f3 = buffer.getFloat32();
|
|
value.f4 = buffer.getFloat32();
|
|
break;
|
|
case ETransitionActionType.Text:
|
|
case ETransitionActionType.Icon:
|
|
value.text = buffer.readS();
|
|
break;
|
|
}
|
|
}
|
|
|
|
public dispose(): void {
|
|
if (this._playing) GTween.kill(this);
|
|
|
|
for (const item of this._items) {
|
|
if (item.tweener) {
|
|
item.tweener.kill();
|
|
item.tweener = undefined;
|
|
}
|
|
item.target = undefined;
|
|
item.hook = undefined;
|
|
if (item.tweenConfig) item.tweenConfig.endHook = undefined;
|
|
}
|
|
|
|
this._items.length = 0;
|
|
super.dispose();
|
|
}
|
|
}
|