分享:FGUI spine 资源加载回调

Hong
Mon, 27 Apr 2026 03:55:42 +0000

FGUI原版GLoader3D加载spine后没有回调,也没有事件发出,外部使用无法得知资源什么时候加载成功.
exp:

const loader: fgui.GLoader3D = self.getChild(`spine`) as fgui.GLoader3D;
loader.url = `ui://${self.getFGUIPackage()}/Scatter`;
const skeleton: sp.Skeleton = loader.content as sp.Skeleton;
skeleton.setAnimation(0, 'animation', true);

loader.url会触发资源加载,加载有个过程,所以此时loader.content为空无法进行后续操作.

import { dragonBones, sp, Vec2 } from 'cc';
import * as fgui from 'fairygui-cc';

type GLoader3DExLoadedCallback = () => void;
/**
 * GLoader3D 扩展类，增加了加载完成回调，方便在加载完成后进行一些操作，如播放动画等
 */
export class GLoader3DEx extends fgui.GLoader3D {
    private _loadedCallback: GLoader3DExLoadedCallback | null = null;

    public set url(value: string | null) {
        this._loadedCallback = null;
        super.url = value;
    }

    public loadRes(url: string, loadedCallback?: GLoader3DExLoadedCallback): void {
        this._loadedCallback = loadedCallback || null;
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        (this as any)['_url'] = url;
        this.loadContent();
        this.updateGear(7);
    }

    public setSpine(asset: sp.SkeletonData, anchor: Vec2, pma?: boolean): void {
        super.setSpine(asset, anchor, pma);
        this._loadedCallback?.();
    }

    public setDragonBones(asset: dragonBones.DragonBonesAsset, atlasAsset: dragonBones.DragonBonesAtlasAsset, anchor: Vec2, pma?: boolean): void {
        super.setDragonBones(asset, atlasAsset, anchor, pma);
        this._loadedCallback?.();
    }
}

/**
 * FGUI 工具类
 */
export default class FGUIUtil {
    public static init(): void {
        FGUIUtil.registLoader3D();
    }

    private static registLoader3D(): void {
        // eslint-disable-next-line @typescript-eslint/typedef
        const originalNewObject = fgui.UIObjectFactory.newObject;

        // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
        fgui.UIObjectFactory.newObject = function (type: number | fgui.PackageItem, userClass?: new () => fgui.GObject) {
            if (typeof type === 'number' && type === fgui.ObjectType.Loader3D) {
                return new GLoader3DEx();
            }

            if (type instanceof fgui.PackageItem && (type.type === fgui.PackageItemType.Spine || type.type === fgui.PackageItemType.DragonBones)) {
                return new GLoader3DEx();
            }

            return originalNewObject.call(fgui.UIObjectFactory, type, userClass);
        };
    }
}

初始化:
在fgui初始化之前FGUIUtil.init() 一般放到启动时即可

使用:

//加载后进行操作
const loader: GLoader3DEx = self.getChild('spine')! as GLoader3DEx;
loader.loadRes(`url`, () => {
    let skeleton: sp.Skeleton = loader.content as sp.Skeleton;
    skeleton.setSkin(`default`);
    skeleton.setAnimation(0, 'animation', true);
});

//不关心资源加载
const loader: GLoader3DEx = self.getChild(`spine`) as GLoader3DEx;
loader.url = `url`;

//也可以和以前一样
const loader: fgui.GLoader3D = self.getChild(`spine`) as fgui.GLoader3D;
loader.url = `url`;

吐槽:
在creator自带编辑这么强大的今天,还有老艺术家固持己见

阅读整个主题