From 8f4d510c15576a2ab8b3d15425f3b6c63e1ed583 Mon Sep 17 00:00:00 2001 From: Zyie <24736175+Zyie@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:34:17 +0100 Subject: [PATCH] chore: update to esoteric api naming (#12) Co-authored-by: Mat Groves --- examples/assets/spine_logo.png | Bin 0 -> 3495 bytes examples/events-example.html | 6 +- examples/index.html | 2 +- examples/manual-loading.html | 6 +- examples/mix-and-match-example.html | 6 +- examples/mouse-following.html | 9 +- examples/simple-input.html | 58 ++++++++-- examples/slot-objects.html | 125 ++++++++++++++++++++ src/Spine.ts | 173 ++++++++++++++++------------ src/SpinePipe.ts | 12 +- 10 files changed, 290 insertions(+), 107 deletions(-) create mode 100644 examples/assets/spine_logo.png create mode 100644 examples/slot-objects.html diff --git a/examples/assets/spine_logo.png b/examples/assets/spine_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..40e65c5c91884ba3af3a5d70cb8eb265c6b3baeb GIT binary patch literal 3495 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 spine-pixi - + @@ -35,8 +35,8 @@ document.body.appendChild(app.view); // Pre-load the skeleton data and atlas. You can also load .json skeleton data. - PIXI.Assets.add("spineboyData", "./assets/spineboy-pro.skel"); - PIXI.Assets.add("spineboyAtlas", "./assets/spineboy-pma.atlas"); + PIXI.Assets.add({alias: "spineboyData", src: "./assets/spineboy-pro.skel" }); + PIXI.Assets.add({alias: "spineboyAtlas", src: "./assets/spineboy-pma.atlas" }); await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]); // Create the Spine display object diff --git a/examples/index.html b/examples/index.html index da69aff..f1b9866 100644 --- a/examples/index.html +++ b/examples/index.html @@ -2,7 +2,7 @@ spine-pixi - + diff --git a/examples/manual-loading.html b/examples/manual-loading.html index 1792aa3..7acbd87 100644 --- a/examples/manual-loading.html +++ b/examples/manual-loading.html @@ -2,7 +2,7 @@ spine-pixi - + @@ -24,8 +24,8 @@ document.body.appendChild(app.view); // Pre-load the skeleton data and atlas. You can also load .json skeleton data. - PIXI.Assets.add("spineboyData", "./assets/spineboy-pro.skel"); - PIXI.Assets.add("spineboyAtlas", "./assets/spineboy-pma.atlas"); + PIXI.Assets.add({alias: "spineboyData", src: "./assets/spineboy-pro.skel" }); + PIXI.Assets.add({alias: "spineboyAtlas", src: "./assets/spineboy-pma.atlas" }); await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]); // Manually load the data and create a Spine display object from it using diff --git a/examples/mix-and-match-example.html b/examples/mix-and-match-example.html index 30a636a..ac69f38 100644 --- a/examples/mix-and-match-example.html +++ b/examples/mix-and-match-example.html @@ -2,7 +2,7 @@ spine-pixi - + @@ -24,8 +24,8 @@ document.body.appendChild(app.view); // Pre-load the skeleton data and atlas. You can also load .json skeleton data. - PIXI.Assets.add("mixAndMatchData", "./assets/mix-and-match-pro.skel"); - PIXI.Assets.add("mixAndMatchAtlas", "./assets/mix-and-match-pma.atlas"); + PIXI.Assets.add({alias: "mixAndMatchData", src: "./assets/mix-and-match-pro.skel" }); + PIXI.Assets.add({alias: "mixAndMatchAtlas", src: "./assets/mix-and-match-pma.atlas" }); await PIXI.Assets.load(["mixAndMatchData", "mixAndMatchAtlas"]); // Create the Spine display object diff --git a/examples/mouse-following.html b/examples/mouse-following.html index 9038b26..b157ba7 100644 --- a/examples/mouse-following.html +++ b/examples/mouse-following.html @@ -2,7 +2,7 @@ Spine Pixi Example - + @@ -24,8 +24,8 @@ document.body.appendChild(app.view); // Pre-load the skeleton data and atlas. You can also load .json skeleton data. - PIXI.Assets.add("spineboyData", "./assets/spineboy-pro.skel"); - PIXI.Assets.add("spineboyAtlas", "./assets/spineboy-pma.atlas"); + PIXI.Assets.add({alias: "spineboyData", src: "./assets/spineboy-pro.skel" }); + PIXI.Assets.add({alias: "spineboyAtlas", src: "./assets/spineboy-pma.atlas" }); await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]); // Create the spine display object @@ -47,6 +47,7 @@ // Add the display object to the stage. app.stage.addChild(spineboy); + app.stage.hitArea = new PIXI.Rectangle(0, 0, app.view.width, app.view.height); // Make the stage interactive and register pointer events app.stage.eventMode = "dynamic"; @@ -57,7 +58,7 @@ setBonePosition(e); }); - app.stage.on("pointermove", (e) => { + app.stage.on("globalpointermove", (e) => { if (isDragging) setBonePosition(e); }); diff --git a/examples/simple-input.html b/examples/simple-input.html index 8220bf1..5c13edd 100644 --- a/examples/simple-input.html +++ b/examples/simple-input.html @@ -2,7 +2,7 @@ spine-pixi - + @@ -24,8 +24,8 @@ document.body.appendChild(app.view); // Pre-load the skeleton data and atlas. You can also load .json skeleton data. - PIXI.Assets.add("spineboyData", "./assets/spineboy-pro.skel"); - PIXI.Assets.add("spineboyAtlas", "./assets/spineboy-pma.atlas"); + PIXI.Assets.add({alias: "spineboyData", src: "./assets/spineboy-pro.skel" }); + PIXI.Assets.add({alias: "spineboyAtlas", src: "./assets/spineboy-pma.atlas" }); await PIXI.Assets.load(["spineboyData", "spineboyAtlas"]); // Create the spine display object @@ -35,7 +35,7 @@ // Set the default animation and the // default mix for transitioning between animations. - spineboy.state.setAnimation(0, "run", true); + spineboy.state.setAnimation(0, "hoverboard", true); spineboy.state.data.defaultMix = 0.2; // Center the spine object on screen. @@ -43,20 +43,56 @@ spineboy.y = window.innerHeight / 2 + spineboy.getBounds().height / 2; // Make it so that you can interact with Spineboy. - // Also, handle the case that you click or tap on the screen. - // The callback function definition can be seen below. + // Handle the case that you click/tap the screen. spineboy.eventMode = 'static'; spineboy.on('pointerdown', onClick); - + // Add the display object to the stage. app.stage.addChild(spineboy); + + // Add variables for movement, speed. + let moveLeft = false; + let moveRight = false; + const speed = 5; + + // Handle the case that the keyboard keys specified below are pressed. + function onKeyDown(key) { + if (key.code === "ArrowLeft" || key.code === "KeyA") { + moveLeft = true; + spineboy.skeleton.scaleX = -1; + } else if (key.code === "ArrowRight" || key.code === "KeyD") { + moveRight = true; + spineboy.skeleton.scaleX = 1; + } + } + + // Handle when the keys are released, if they were pressed. + function onKeyUp(key) { + if (key.code === "ArrowLeft" || key.code === "KeyA") { + moveLeft = false; + } else if (key.code === "ArrowRight" || key.code === "KeyD") { + moveRight = false; + } + } - // This callback function handles what happens - // when you click or tap on the screen. + // Handle if you click/tap the screen. function onClick() { - spineboy.state.addAnimation(0, "jump", false, 0); - spineboy.state.addAnimation(0, "idle", true, 0); + spineboy.state.setAnimation(1, "shoot", false, 0); } + + // Add event listeners so that the window will correctly handle input. + window.addEventListener("keydown", onKeyDown); + window.addEventListener("keyup", onKeyUp); + + // Update the application to move Spineboy if input is detected. + app.ticker.add(() => { + if (moveLeft) { + spineboy.x -= speed; + } + if (moveRight) { + spineboy.x += speed; + } + }); })(); diff --git a/examples/slot-objects.html b/examples/slot-objects.html new file mode 100644 index 0000000..3f09381 --- /dev/null +++ b/examples/slot-objects.html @@ -0,0 +1,125 @@ + + + + spine-pixi + + + + + + + + + + diff --git a/src/Spine.ts b/src/Spine.ts index 36f0097..3e47243 100644 --- a/src/Spine.ts +++ b/src/Spine.ts @@ -37,7 +37,7 @@ import { DestroyOptions, PointData, Ticker, - View + View, } from 'pixi.js'; import { ISpineDebugRenderer } from './SpineDebugRenderer'; import { @@ -59,7 +59,7 @@ import { Slot, type TextureAtlas, TrackEntry, - Vector2 + Vector2, } from '@esotericsoftware/spine-core'; export type SpineFromOptions = { @@ -94,6 +94,7 @@ export interface SpineEvents export interface AttachmentCacheData { + id: string; clipped: boolean; vertices: Float32Array; uvs: Float32Array; @@ -103,8 +104,8 @@ export interface AttachmentCacheData vertices: Float32Array; uvs: Float32Array; indices: Uint16Array; - vertexCount: number, - indicesCount: number, + vertexCount: number; + indicesCount: number; }; } @@ -117,7 +118,7 @@ export class Spine extends Container implements View public _didSpineUpdate = false; public _boundsDirty = true; public _roundPixels: 0 | 1; - private _bounds:Bounds = new Bounds(); + private _bounds: Bounds = new Bounds(); // Spine properties public skeleton: Skeleton; @@ -125,7 +126,20 @@ export class Spine extends Container implements View public skeletonBounds: SkeletonBounds; private _debug?: ISpineDebugRenderer | undefined = undefined; - readonly _slotAttachments:{slot:Slot, container:Container}[] = []; + readonly _slotsObject: Record = Object.create(null); + + private getSlotFromRef(slotRef: number | string | Slot): Slot + { + let slot: Slot | null; + + if (typeof slotRef === 'number') slot = this.skeleton.slots[slotRef]; + else if (typeof slotRef === 'string') slot = this.skeleton.findSlot(slotRef); + else slot = slotRef; + + if (!slot) throw new Error(`No slot found with the given slot reference: ${slotRef}`); + + return slot; + } public spineAttachmentsDirty: boolean; private _lastAttachments: Attachment[]; @@ -174,12 +188,12 @@ export class Spine extends Container implements View this._autoUpdate = value; } - constructor(options:SpineOptions | SkeletonData) + constructor(options: SpineOptions | SkeletonData) { if (options instanceof SkeletonData) { options = { - skeletonData: options + skeletonData: options, }; } @@ -196,8 +210,10 @@ export class Spine extends Container implements View { if (this.autoUpdate && !this.autoUpdateWarned) { - // eslint-disable-next-line max-len - console.warn('You are calling update on a Spine instance that has autoUpdate set to true. This is probably not what you want.'); + console.warn( + // eslint-disable-next-line max-len + 'You are calling update on a Spine instance that has autoUpdate set to true. This is probably not what you want.', + ); this.autoUpdateWarned = true; } @@ -208,7 +224,7 @@ export class Spine extends Container implements View { // Because reasons, pixi uses deltaFrames at 60fps. // We ignore the default deltaFrames and use the deltaSeconds from pixi ticker. - this.updateState(deltaSeconds ?? Ticker.shared.deltaMS / 1000); + this._updateState(deltaSeconds ?? Ticker.shared.deltaMS / 1000); } get bounds() @@ -279,8 +295,9 @@ export class Spine extends Container implements View * as this is differed until the `applyState` method is called. * * @param time the time at which to set the state + * @internal */ - updateState(time:number) + _updateState(time: number) { this.state.update(time); @@ -298,8 +315,9 @@ export class Spine extends Container implements View * - validates the attachments - to flag if the attachments have changed this state * - transforms the attachments - to update the vertices of the attachments based on the new positions * - update the slot attachments - to update the position, rotation, scale, and visibility of the attached containers + * @internal */ - applyState() + _applyState() { if (!this._stateChanged) return; this._stateChanged = false; @@ -321,7 +339,7 @@ export class Spine extends Container implements View { const currentDrawOrder = this.skeleton.drawOrder; - const lastAttachments = this._lastAttachments ||= []; + const lastAttachments = (this._lastAttachments ||= []); let index = 0; @@ -375,7 +393,14 @@ export class Spine extends Container implements View } else { - attachment.computeWorldVertices(slot, 0, attachment.worldVerticesLength, cacheData.vertices, 0, 2); + attachment.computeWorldVertices( + slot, + 0, + attachment.worldVerticesLength, + cacheData.vertices, + 0, + 2, + ); } cacheData.clipped = false; @@ -434,7 +459,7 @@ export class Spine extends Container implements View const clippedData = cacheData.clippedData; - const sizeChange = (clippedData.vertexCount !== verticesCount || indicesCount !== clippedData.indicesCount); + const sizeChange = clippedData.vertexCount !== verticesCount || indicesCount !== clippedData.indicesCount; if (sizeChange) { @@ -473,15 +498,18 @@ export class Spine extends Container implements View clippedData.indicesCount = indicesCount; } + /** * ensure that attached containers map correctly to their slots * along with their position, rotation, scale, and visibility. */ private updateSlotAttachments() { - for (let i = 0; i < this._slotAttachments.length; i++) + for (const i in this._slotsObject) { - const slotAttachment = this._slotAttachments[i]; + const slotAttachment = this._slotsObject[i]; + + if (!slotAttachment) continue; const { slot, container } = slotAttachment; @@ -501,35 +529,36 @@ export class Spine extends Container implements View container.rotation = Math.atan2( Math.sin(rotationX) + Math.sin(rotationY), - Math.cos(rotationX) + Math.cos(rotationY) + Math.cos(rotationX) + Math.cos(rotationY), ); } } } - getCachedData(slot: Slot, attachment: RegionAttachment | MeshAttachment):AttachmentCacheData + getCachedData(slot: Slot, attachment: RegionAttachment | MeshAttachment): AttachmentCacheData { const key = `${slot.data.index}-${attachment.name}`; return this.attachmentCacheData[key] || this.initCachedData(slot, attachment); } - private initCachedData(slot: Slot, attachment: RegionAttachment | MeshAttachment):AttachmentCacheData + private initCachedData(slot: Slot, attachment: RegionAttachment | MeshAttachment): AttachmentCacheData { const key = `${slot.data.index}-${attachment.name}`; - let vertices:Float32Array; + let vertices: Float32Array; if (attachment instanceof RegionAttachment) { vertices = new Float32Array(8); this.attachmentCacheData[key] = { + id: key, vertices, clipped: false, indices: [0, 1, 2, 0, 2, 3], uvs: attachment.uvs as Float32Array, - color: slot.color + color: slot.color, }; } else @@ -537,11 +566,12 @@ export class Spine extends Container implements View vertices = new Float32Array(attachment.worldVerticesLength); this.attachmentCacheData[key] = { + id: key, vertices, clipped: false, indices: attachment.triangles, uvs: attachment.uvs as Float32Array, - color: slot.color + color: slot.color, }; } @@ -573,32 +603,40 @@ export class Spine extends Container implements View * to the attached container. A container can only be attached to one slot at a time. * * @param container - The container to attach to the slot - * @param slot - The slot id or slot to attach to + * @param slotRef - The slot id or slot to attach to */ - attachToSlot(container:Container, slot:string | Slot) + addSlotObject(slot: number | string | Slot, container: Container) { - this.detachFromSlot(container, slot); - - container.includeInBuild = false; + slot = this.getSlotFromRef(slot); - if (typeof slot === 'string') + // need to check in on the container too... + for (const i in this._slotsObject) { - slot = this.skeleton.findSlot(slot) as Slot; + if (this._slotsObject[i]?.container === container) + { + this.removeSlotObject(this._slotsObject[i].slot); + } } - if (!slot) - { - throw new Error(`Slot ${slot} not found`); - } + this.removeSlotObject(slot); + + container.includeInBuild = false; // TODO only add once?? this.addChild(container); // TODO search for copies... - one container - to one bone! - this._slotAttachments.push({ - slot, - container - }); + this._slotsObject[slot.data.name] = { + container, + slot + }; + + const renderGroup = this.renderGroup || this.parentRenderGroup; + + if (renderGroup) + { + renderGroup.structureDidChange = true; + } } /** @@ -607,53 +645,33 @@ export class Spine extends Container implements View * @param container - The container to detach from the slot * @param slot - The slot id or slot to detach from */ - detachFromSlot(container:Container, slot:string | Slot) + removeSlotObject(slot: number | string | Slot) { - container.includeInBuild = true; - - if (typeof slot === 'string') - { - slot = this.skeleton.findSlot(slot) as Slot; - } - - if (!slot) - { - throw new Error(`Bone ${slot} not found`); - } + slot = this.getSlotFromRef(slot); - this.removeChild(container); + const container = this._slotsObject[slot.data.name]?.container; - for (let i = 0; i < this._slotAttachments.length; i++) + if (container) { - const mapping = this._slotAttachments[i]; + this.removeChild(container); - if (mapping.slot === slot && mapping.container === container) - { - this._slotAttachments.splice(i, 1); - break; - } + container.includeInBuild = true; } + + this._slotsObject[slot.data.name] = null; } /** * Returns a container attached to a slot, or undefined if no container is attached. * - * @param slot - The slot id or slot to get the attachment from + * @param slotRef - The slot id or slot to get the attachment from * @returns - The container attached to the slot */ - getSlotAttachment(slot:string | Slot) + getSlotObject(slot: number | string | Slot) { - if (typeof slot === 'string') - { - slot = this.skeleton.findSlot(slot) as Slot; - } - - if (!slot) - { - throw new Error(`Slot ${slot} not found`); - } + slot = this.getSlotFromRef(slot); - return this._slotAttachments.find((mapping) => mapping.slot === slot)?.container; + return this._slotsObject[slot.data.name].container; } updateBounds() @@ -668,7 +686,7 @@ export class Spine extends Container implements View if (skeletonBounds.minX === Infinity) { - this.applyState(); + this._applyState(); const drawOrder = this.skeleton.drawOrder; const bounds = this._bounds; @@ -734,7 +752,7 @@ export class Spine extends Container implements View this.debug = undefined; this.skeleton = null as any; this.state = null as any; - (this._slotAttachments as any) = null; + (this._slotsObject as any) = null; this._lastAttachments = null; this.attachmentCacheData = null as any; } @@ -750,7 +768,7 @@ export class Spine extends Container implements View this._roundPixels = value ? 1 : 0; } - static from({ skeleton, atlas, scale = 1 }:SpineFromOptions) + static from({ skeleton, atlas, scale = 1 }: SpineFromOptions) { const cacheKey = `${skeleton}-${atlas}`; @@ -764,7 +782,10 @@ export class Spine extends Container implements View const atlasAsset = Assets.get(atlas); const attachmentLoader = new AtlasAttachmentLoader(atlasAsset); // eslint-disable-next-line max-len - const parser = skeletonAsset instanceof Uint8Array ? new SkeletonBinary(attachmentLoader) : new SkeletonJson(attachmentLoader); + const parser + = skeletonAsset instanceof Uint8Array + ? new SkeletonBinary(attachmentLoader) + : new SkeletonJson(attachmentLoader); // TODO scale? parser.scale = scale; @@ -773,7 +794,7 @@ export class Spine extends Container implements View Cache.set(cacheKey, skeletonData); return new Spine({ - skeletonData + skeletonData, }); } } diff --git a/src/SpinePipe.ts b/src/SpinePipe.ts index 63d14f6..9c8d432 100644 --- a/src/SpinePipe.ts +++ b/src/SpinePipe.ts @@ -72,7 +72,7 @@ export class SpinePipe implements RenderPipe validateRenderable(spine: Spine): boolean { - spine.applyState(); + spine._applyState(); // loop through and see if the mesh lengths have changed.. return spine.spineAttachmentsDirty; @@ -88,7 +88,7 @@ export class SpinePipe implements RenderPipe const roundPixels = (this.renderer._roundPixels | spine._roundPixels) as 0 | 1; - spine.applyState(); + spine._applyState(); for (let i = 0, n = drawOrder.length; i < n; i++) { @@ -98,8 +98,8 @@ export class SpinePipe implements RenderPipe if (attachment instanceof RegionAttachment || attachment instanceof MeshAttachment) { - const batchableSpineSlot = gpuSpine.slotBatches[attachment.name] ||= new BatchableSpineSlot(); const cacheData = spine.getCachedData(slot, attachment); + const batchableSpineSlot = gpuSpine.slotBatches[cacheData.id] ||= new BatchableSpineSlot(); if (!cacheData.clipped || (cacheData.clipped && cacheData.clippedData.vertices.length > 0)) { @@ -115,7 +115,7 @@ export class SpinePipe implements RenderPipe } } - const containerAttachment = spine._slotAttachments.find((mapping) => mapping.slot === slot); + const containerAttachment = spine._slotsObject[slot.data.name]; if (containerAttachment) { @@ -135,7 +135,7 @@ export class SpinePipe implements RenderPipe // we assume that spine will always change its verts size.. const gpuSpine = this.gpuSpineData[spine.uid]; - spine.applyState(); + spine._applyState(); const drawOrder = spine.skeleton.drawOrder; @@ -146,7 +146,7 @@ export class SpinePipe implements RenderPipe if (attachment instanceof RegionAttachment || attachment instanceof MeshAttachment) { - const batchableSpineSlot = gpuSpine.slotBatches[attachment.name]; + const batchableSpineSlot = gpuSpine.slotBatches[spine.getCachedData(slot, attachment).id]; batchableSpineSlot.batcher.updateElement(batchableSpineSlot); }