消消方块阵换皮表情
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

161 lines
5.7 KiB

import { Node, assetManager, sp, AssetManager, Vec3 } from 'cc';
import { ensureSpineAssetResetEnums } from '../module/lang/spineRuntimePatch';
/**
* SpineLoader 类用于动态加载和播放 Spine 动画。
*/
export class SpineLoader {
/**
* 动态加载并播放 Spine 动画
* @param bundleName - Asset Bundle 的名称
* @param spinePath - Spine 资源的路径(相对于 bundle 根目录)
* @param parentNode - 父节点,用于挂载 Spine 动画
* @param animationName - 播放的动画名称
* @param loop - 是否循环播放动画
* @param onComplete - 动画播放完成时的回调函数(仅在非循环模式下有效)
* @returns Promise<sp.Skeleton> - 返回加载完成的 Spine Skeleton 组件
*/
public static async loadAndPlaySpine(
bundleName: string,
spinePath: string,
animationName: string,
parentNode: Node,
position: Vec3 = Vec3.ZERO,
loop: boolean = true,
onComplete?: () => void
): Promise<sp.Skeleton> {
return new Promise(async (resolve, reject) => {
try {
// 加载指定的 Asset Bundle
const bundle = await this.loadBundle(bundleName);
// 加载 Spine 资源
const spineAsset = await this.loadSpineAsset(bundle, spinePath);
spineAsset.addRef();
// 创建 Spine 节点
const spineNode = this.createSpineNode(spineAsset);
// 将 Spine 节点添加到父节点
parentNode.addChild(spineNode);
spineNode.setPosition(position);
// 获取 Spine Skeleton 组件
const skeleton = spineNode.getComponent(sp.Skeleton);
if (!skeleton) {
throw new Error("Failed to get Skeleton component from Spine node.");
}
// 播放指定动画
skeleton.setAnimation(0, animationName, loop);
// 如果是非循环模式,监听动画完成事件
if (!loop) {
skeleton.setCompleteListener(() => {
spineAsset.decRef();
spineNode.destroy();
if (onComplete) onComplete();
})
}
resolve(skeleton);
} catch (error) {
reject(error);
}
});
}
/**
* 查询 Spine 动画的时长(不播放动画)
* @param bundleName - Asset Bundle 的名称
* @param spinePath - Spine 资源的路径(相对于 bundle 根目录)
* @param animationName - 动画名称
* @returns Promise<number> - 返回动画的时长(单位:秒)
*/
public static async getAnimationDuration(
bundleName: string,
spinePath: string,
animationName: string
): Promise<number> {
return new Promise(async (resolve, reject) => {
try {
// 加载指定的 Asset Bundle
const bundle = await this.loadBundle(bundleName);
// 加载 Spine 资源
const spineAsset = await this.loadSpineAsset(bundle, spinePath);
// 获取动画数据
const animation = spineAsset.getRuntimeData().findAnimation(animationName);
if (!animation) {
reject(`Animation "${animationName}" not found in Spine asset.`);
} else {
resolve(animation.duration); // 返回动画时长
}
} catch (error) {
reject(error);
}
});
}
/**
* 加载 Asset Bundle
* @param bundleName - Asset Bundle 的名称
* @returns Promise<AssetManager.Bundle> - 返回加载完成的 Asset Bundle
*/
private static loadBundle(bundleName: string): Promise<AssetManager.Bundle> {
return new Promise((resolve, reject) => {
let bundle = assetManager.getBundle(bundleName);
if (bundle) {
resolve(bundle);
return;
}
assetManager.loadBundle(bundleName, (err, bundle) => {
if (err) {
reject(`Failed to load bundle: ${bundleName}, error: ${err.message}`);
} else {
resolve(bundle);
}
});
});
}
/**
* 加载 Spine 资源
* @param bundle - Asset Bundle
* @param spinePath - Spine 资源的路径
* @returns Promise<sp.SkeletonData> - 返回加载完成的 Spine 数据
*/
private static loadSpineAsset(bundle: AssetManager.Bundle, spinePath: string): Promise<sp.SkeletonData> {
return new Promise((resolve, reject) => {
let asset = bundle.get(spinePath, sp.SkeletonData);
if (asset) {
resolve(asset);
return;
}
bundle.load(spinePath, sp.SkeletonData, (err, asset) => {
if (err) {
reject(`Failed to load Spine asset: ${spinePath}, error: ${err.message}`);
} else {
resolve(asset);
}
});
});
}
/**
* 创建 Spine 节点
* @param spineAsset - Spine 数据
* @returns Node - 返回包含 Spine 动画的节点
*/
private static createSpineNode(spineAsset: sp.SkeletonData): Node {
ensureSpineAssetResetEnums(spineAsset);
const spineNode = new Node();
const skeleton = spineNode.addComponent(sp.Skeleton);
skeleton.skeletonData = spineAsset;
return spineNode;
}
}