pinball/assets/_Game/Scripts/Base/SpineAnimationHandler.ts

288 lines
8.9 KiB
TypeScript

import { _decorator, Component, Enum, Node, setPropertyEnumType, sp } from 'cc';
const { ccclass, property, type } = _decorator;
export enum SocketPath {}
Enum(SocketPath);
export enum SpineAnimation {}
Enum(SpineAnimation);
export enum SpineSkin {}
Enum(SpineSkin);
@ccclass('SpineAnimationHandler')
export default class SpineAnimationHandler extends Component {
@property(sp.Skeleton)
private skeleton: sp.Skeleton;
@property({ visible: true })
private _flipX: boolean = false;
@property({ visible: true })
private _flipY: boolean = false;
public get flipX() {
return this._flipX;
}
public set flipX(value: boolean) {
if (value) {
this.skeleton._skeleton.scaleX = -Math.abs(this.skeleton._skeleton.scaleX);
} else {
this.skeleton._skeleton.scaleX = Math.abs(this.skeleton._skeleton.scaleX);
}
this._flipX = value;
}
public get flipY() {
return this._flipY;
}
public set flipY(value: boolean) {
if (value) {
this.skeleton._skeleton.scaleY = -Math.abs(this.skeleton._skeleton.scaleY);
} else {
this.skeleton._skeleton.scaleY = Math.abs(this.skeleton._skeleton.scaleY);
}
this._flipX = value;
}
private _enumSocketPath = Enum({});
private _enumAnimation = Enum({});
private _enumSkin = Enum({});
onFocusInEditor(): void {
this.setPropertySocketPath(this, '');
}
protected onLoad(): void {
this.skeleton._skeleton.scaleX = this._flipX ? -this.skeleton._skeleton.scaleX : this.skeleton._skeleton.scaleX;
this.skeleton._skeleton.scaleY = this._flipY ? -this.skeleton._skeleton.scaleY : this.skeleton._skeleton.scaleY;
}
public setPropertySocketPath(object: object, propertyName: string) {
//update enum SocketPath
let pathEnum = {};
this.skeleton.querySockets().forEach((path, i) => {
pathEnum[path] = i;
});
this._enumSocketPath = Enum({});
Object.assign(this._enumSocketPath, pathEnum);
Enum.update(this._enumSocketPath);
setPropertyEnumType(object, propertyName, this._enumSocketPath);
}
public setPropertySpineAnimation(object: object, propertyName: string) {
//update enum Animations
let animEnum = this.skeleton.skeletonData.getAnimsEnum();
this._enumAnimation = Enum({});
Object.assign(this._enumAnimation, animEnum);
Enum.update(this._enumAnimation);
setPropertyEnumType(object, propertyName, this._enumAnimation);
}
public setPropertySpineSkin(object: object, propertyName: string) {
//update enum Skin
let skinEnum = this.skeleton.skeletonData.getSkinsEnum();
this._enumSkin = Enum({});
Object.assign(this._enumSkin, skinEnum);
Enum.update(this._enumSkin);
setPropertyEnumType(object, propertyName, this._enumSkin);
}
public setAnimation(
animName: string,
options?: {
loop?: boolean;
trackIndex?: number;
ignoreAnimationRunning?: boolean;
onComplete?: (entry: sp.spine.TrackEntry) => void;
},
): sp.spine.TrackEntry {
if (!this.skeleton) return null;
const opts = {
trackIndex: 0,
loop: false,
...options,
};
if (opts.ignoreAnimationRunning) {
const trackEntry = this.skeleton.getCurrent(opts.trackIndex);
const animRunning = trackEntry?.animation?.name;
if (animRunning && animRunning == animName) return trackEntry;
}
this.skeleton.setCompleteListener(null);
const trackEntry = this.skeleton.setAnimation(opts?.trackIndex || 0, animName, opts?.loop);
if (opts.onComplete) {
this.skeleton.setCompleteListener(opts.onComplete);
}
return trackEntry;
}
public setListener(listener: (entry: sp.spine.TrackEntry, e: sp.spine.Event) => void) {
this.skeleton.setEventListener(listener);
}
public setAnimationAsync(
animName: string,
options?: {
loop?: boolean;
trackIndex?: number;
ignoreAnimationRunning?: boolean;
},
): Promise<sp.spine.TrackEntry> {
return new Promise((resolve) => {
this.setAnimation(animName, {
...options,
onComplete(entry) {
resolve(entry);
},
});
});
}
public addAnimation(
animName: string,
options?: {
loop?: boolean;
trackIndex?: number;
mixDuration?: number;
delay?: number;
onComplete?: (entry: sp.spine.TrackEntry) => void;
},
): sp.spine.TrackEntry {
if (!this.skeleton) return null;
const opts = {
trackIndex: 0,
loop: false,
...options,
};
this.skeleton.setCompleteListener(null);
const trackEntry = this.skeleton.addAnimation(opts?.trackIndex || 0, animName, opts?.loop, opts?.delay);
if (opts?.mixDuration) {
trackEntry.mixDuration = opts.mixDuration;
}
if (opts.onComplete) {
this.skeleton.setCompleteListener(opts.onComplete);
}
return trackEntry;
}
public addAnimationAsync(
animName: string,
options?: {
loop?: boolean;
trackIndex?: number;
mixDuration?: number;
delay?: number;
},
): Promise<sp.spine.TrackEntry> {
return new Promise((resolve) => {
this.addAnimation(animName, {
...options,
onComplete(entry) {
resolve(entry);
},
});
});
}
public addEmptyAnimation(options?: {
trackIndex?: number;
mixDuration?: number;
delay?: number;
onComplete?: (entry: sp.spine.TrackEntry) => void;
}): sp.spine.TrackEntry {
if (!this.skeleton) return;
const opts = {
trackIndex: 0,
mixDuration: 0.2,
delay: 0.2,
...options,
};
const trackEntry = this.skeleton.getState().addEmptyAnimation(opts.trackIndex, opts.mixDuration, opts.delay);
if (opts.onComplete) {
this.skeleton.setTrackCompleteListener(trackEntry, opts.onComplete);
}
return trackEntry;
}
public addEmptyAnimationAsync(options?: {
trackIndex?: number;
mixDuration?: number;
delay?: number;
}): Promise<sp.spine.TrackEntry> {
return new Promise((resolve) => {
this.addEmptyAnimation({
...options,
onComplete(entry) {
resolve(entry);
},
});
});
}
public clearTrack(trackIndex: number = 0): void {
if (!this.skeleton) return;
this.skeleton.clearTrack(trackIndex);
}
public clearTracks(): void {
if (!this.skeleton) return;
this.skeleton.clearTracks();
}
public findBone(boneName: string): sp.spine.Bone {
return this.skeleton.findBone(boneName);
}
public socketPathToString(socketPath: SocketPath): string {
return this.skeleton.querySockets()[socketPath];
}
public SpineAnimationToString(animationName: SpineAnimation): string {
return this.skeleton._skeleton.data.animations[animationName].name;
}
public SpineAnimationToAnimation(animationName: SpineAnimation): sp.spine.Animation {
return this.skeleton._skeleton.data.animations[animationName];
}
public addSocket(socketPath: SocketPath | string, target: Node): sp.SpineSocket {
let socket: sp.SpineSocket;
if (typeof socketPath === 'string') {
socket = new sp.SpineSocket(socketPath, target);
} else {
socket = new sp.SpineSocket(this.socketPathToString(socketPath), target);
}
this.skeleton.sockets.push(socket);
this.skeleton!.sockets = this.skeleton!.sockets;
return socket;
}
public updateSocketPath(socket: sp.SpineSocket, socketPath: SocketPath | string): sp.SpineSocket {
let newSocket: sp.SpineSocket;
if (typeof socketPath === 'string') {
newSocket = new sp.SpineSocket(socketPath, socket.target);
} else {
newSocket = new sp.SpineSocket(this.socketPathToString(socketPath), socket.target);
}
const index = this.skeleton.sockets.indexOf(socket);
this.skeleton.sockets[index] = newSocket;
this.skeleton!.sockets = this.skeleton!.sockets;
return newSocket;
}
public removeSocket(socket: sp.SpineSocket): void {
const index = this.skeleton.sockets.indexOf(socket);
this.skeleton.sockets.splice(index, 1);
this.skeleton!.sockets = this.skeleton!.sockets;
}
}