[ts][pixi-v7][pixi-v8] Add static createOptions for Spine init config to simplify subclassing; deprecate from(). (#2950)

* [ts][pixi-v7] extract Spine initialization data into getSpineInitData method

* [ts][pixi-v8] extract Spine initialization data into getSpineInitData method

* [ts][pixi-v8] Renamed getSpineInitData to createOptions. Deprecated from in favor of constructor accepting both SpineOptions and SpineFromOptions.

* [ts][pixi-v7] Renamed getSpineInitData to createOptions. Deprecated from in favor of constructor accepting both SpineOptions and SpineFromOptions.

* [ts][pixi-v7][pixi-v8] Refactored constructor.

---------

Co-authored-by: Eugene Avtukhov <eugene.avtukhov@3oaks.com>
Co-authored-by: Davide Tantillo <iamdjj@gmail.com>
This commit is contained in:
Eugene Avtuhov 2025-10-21 10:40:24 +02:00 committed by GitHub
parent 4a5cf750f5
commit 5bfb51ed0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 146 additions and 118 deletions

View File

@ -29,21 +29,21 @@
// Create the spine display object
const spineboy1 = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2 });
const spineboy1 = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2 });
const spineboy2 = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
const spineboy2 = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
boundsProvider: new spine.SetupPoseBoundsProvider(),
});
const spineboy3 = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
const spineboy3 = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
boundsProvider: new spine.SkinsAndAnimationBoundsProvider("portal", undefined, undefined, false),
});
const spineboy4 = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
const spineboy4 = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
boundsProvider: new spine.SkinsAndAnimationBoundsProvider("portal", undefined, undefined, true),
});
const spineboy5 = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
const spineboy5 = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
boundsProvider: new spine.AABBRectangleBoundsProvider(-100, -100, 100, 100),
});

View File

