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.
AdLike2048/assets/script/com/lLoadSpine.ts

193 lines
6.0 KiB

3 weeks ago
import { _decorator, Component, Node, Sprite, director, SpriteFrame, sp, AssetManager, Asset, assetManager, isValid } from 'cc';
import { GBundle } from '../game/ConfigRes';
const { ccclass, property } = _decorator;
/**加载 加载动画 皮肤的组件*/
@ccclass('lLoadSpine')
export class lLoadSpine extends Component {
@property(sp.Skeleton)
kaichangSpine: sp.Skeleton = null;
@property(sp.Skeleton)
zhuizhuSpine: sp.Skeleton = null;
path: string = "";
key: string = "";
animation: string = "开场动画";
skinName: string = "默认皮肤";
langSp: sp.Skeleton = null;
curentSpineData: sp.SkeletonData = null;
/** 已成功加载并挂上的资源路径,用于同皮肤重复进入时跳过后台 load */
private _lastLoadedAssetPath: string = '';
private isLoading: boolean = false; // ✅ 添加加载锁
private abortController: { aborted: boolean } = null; // ✅ 添加取消机制
onLoad() {
this.langSp = this.getComponent(sp.Skeleton);
}
onEnable() {
this.updateLang();
}
onDisable() {
if (this.abortController) {
this.abortController.aborted = true;
}
}
onDestroy() {
if (this.abortController) {
this.abortController.aborted = true;
}
if (this.curentSpineData && isValid(this.curentSpineData)) {
this.curentSpineData.decRef();
this.curentSpineData = null;
}
this._lastLoadedAssetPath = '';
}
/** 与 load 时一致的 Spine 资源相对路径(不含扩展名) */
private getAssetPath(): string {
const k = this.key || this.node.name;
return `${k}/${this.path}`;
}
updateLang() {
if (!this.node.isValid || this.langSp == null) return;
const assetPath = this.getAssetPath();
if (
this._lastLoadedAssetPath === assetPath &&
this.curentSpineData &&
isValid(this.curentSpineData) &&
this.langSp.skeletonData === this.curentSpineData
) {
// console.log("spineAsset 已加载", this.path, this.key);
return;
}
if (this.abortController) {
this.abortController.aborted = true;
}
this.abortController = { aborted: false };
if (this.isLoading) return;
this.isLoading = true;
const currentAbort = this.abortController;
const bundleName = GBundle.Comm;
const loop = this.langSp.loop;
// console.log("更新 lLoadSpine 组件", this.path, this.key);
this.loadBundle(bundleName).then((bundle) => {
if (currentAbort.aborted || !this.node.isValid) {
this.isLoading = false;
return null;
}
if (!bundle) {
this.isLoading = false;
return null;
}
return this.loadRes(bundle, assetPath, sp.SkeletonData);
}).then((spineAsset) => {
if (!spineAsset) return;
if (currentAbort.aborted || !this.node.isValid) {
this._releaseOrphanSpineAsset(spineAsset as sp.SkeletonData);
this.isLoading = false;
return;
}
const data = spineAsset as sp.SkeletonData;
if (this.curentSpineData == data) {
assetManager.releaseAsset(data);
this._lastLoadedAssetPath = assetPath;
this.isLoading = false;
return;
}
const oldres = this.curentSpineData;
this.curentSpineData = data;
data.addRef();
this._lastLoadedAssetPath = assetPath;
// console.log("spineAsset 加载完成", this.path, this.key);
this.langSp.clearTrack(0);
this.langSp.skeletonData = data;
if (this.node.isValid && this.animation) {
this.langSp.setSkin(this.skinName);
this.langSp.setAnimation(0, this.animation, loop);
this.kaichangSpine.setAnimation(0, '开场动画', loop);
this.zhuizhuSpine.setAnimation(0, '怪物追逐', loop);
}
if (oldres && oldres != data) {
this.scheduleOnce(() => {
if (oldres.refCount > 0) {
oldres.decRef();
}
}, 0.1);
}
this.isLoading = false;
}).catch((error) => {
// console.log("更新 lLoadSpine 组件失败", error);
this.isLoading = false;
});
}
setKey(key: string) {
this.key = key;
this.updateLang();
}
setPath(path: string) {
this.path = path;
this.updateLang();
}
private _releaseOrphanSpineAsset(spineAsset: sp.SkeletonData | null): void {
if (!spineAsset || spineAsset === this.curentSpineData) return;
assetManager.releaseAsset(spineAsset);
}
private loadBundle(bundleName) {
return new Promise<AssetManager.Bundle>((resolve, reject) => {
let bundle = assetManager.getBundle(bundleName);
if (bundle) {
resolve(bundle);
return;
}
assetManager.loadBundle(bundleName, (err, bundle) => {
if (err) {
// console.log(`加载Bundle:${bundleName}错误`, err);
resolve(null);
} else {
resolve(bundle);
}
})
})
}
private loadRes(bundle: AssetManager.Bundle, assetPath, type = Asset) {
return new Promise<Asset>((resolve, reject) => {
bundle.load(assetPath, type, (err, asset) => {
if (err) {
// console.log(`加载Bundle:${bundle.name},path:${assetPath}资源错误`, err);
resolve(null);
} else {
resolve(asset);
}
});
});
}
}