@ -88,7 +88,7 @@
bounds;
constructor(bounds) {
const spineboy = spine.Spine.from({
const spineboy = new spine.Spine({
atlas: "spineboyAtlas",
skeleton: "spineboyData",
scale: 0.125,

View File

@ -45,7 +45,7 @@
await PIXI.Assets.load(["stretchymanData", "stretchymanAtlas"]);
// Create the spine display object
const stretchyman = spine.Spine.from({skeleton: "stretchymanData", atlas: "stretchymanAtlas",
const stretchyman = new spine.Spine({skeleton: "stretchymanData", atlas: "stretchymanAtlas",
scale: 0.75,
});

View File

@ -39,7 +39,7 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the Spine display object
const spineboy = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas",
const spineboy = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas",
scale: 0.5,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the spine display object
const spineboy = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas",
const spineboy = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas",
scale: 0.5,
});

View File

@ -53,7 +53,7 @@
await PIXI.Assets.load(["skelBase64", "atlasBase64"]);
// creating spine game object with base64 data
const base64GameObject = spine.Spine.from({skeleton: "skelBase64", atlas: "atlasBase64" });
const base64GameObject = new spine.Spine({skeleton: "skelBase64", atlas: "atlasBase64" });
app.stage.addChild(base64GameObject);
base64GameObject.state.setAnimation(0, "animation", true);
base64GameObject.position.set(window.innerWidth / 3, window.innerHeight / 2);
@ -91,7 +91,7 @@
await PIXI.Assets.load(["skelBlob", "atlasBlob"]);
// creating spine game object
const blobGameObject = spine.Spine.from({skeleton: "skelBase64", atlas: "atlasBase64" });
const blobGameObject = new spine.Spine({skeleton: "skelBase64", atlas: "atlasBase64" });
app.stage.addChild(blobGameObject);
blobGameObject.state.setAnimation(0, "animation", true);
blobGameObject.position.set(window.innerWidth / 3 * 2, window.innerHeight / 2);

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["mixAndMatchData", "mixAndMatchAtlas"]);
// Create the Spine display object
const mixAndMatch = spine.Spine.from({skeleton: "mixAndMatchData", atlas: "mixAndMatchAtlas",
const mixAndMatch = new spine.Spine({skeleton: "mixAndMatchData", atlas: "mixAndMatchAtlas",
scale: 0.5,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the spine display object
const spineboy = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas",
const spineboy = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas",
scale: 0.5,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["sackData", "sackAtlas"]);
// Create the spine display object
const sack = spine.Spine.from({skeleton: "sackData", atlas: "sackAtlas",
const sack = new spine.Spine({skeleton: "sackData", atlas: "sackAtlas",
scale: 0.2,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["girlData", "girlAtlas"]);
// Create the spine display object
const girl = spine.Spine.from({skeleton: "girlData", atlas: "girlAtlas",
const girl = new spine.Spine({skeleton: "girlData", atlas: "girlAtlas",
scale: 0.2,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["snowglobeData", "snowglobeAtlas"]);
// Create the spine display object
const snowglobe = spine.Spine.from({skeleton: "snowglobeData", atlas: "snowglobeAtlas",
const snowglobe = new spine.Spine({skeleton: "snowglobeData", atlas: "snowglobeAtlas",
scale: 0.25,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["cloudPotData", "cloudPotAtlas"]);
// Create the spine display object
const cloudPot = spine.Spine.from({skeleton: "cloudPotData", atlas: "cloudPotAtlas",
const cloudPot = new spine.Spine({skeleton: "cloudPotData", atlas: "cloudPotAtlas",
scale: 0.25,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the spine display object
const spineboy = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas",
const spineboy = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas",
scale: 0.5,
});

View File

@ -36,7 +36,7 @@
PIXI.Assets.cache.set("spineboyAtlas", textureAtlas);
// creating spine game object
const spineGO = spine.Spine.from({skeleton: "jsonSkel", atlas: "spineboyAtlas" });
const spineGO = new spine.Spine({skeleton: "jsonSkel", atlas: "spineboyAtlas" });
spineGO.position.set(300, 300);
app.stage.addChild(spineGO);

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the spine display object
const spineboy = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas",
const spineboy = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas",
scale: 0.25,
});

View File

@ -1,5 +1,5 @@
import { Application, Assets } from 'pixi.js';
import { Spine } from '@esotericsoftware/spine-pixi-v7';
import { Application, Assets } from 'pixi.js';
/** The PixiJS app Application instance, shared across the project */
export const app = new Application<HTMLCanvasElement>({
@ -23,7 +23,8 @@ async function init () {
await Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the spine display object
const spineboy = Spine.from("spineboyData", "spineboyAtlas", {
const spineboy = new Spine({
skeleton: "spineboyData", atlas: "spineboyAtlas",
scale: 0.5,
});

View File

@ -40,7 +40,7 @@ import {
Skeleton,
SkeletonBinary,
SkeletonClipping,
SkeletonData,
type SkeletonData,
SkeletonJson,
Skin,
Utils,
@ -247,7 +247,8 @@ export class SkinsAndAnimationBoundsProvider
/**
* The class to instantiate a {@link Spine} game object in Pixi.
* The static method {@link Spine.from} should be used to instantiate a Spine game object.
* Create and customize the default configuration using the static method {@link Spine.createOptions},
* then pass it to the constructor.
*/
export class Spine extends Container {
/** The skeleton for this Spine game object. */
@ -328,29 +329,23 @@ export class Spine extends Container {
private _boundsSpineID = -1;
private _boundsSpineDirty = true;
constructor (options: SpineOptions | SkeletonData) {
if (options instanceof SkeletonData) {
options = {
skeletonData: options,
};
}
constructor (options: SpineOptions | SpineFromOptions) {
super();
const skeletonData = options instanceof SkeletonData ? options : options.skeletonData;
if ("skeleton" in options)
options = new.target.createOptions(options);
const { autoUpdate = true, boundsProvider, darkTint, skeletonData } = options;
this.skeleton = new Skeleton(skeletonData);
const animData = new AnimationStateData(skeletonData);
this.state = new AnimationState(animData);
this.autoUpdate = options?.autoUpdate ?? true;
this.state = new AnimationState(new AnimationStateData(skeletonData));
this.autoUpdate = autoUpdate;
this.boundsProvider = boundsProvider;
// dark tint can be enabled by options, otherwise is enable if at least one slot has tint black
this.darkTint = options?.darkTint === undefined
this.darkTint = darkTint === undefined
? this.skeleton.slots.some(slot => !!slot.data.setup.darkColor)
: options?.darkTint;
: darkTint;
if (this.darkTint) this.slotMeshFactory = () => new DarkSlotMesh();
this.boundsProvider = options.boundsProvider;
}
/** If {@link Spine.autoUpdate} is `false`, this method allows to update the AnimationState and the Skeleton with the given delta. */
@ -861,7 +856,7 @@ export class Spine extends Container {
public static readonly skeletonCache: Record<string, SkeletonData> = Object.create(null);
/**
* Use this method to instantiate a Spine game object.
* Get a convenient initialization configuration for your Spine game object.
* Before instantiating a Spine game object, the skeleton (`.skel` or `.json`) and the atlas text files must be loaded into the Assets. For example:
* ```
* PIXI.Assets.add("sackData", "/assets/sack-pro.skel");
@ -872,9 +867,9 @@ export class Spine extends Container {
* `${skeletonAssetName}-${atlasAssetName}-${options?.scale ?? 1}`
*
* @param options - Options to configure the Spine game object. See {@link SpineFromOptions}
* @returns {Spine} The Spine game object instantiated
* @returns {SpineOptions} The configuration ready to be passed to the Spine constructor
*/
public static from ({ skeleton, atlas, scale = 1, darkTint, autoUpdate = true, boundsProvider, allowMissingRegions }: SpineFromOptions) {
public static createOptions ({ skeleton, atlas, scale = 1, darkTint, autoUpdate = true, boundsProvider, allowMissingRegions }: SpineFromOptions): SpineOptions {
const cacheKey = `${skeleton}-${atlas}-${scale}`;
let skeletonData = Spine.skeletonCache[cacheKey];
@ -888,7 +883,25 @@ export class Spine extends Container {
skeletonData = parser.readSkeletonData(skeletonAsset);
Spine.skeletonCache[cacheKey] = skeletonData;
}
return new Spine({ skeletonData, darkTint, autoUpdate, boundsProvider });
return { skeletonData, darkTint, autoUpdate, boundsProvider };
}
/**
* @deprecated Use directly the Spine constructor or {@link createOptions} to make options and customize it to pass to the constructor
* Before instantiating a Spine game object, the skeleton (`.skel` or `.json`) and the atlas text files must be loaded into the Assets. For example:
* ```
* PIXI.Assets.add("sackData", "/assets/sack-pro.skel");
* PIXI.Assets.add("sackAtlas", "/assets/sack-pma.atlas");
* await PIXI.Assets.load(["sackData", "sackAtlas"]);
* ```
* Once a Spine game object is created, its skeleton data is cached into {@link Spine.skeletonCache} using the key:
* `${skeletonAssetName}-${atlasAssetName}-${options?.scale ?? 1}`
*
* @param options - Options to configure the Spine game object. See {@link SpineFromOptions}
* @returns {Spine} The Spine game object instantiated
*/
public static from (options: SpineFromOptions) {
return new Spine(Spine.createOptions(options));
}
public get tint (): number {

View File

@ -29,21 +29,21 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the spine display object
const spineboy1 = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2 });
const spineboy1 = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2 });
const spineboy2 = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
const spineboy2 = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
boundsProvider: new spine.SetupPoseBoundsProvider(),
});
const spineboy3 = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
const spineboy3 = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
boundsProvider: new spine.SkinsAndAnimationBoundsProvider("portal", undefined, undefined, false),
});
const spineboy4 = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
const spineboy4 = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
boundsProvider: new spine.SkinsAndAnimationBoundsProvider("portal", undefined, undefined, true),
});
const spineboy5 = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
const spineboy5 = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: .2,
boundsProvider: new spine.AABBRectangleBoundsProvider(-100, -100, 100, 100),
});

View File

@ -98,7 +98,7 @@
bounds;
constructor(bounds) {
const spineboy = spine.Spine.from({
const spineboy = new spine.Spine({
atlas: "spineboyAtlas",
skeleton: "spineboyData",
scale: 0.125,

View File

@ -30,7 +30,7 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the spine display object
const spineboy = spine.Spine.from({
const spineboy = new spine.Spine({
skeleton: "spineboyData",
atlas: "spineboyAtlas",
scale: 1,

View File

@ -45,7 +45,7 @@
await PIXI.Assets.load(["stretchymanData", "stretchymanAtlas"]);
// Create the spine display object
const stretchyman = spine.Spine.from({skeleton: "stretchymanData", atlas: "stretchymanAtlas",
const stretchyman = new spine.Spine({skeleton: "stretchymanData", atlas: "stretchymanAtlas",
scale: 0.75,
});

View File

@ -32,8 +32,8 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas", "spineboyData", "spineboyAtlas2"]);
// Create the spine display object
const spineboy = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: 0.5 });
const spineboy2 = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: 0.5 });
const spineboy = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: 0.5 });
const spineboy2 = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: 0.5 });
spineboy.autoUpdate = false;
spineboy2.autoUpdate = false;

View File

@ -39,7 +39,7 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the Spine display object
const spineboy = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas",
const spineboy = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas",
scale: 0.5,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the spine display object
const spineboy = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas",
const spineboy = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas",
scale: 0.5,
});

View File

@ -52,7 +52,7 @@
await PIXI.Assets.load(["skelBase64", "atlasBase64"]);
// creating spine game object with base64 data
const base64GameObject = spine.Spine.from({skeleton: "skelBase64", atlas: "atlasBase64" });
const base64GameObject = new spine.Spine({skeleton: "skelBase64", atlas: "atlasBase64" });
app.stage.addChild(base64GameObject);
base64GameObject.state.setAnimation(0, "animation", true);
base64GameObject.position.set(window.innerWidth / 3, window.innerHeight / 2);
@ -90,7 +90,7 @@
await PIXI.Assets.load(["skelBlob", "atlasBlob"]);
// creating spine game object
const blobGameObject = spine.Spine.from({skeleton: "skelBase64", atlas: "atlasBase64" });
const blobGameObject = new spine.Spine({skeleton: "skelBase64", atlas: "atlasBase64" });
app.stage.addChild(blobGameObject);
blobGameObject.state.setAnimation(0, "animation", true);
blobGameObject.position.set(window.innerWidth / 3 * 2, window.innerHeight / 2);

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["mixAndMatchData", "mixAndMatchAtlas"]);
// Create the Spine display object
const mixAndMatch = spine.Spine.from({skeleton: "mixAndMatchData", atlas: "mixAndMatchAtlas",
const mixAndMatch = new spine.Spine({skeleton: "mixAndMatchData", atlas: "mixAndMatchAtlas",
scale: 0.5,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the spine display object
const spineboy = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas",
const spineboy = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas",
scale: 0.5,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["sackData", "sackAtlas"]);
// Create the spine display object
const sack = spine.Spine.from({skeleton: "sackData", atlas: "sackAtlas",
const sack = new spine.Spine({skeleton: "sackData", atlas: "sackAtlas",
scale: 0.2,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["girlData", "girlAtlas"]);
// Create the spine display object
const girl = spine.Spine.from({skeleton: "girlData", atlas: "girlAtlas",
const girl = new spine.Spine({skeleton: "girlData", atlas: "girlAtlas",
scale: 0.2,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["snowglobeData", "snowglobeAtlas"]);
// Create the spine display object
const snowglobe = spine.Spine.from({skeleton: "snowglobeData", atlas: "snowglobeAtlas",
const snowglobe = new spine.Spine({skeleton: "snowglobeData", atlas: "snowglobeAtlas",
scale: 0.25,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["cloudPotData", "cloudPotAtlas"]);
// Create the spine display object
const cloudPot = spine.Spine.from({skeleton: "cloudPotData", atlas: "cloudPotAtlas",
const cloudPot = new spine.Spine({skeleton: "cloudPotData", atlas: "cloudPotAtlas",
scale: 0.25,
});

View File

@ -28,7 +28,7 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the spine display object
const spineboy = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas",
const spineboy = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas",
scale: 0.5,
});

View File

@ -35,7 +35,7 @@
PIXI.Assets.cache.set("spineboyAtlas", textureAtlas);
// creating spine game object
const spineGO = spine.Spine.from({skeleton: "jsonSkel", atlas: "spineboyAtlas" });
const spineGO = new spine.Spine({ skeleton: "jsonSkel", atlas: "spineboyAtlas" });
spineGO.position.set(300, 300);
app.stage.addChild(spineGO);

View File

@ -29,7 +29,7 @@
await PIXI.Assets.load(["spineboyData", "spineboyAtlas", "raptor_jaw"]);
// Create the spine display object
const spineboy = spine.Spine.from({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: 0.25 });
const spineboy = new spine.Spine({skeleton: "spineboyData", atlas: "spineboyAtlas", scale: 0.25 });
// Set the default mix time to use when transitioning
// from one animation to the next.

View File

@ -1,5 +1,5 @@
import { Application, Assets } from 'pixi.js';
import { Spine } from '@esotericsoftware/spine-pixi-v8';
import { Application, Assets } from 'pixi.js';
/** The PixiJS app Application instance, shared across the project */
export const app = new Application();
@ -25,7 +25,7 @@ async function init () {
await Assets.load(["spineboyData", "spineboyAtlas"]);
// Create the spine display object
const spineboy = Spine.from({
const spineboy = new Spine({
atlas: "spineboyAtlas",
skeleton: "spineboyData",
scale: 0.5,

View File

@ -43,7 +43,7 @@ import {
SkeletonBinary,
SkeletonBounds,
SkeletonClipping,
SkeletonData,
type SkeletonData,
SkeletonJson,
Skin,
type Slot,
@ -292,7 +292,8 @@ const maskPool = new Pool<Graphics>(() => new Graphics);
/**
* The class to instantiate a {@link Spine} game object in Pixi.
* The static method {@link Spine.from} should be used to instantiate a Spine game object.
* Create and customize the default configuration using the static method {@link Spine.createOptions},
* then pass it to the constructor.
*/
export class Spine extends ViewContainer {
// Pixi properties
@ -384,35 +385,28 @@ export class Spine extends ViewContainer {
}
private hasNeverUpdated = true;
constructor (options: SpineOptions | SkeletonData) {
if (options instanceof SkeletonData) {
options = {
skeletonData: options,
};
}
constructor (options: SpineOptions | SpineFromOptions) {
super({});
if ("skeleton" in options)
options = new.target.createOptions(options);
this.allowChildren = true;
const skeletonData = options instanceof SkeletonData ? options : options.skeletonData;
const { autoUpdate, boundsProvider, darkTint, skeletonData } = options;
this.skeleton = new Skeleton(skeletonData);
this.state = new AnimationState(new AnimationStateData(skeletonData));
this.autoUpdate = options?.autoUpdate ?? true;
this.autoUpdate = autoUpdate ?? true;
this._boundsProvider = boundsProvider;
// dark tint can be enabled by options, otherwise is enable if at least one slot has tint black
this.darkTint = options?.darkTint === undefined
this.darkTint = darkTint === undefined
? this.skeleton.slots.some(slot => !!slot.data.setup.darkColor)
: options?.darkTint;
: darkTint;
const slots = this.skeleton.slots;
for (let i = 0; i < slots.length; i++) {
for (let i = 0; i < slots.length; i++)
this.attachmentCacheData[i] = Object.create(null);
}
this._boundsProvider = options.boundsProvider;
}
/** If {@link Spine.autoUpdate} is `false`, this method allows to update the AnimationState and the Skeleton with the given delta. */
@ -1065,6 +1059,55 @@ export class Spine extends ViewContainer {
}
/**
* Get a convenient initialization configuration for your Spine game object.
* Before instantiating a Spine game object, the skeleton (`.skel` or `.json`) and the atlas text files must be loaded into the {@link Assets}. For example:
* ```
* PIXI.Assets.add("sackData", "/assets/sack-pro.skel");
* PIXI.Assets.add("sackAtlas", "/assets/sack-pma.atlas");
* await PIXI.Assets.load(["sackData", "sackAtlas"]);
* ```
* Once a Spine game object is created, its skeleton data is cached into {@link Cache} using the key:
* `${skeletonAssetName}-${atlasAssetName}-${options?.scale ?? 1}`
*
* @param options - Options to configure the Spine game object. See {@link SpineFromOptions}
* @returns {SpineOptions} The configuration ready to be passed to the Spine constructor
*/
static createOptions ({ skeleton, atlas, scale = 1, darkTint, autoUpdate = true, boundsProvider, allowMissingRegions = false }: SpineFromOptions): SpineOptions {
const cacheKey = `${skeleton}-${atlas}-${scale}`;
if (Cache.has(cacheKey)) {
return {
skeletonData: Cache.get<SkeletonData>(cacheKey),
darkTint,
autoUpdate,
boundsProvider,
};
}
const atlasAsset = Assets.get<TextureAtlas>(atlas);
const attachmentLoader = new AtlasAttachmentLoader(atlasAsset, allowMissingRegions);
// biome-ignore lint/suspicious/noExplicitAny: json skeleton data is any
const skeletonAsset = Assets.get<any | Uint8Array>(skeleton);
const parser = skeletonAsset instanceof Uint8Array
? new SkeletonBinary(attachmentLoader)
: new SkeletonJson(attachmentLoader);
parser.scale = scale;
const skeletonData = parser.readSkeletonData(skeletonAsset);
Cache.set(cacheKey, skeletonData);
return {
skeletonData,
darkTint,
autoUpdate,
boundsProvider,
};
}
/**
* @deprecated Use directly the Spine constructor or {@link createOptions} to make options and customize it to pass to the constructor
* Use this method to instantiate a Spine game object.
* Before instantiating a Spine game object, the skeleton (`.skel` or `.json`) and the atlas text files must be loaded into the Assets. For example:
* ```
@ -1078,36 +1121,7 @@ export class Spine extends ViewContainer {
* @param options - Options to configure the Spine game object. See {@link SpineFromOptions}
* @returns {Spine} The Spine game object instantiated
*/
static from ({ skeleton, atlas, scale = 1, darkTint, autoUpdate = true, boundsProvider, allowMissingRegions = false }: SpineFromOptions) {
const cacheKey = `${skeleton}-${atlas}-${scale}`;
if (Cache.has(cacheKey)) {
return new Spine({
skeletonData: Cache.get<SkeletonData>(cacheKey),
darkTint,
autoUpdate,
boundsProvider,
});
}
const skeletonAsset = Assets.get<any | Uint8Array>(skeleton);
const atlasAsset = Assets.get<TextureAtlas>(atlas);
const attachmentLoader = new AtlasAttachmentLoader(atlasAsset, allowMissingRegions);
const parser = skeletonAsset instanceof Uint8Array
? new SkeletonBinary(attachmentLoader)
: new SkeletonJson(attachmentLoader);
parser.scale = scale;
const skeletonData = parser.readSkeletonData(skeletonAsset);
Cache.set(cacheKey, skeletonData);
return new Spine({
skeletonData,
darkTint,
autoUpdate,
boundsProvider,
});
static from (options: SpineFromOptions) {
return new Spine(Spine.createOptions(options));
}
}