Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add spine doc #2262

Merged
merged 4 commits into from
Aug 2, 2024
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
503 changes: 409 additions & 94 deletions docs/zh/graphics/2D/spine.md

Large diffs are not rendered by default.

41 changes: 32 additions & 9 deletions examples/spine-animation.ts
Original file line number Diff line number Diff line change
@@ -3,8 +3,8 @@
* @category 2D
* @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*IALeTYOXMXwAAAAAAAAAAAAADiR2AQ/original
*/
import { Camera, Logger, Vector3, WebGLEngine, Entity } from "@galacean/engine";
import { SpineRenderer } from "@galacean/engine-spine";
import { Camera, Entity, Logger, Vector3, WebGLEngine } from "@galacean/engine";
import { SpineAnimationRenderer } from "@galacean/engine-spine";

Logger.enable();

@@ -18,20 +18,43 @@ WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
// camera
const cameraEntity = rootEntity.createChild("camera_node");
const camera = cameraEntity.addComponent(Camera);
cameraEntity.transform.position = new Vector3(0, 0, 60);
cameraEntity.transform.position = new Vector3(0, 0, 100);
camera.nearClipPlane = 0.001;
camera.farClipPlane = 20000;

engine.resourceManager
.load({
url: "https://mmtcdp.stable.alipay.net/oasis_be/afts/file/A*jceoSrUXbUYAAAAAAAAAAAAADnN-AQ/spineboy.json",
url: "https://mdn.alipayobjects.com/huamei_kz4wfo/uri/file/as/2/kz4wfo/4/mp/qGISZ7QTJFkEL0Qx/spineboy/spineboy.json",
type: "spine",
})
.then((spineResource: any) => {
const spineEntity = rootEntity.createChild("spine");
const spineEntity = new Entity(engine);
spineEntity.transform.setPosition(0, -18, 0);
const spineRenderer = spineEntity.addComponent(SpineRenderer);
spineRenderer.scale = 0.05;
spineRenderer.animationName = "walk";
spineRenderer.resource = spineResource;
const spine = spineEntity.addComponent(SpineAnimationRenderer);
spine.resource = spineResource;
spine.defaultState.scale = 0.05;
rootEntity.addChild(spineEntity);
const { state } = spine;
state.data.defaultMix = 0.3;
state.data.setMix('death', 'portal', 0);
const queue = () => {
state.setAnimation(0, 'portal', false);
state.addAnimation(0, 'idle', true, 0);
state.addAnimation(0, 'walk', true, 1);
state.addAnimation(0, 'run', true, 2);
state.addAnimation(0, 'jump', false, 2);
state.addAnimation(0, 'death', false, 0);
};
queue();
state.addListener({
complete: (entry) => {
if (entry?.animation?.name === 'death') {
setTimeout(() => {
queue();
}, 1000);
}
}
});
});

engine.run();
76 changes: 24 additions & 52 deletions examples/spine-change-attachment.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
/**
* @title Spine Change Attachment
* @title Spine change Attachment
* @category 2D
* @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*VUeSSbViZe8AAAAAAAAAAAAADiR2AQ/original
* @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*IALeTYOXMXwAAAAAAAAAAAAADiR2AQ/original
*/
import { Camera, Logger, Vector3, WebGLEngine, Entity } from "@galacean/engine";
import { SpineRenderer } from "@galacean/engine-spine";
import * as dat from "dat.gui";
import { Camera, Entity, Logger, Vector3, WebGLEngine } from "@galacean/engine";
import { SpineAnimationRenderer } from "@galacean/engine-spine";

Logger.enable();

const gui = new dat.GUI();

// Create engine
WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
engine.canvas.resizeByClientSize();
@@ -21,58 +18,33 @@ WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
// camera
const cameraEntity = rootEntity.createChild("camera_node");
const camera = cameraEntity.addComponent(Camera);
cameraEntity.transform.position = new Vector3(0, 0, 60);
cameraEntity.transform.position = new Vector3(0, 0, 100);
camera.nearClipPlane = 0.001;
camera.farClipPlane = 20000;

engine.resourceManager
.load({
urls: [
"https://gw.alipayobjects.com/os/OasisHub/01c23386-ae6d-41b3-ab51-08b023a0dc3f/1629864253199.json",
"https://gw.alipayobjects.com/os/OasisHub/27b76dd2-01b3-4282-83e8-17be20b910ae/1629864253200.atlas",
"https://gw.alipayobjects.com/zos/OasisHub/99bc4468-02c6-4f35-8fef-ac5a711fc641/1629864253200.png",
],
url: "https://mdn.alipayobjects.com/huamei_kz4wfo/uri/file/as/2/kz4wfo/4/mp/24ejL92gvbWxsXRi/mix-and-match/mix-and-match.json",
type: "spine",
})
.then((spineResource: any) => {
const spineEntity = rootEntity.createChild("spine");
const spineEntity = new Entity(engine);
spineEntity.transform.setPosition(0, -18, 0);
const spine = spineEntity.addComponent(SpineAnimationRenderer);
spine.resource = spineResource;
spine.defaultState.scale = 0.05;
spine.defaultState.skinName = 'full-skins/girl';
spine.defaultState.animationName = 'idle';
rootEntity.addChild(spineEntity);
const spineRenderer = spineEntity.addComponent(SpineRenderer);
spineRenderer.scale = 0.05;
spineRenderer.animationName = "walk";
spineRenderer.resource = spineResource;
const { skeleton, state, skeletonData } = spineRenderer.spineAnimation;
spineEntity.transform.setPosition(0, -10, 0);
state.setAnimation(0, "sneering", true);
skeleton.setSkinByName("fullskin/0101"); // 1. Set the active skin
skeleton.setSlotsToSetupPose(); // 2. Use setup pose to set base attachments.
state.apply(skeleton);
const slotName = "fBody";
const info = {
更换衣服部件: "fullskin/0101",
};
gui
.add(info, "更换衣服部件", [
"fullskin/0101",
"fullskin/autumn",
"fullskin/carnival",
"fullskin/fishing",
"fullskin/football",
"fullskin/newyear",
"fullskin/painter",
"fullskin/snowman",
])
.onChange((skinName) => {
const currentSkin = skeleton.skin;
const slotIndex = skeleton.findSlotIndex(slotName);
const changeSkin = skeletonData.findSkin(skinName);
const changeAttachment = changeSkin.getAttachment(
slotIndex,
slotName
);
if (changeAttachment) {
currentSkin.removeAttachment(slotIndex, slotName);
currentSkin.setAttachment(slotIndex, slotName, changeAttachment);
}
});
const { skeleton } = spine;
const slot = skeleton.findSlot('body')!;
// If the attachment is in the same slot of the same skin,
// you can use skeleton.getAttachment(slot.index, 'attachmentName') to get the attachment from the currentSkin or defaultSkin.
const skin = skeleton.data.findSkin('full-skins/boy')!;
const attachment = skin.getAttachment(slot.data.index, 'body');
// If the attachment is in the same slot of the same skin,
// you can use skeleton.setAttachment('slotName', 'attachmentName') to change the attachment.
slot.attachment = attachment;
});

engine.run();
75 changes: 75 additions & 0 deletions examples/spine-follow-shoot.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/**
* @title Spine follow shoot
* @category 2D
* @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*IALeTYOXMXwAAAAAAAAAAAAADiR2AQ/original
*/
import { Camera, Entity, Logger, Script, Vector3, WebGLEngine } from "@galacean/engine";
import { Bone, SpineAnimationRenderer } from "@galacean/engine-spine";

Logger.enable();

// Create engine
WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
engine.canvas.resizeByClientSize();

const scene = engine.sceneManager.activeScene;
const rootEntity = scene.createRootEntity();

// camera
const cameraEntity = rootEntity.createChild("camera_node");
const camera = cameraEntity.addComponent(Camera);
cameraEntity.transform.position = new Vector3(0, 0, 100);
camera.nearClipPlane = 0.001;
camera.farClipPlane = 20000;

engine.resourceManager
.load({
url: "https://mdn.alipayobjects.com/huamei_kz4wfo/uri/file/as/2/kz4wfo/4/mp/yKbdfgijyLGzQDyQ/spineboy/spineboy.json",
type: "spine",
})
.then((spineResource: any) => {
const spineEntity = new Entity(engine);
spineEntity.transform.setPosition(0, -18, 0);
const spine = spineEntity.addComponent(SpineAnimationRenderer);
spine.resource = spineResource;
spine.defaultState.scale = 0.05;
rootEntity.addChild(spineEntity);
const { state, skeleton } = spine;
state.setAnimation(0, 'idle', true);
state.setAnimation(1, 'aim', true);
const shoot = () => {
state.setAnimation(2, 'shoot', false);
};
spineEntity.addComponent(class extends Script {
private _vec3 = new Vector3();
onUpdate(): void {
const { inputManager } = engine;
const pointers = inputManager.pointers;
if (pointers.length > 0) {
const { position } = pointers[0];
const worldPos = this._vec3;
camera.screenToWorldPoint(
new Vector3(position.x, position.y, 2000),
worldPos,
);
const targetBone = skeleton.findBone('crosshair') as Bone;targetBone.y = worldPos.y + 380;
targetBone.y = worldPos.y + 380;
if (worldPos.x < 0) {
skeleton.scaleX = -0.05;
targetBone.x = -worldPos.x;
} else {
skeleton.scaleX = 0.05;
targetBone.x = worldPos.x;
}
}
if (inputManager.isPointerDown()) {
shoot();
}
}
});
});

engine.run();
});


64 changes: 64 additions & 0 deletions examples/spine-full-skin-change.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* @title Spine Full Skin Change
* @category 2D
* @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*IALeTYOXMXwAAAAAAAAAAAAADiR2AQ/original
*/
import { Camera, Entity, Logger, Vector3, WebGLEngine } from "@galacean/engine";
import { SpineAnimationRenderer } from "@galacean/engine-spine";
import * as dat from "dat.gui";

Logger.enable();

const gui = new dat.GUI();

// Create engine
WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
engine.canvas.resizeByClientSize();

const scene = engine.sceneManager.activeScene;
const rootEntity = scene.createRootEntity();

// camera
const cameraEntity = rootEntity.createChild("camera_node");
const camera = cameraEntity.addComponent(Camera);
cameraEntity.transform.position = new Vector3(0, 0, 100);
camera.nearClipPlane = 0.001;
camera.farClipPlane = 20000;

engine.resourceManager
.load({
url: "https://mdn.alipayobjects.com/huamei_kz4wfo/uri/file/as/2/kz4wfo/4/mp/24ejL92gvbWxsXRi/mix-and-match/mix-and-match.json",
type: "spine",
})
.then((spineResource: any) => {
const spineEntity = new Entity(engine);
spineEntity.transform.setPosition(0, -18, 0);
const spine = spineEntity.addComponent(SpineAnimationRenderer);
spine.resource = spineResource;
spine.defaultState.scale = 0.05;
spine.defaultState.skinName = 'full-skins/girl';
spine.defaultState.animationName = 'idle';
rootEntity.addChild(spineEntity);
const { skeleton, state } = spine;
const info = {
skin: "full-skins/girl",
};
gui
.add(info, "skin", [
"full-skins/girl",
"full-skins/girl-blue-cape",
"full-skins/girl-spring-dress",
"full-skins/boy",
])
.onChange((skinName) => {
skeleton.setSkinByName(skinName);
skeleton.setSlotsToSetupPose();
state.data.defaultMix = 0.2;
state.setAnimation(0, 'dress-up', false);
state.addAnimation(0, 'idle', true, 0);
});

});

engine.run();
});
141 changes: 0 additions & 141 deletions examples/spine-hack-slot-texture.ts

This file was deleted.

213 changes: 213 additions & 0 deletions examples/spine-mix-and-match.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/**
* @title Spine Mix And Match
* @category 2D
* @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*IALeTYOXMXwAAAAAAAAAAAAADiR2AQ/original
*/
import { Camera, Entity, Logger, Script, Vector3, WebGLEngine } from "@galacean/engine";
import { Skin, SpineAnimationRenderer } from "@galacean/engine-spine";
import * as dat from "dat.gui";

const gui = new dat.GUI();

Logger.enable();

// Create engine
WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
engine.canvas.resizeByClientSize();

const scene = engine.sceneManager.activeScene;
const rootEntity = scene.createRootEntity();

// camera
const cameraEntity = rootEntity.createChild("camera_node");
const camera = cameraEntity.addComponent(Camera);
cameraEntity.transform.position = new Vector3(0, 0, 100);
camera.nearClipPlane = 0.001;
camera.farClipPlane = 20000;

engine.resourceManager
.load({
url: "https://mdn.alipayobjects.com/huamei_kz4wfo/uri/file/as/2/kz4wfo/4/mp/24ejL92gvbWxsXRi/mix-and-match/mix-and-match.json",
type: "spine",
})
.then((spineResource: any) => {
const spineEntity = new Entity(engine);
spineEntity.transform.setPosition(0, -18, 0);
const spine = spineEntity.addComponent(SpineAnimationRenderer);
spine.resource = spineResource;
spine.defaultState.scale = 0.05;
spine.defaultState.skinName = 'full-skins/girl';
spine.defaultState.animationName = 'idle';
const mixAndMatch = spineEntity.addComponent(MixAndMatch);
rootEntity.addChild(spineEntity);
const { state } = spine;
const info = {
Eyes: mixAndMatch.eyesSkins[0],
Hair: mixAndMatch.hairSkins[0],
Nose: mixAndMatch.noseSkins[0],
Bag: mixAndMatch.bagSkins[0],
Hat: mixAndMatch.hatSkins[0],
Pants: mixAndMatch.pantsSkins[0],
Cloth: mixAndMatch.clothesSkins[0],
};
gui
.add(info, "Eyes", mixAndMatch.eyesSkins)
.onChange((eyesSkinName) => {
mixAndMatch.eyesSkin = eyesSkinName;
mixAndMatch.updateCharacterSkin();
mixAndMatch.updateCombinedSkin();
state.setAnimation(1, 'blink', false);
state.addEmptyAnimation(1, 0.3, 0);
});

gui
.add(info, "Hair", mixAndMatch.hairSkins)
.onChange((hairSkinName) => {
mixAndMatch.hairSkin = hairSkinName;
mixAndMatch.updateCharacterSkin();
mixAndMatch.updateCombinedSkin();
state.data.defaultMix = 0.2;
state.setAnimation(0, 'aware', false);
state.addAnimation(0, 'idle', true, 0);
});

gui
.add(info, "Nose", mixAndMatch.noseSkins)
.onChange((noseSkinName) => {
mixAndMatch.noseSkin = noseSkinName;
mixAndMatch.updateCharacterSkin();
mixAndMatch.updateCombinedSkin();
state.data.defaultMix = 0.2;
state.setAnimation(1, 'blink', false);
state.addEmptyAnimation(1, 0.3, 0);
});

gui
.add(info, "Bag", mixAndMatch.bagSkins)
.onChange((bagSkinName) => {
mixAndMatch.bagSkin = bagSkinName;
mixAndMatch.updateCharacterSkin();
mixAndMatch.updateCombinedSkin();
state.data.defaultMix = 0.3;
if (bagSkinName) {
state.setAnimation(0, 'dance', true);
state.addAnimation(0, 'idle', true, 1);
}
});

gui
.add(info, "Hat", mixAndMatch.hatSkins)
.onChange((hatSkinName) => {
mixAndMatch.hatSkin = hatSkinName;
mixAndMatch.updateCharacterSkin();
mixAndMatch.updateCombinedSkin();
state.data.defaultMix = 0.2;
state.setAnimation(0, 'aware', false);
state.addAnimation(0, 'idle', true, 0);
});

gui
.add(info, "Pants", mixAndMatch.pantsSkins)
.onChange((pantsSkinName) => {
mixAndMatch.pantsSkin = pantsSkinName;
mixAndMatch.updateCharacterSkin();
mixAndMatch.updateCombinedSkin();
state.data.defaultMix = 0.2;
state.setAnimation(0, 'dress-up', false);
state.addAnimation(0, 'idle', true, 0);
});

gui
.add(info, "Cloth", mixAndMatch.clothesSkins)
.onChange((clothSkinName) => {
mixAndMatch.clothesSkin = clothSkinName;
mixAndMatch.updateCharacterSkin();
mixAndMatch.updateCombinedSkin();
state.data.defaultMix = 0.2;
state.setAnimation(0, 'dress-up', false);
state.addAnimation(0, 'idle', true, 0);
});

});

engine.run();
});

enum ItemType {
Cloth,
Pants,
Bag,
Hat
}

class MixAndMatch extends Script {
noseSkin = "nose/short";
eyesSkin = "eyes/violet";
hairSkin = "hair/brown";
bagSkin = "";
baseSkin = "skin-base";
eyelidsSkin = 'eyelids/girly';
clothesSkin = "clothes/hoodie-orange";
pantsSkin = "legs/pants-jeans";
hatSkin = "accessories/hat-red-yellow";
spine: SpineAnimationRenderer;
characterSkin: Skin;

eyesSkins = ["eyes/violet", "eyes/green", "eyes/yellow"];
hairSkins = ["hair/brown", "hair/blue", "hair/pink", "hair/short-red", "hair/long-blue-with-scarf"];
noseSkins = ["nose/short", "nose/long"];
bagSkins = ["", "accessories/bag", "accessories/backpack"];
hatSkins = ["accessories/hat-red-yellow", "accessories/hat-pointy-blue-yellow"];
pantsSkins = ["legs/pants-jeans", "legs/pants-green"];
clothesSkins = ["clothes/hoodie-orange", "clothes/dress-blue", "clothes/dress-green", "clothes/hoodie-blue-and-scarf"];

onAwake(): void {
this.spine = this.entity.getComponent(SpineAnimationRenderer)!;
}

onStart(): void {
this.updateCharacterSkin();
this.updateCombinedSkin();
}

updateCharacterSkin() {
const skeletonAnimation = this.spine;
const skeleton = skeletonAnimation.skeleton;
const skeletonData = skeleton.data;
const skin = new Skin("character-base");
skin.addSkin(skeletonData.findSkin(this.baseSkin)!);
skin.addSkin(skeletonData.findSkin(this.noseSkin)!);
skin.addSkin(skeletonData.findSkin(this.eyelidsSkin)!);
skin.addSkin(skeletonData.findSkin(this.eyesSkin)!);
skin.addSkin(skeletonData.findSkin(this.hairSkin)!);
this.characterSkin = skin;
}

updateCombinedSkin() {
const skeletonAnimation = this.spine;
const skeleton = skeletonAnimation.skeleton;
const resultCombinedSkin = new Skin("character-combined");

resultCombinedSkin.addSkin(this.characterSkin);
this.addEquipmentSkinsTo(resultCombinedSkin);

skeleton.setSkin(resultCombinedSkin);
skeleton.setSlotsToSetupPose();
}

addEquipmentSkinsTo(combinedSkin: Skin) {
const skeleton = this.spine.skeleton;
const skeletonData = skeleton.data;
combinedSkin.addSkin(skeletonData.findSkin(this.clothesSkin)!);
combinedSkin.addSkin(skeletonData.findSkin(this.pantsSkin)!);
if (this.bagSkin) {
combinedSkin.addSkin(skeletonData.findSkin(this.bagSkin)!);
}
if (this.hatSkin) {
combinedSkin.addSkin(skeletonData.findSkin(this.hatSkin)!);
}
}
}



22 changes: 9 additions & 13 deletions examples/spine-performance.ts
Original file line number Diff line number Diff line change
@@ -3,8 +3,8 @@
* @category Benchmark
* @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*6xrGR6nr1c0AAAAAAAAAAAAADiR2AQ/original
*/
import { Camera, Vector3, WebGLEngine } from "@galacean/engine";
import { SpineRenderer } from "@galacean/engine-spine";
import { Camera, Entity, Vector3, WebGLEngine } from "@galacean/engine";
import { SpineAnimationRenderer } from "@galacean/engine-spine";
import { Stats } from "@galacean/engine-toolkit-stats";

WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
@@ -21,19 +21,15 @@ WebGLEngine.create({ canvas: "canvas" }).then((engine) => {

engine.resourceManager
.load({
urls: [
"https://gw.alipayobjects.com/os/OasisHub/a66ef194-6bc8-4325-9a59-6ea9097225b1/1620888427489.json",
"https://gw.alipayobjects.com/os/OasisHub/a1e3e67b-a783-4832-ba1b-37a95bd55291/1620888427490.atlas",
"https://gw.alipayobjects.com/zos/OasisHub/a3ca8f62-1068-43a5-bb64-5c9a0f823dde/1620888427490.png",
],
url: "https://mdn.alipayobjects.com/huamei_kz4wfo/uri/file/as/2/kz4wfo/4/mp/qGISZ7QTJFkEL0Qx/spineboy/spineboy.json",
type: "spine",
})
.then((spineResouce: any) => {
const spineEntity = rootEntity.createChild("spine");
const spineRenderer = spineEntity.addComponent(SpineRenderer);
spineRenderer.resource = spineResouce;
spineRenderer.scale = 0.01;
spineRenderer.animationName = "walk";
.then((resource: any) => {
const spineEntity = new Entity(engine);
const spine = spineEntity.addComponent(SpineAnimationRenderer);
spine.resource = resource;
spine.defaultState.scale = 0.02;
spine.defaultState.animationName = "walk";
for (let i = -5; i < 5; i++) {
for (let j = -5; j < 5; j++) {
const clone = spineEntity.clone();
63 changes: 63 additions & 0 deletions examples/spine-physics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* @title Spine Physics
* @category 2D
* @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*IALeTYOXMXwAAAAAAAAAAAAADiR2AQ/original
*/
import { Camera, Entity, Logger, Script, Vector3, WebGLEngine } from "@galacean/engine";
import { SpineAnimationRenderer } from "@galacean/engine-spine";

Logger.enable();

// Create engine
WebGLEngine.create({ canvas: "canvas" }).then((engine) => {
engine.canvas.resizeByClientSize();

const scene = engine.sceneManager.activeScene;
const rootEntity = scene.createRootEntity();

// camera
const cameraEntity = rootEntity.createChild("camera_node");
const camera = cameraEntity.addComponent(Camera);
cameraEntity.transform.position = new Vector3(0, 0, 2000);
camera.nearClipPlane = 0.001;
camera.farClipPlane = 20000;

engine.resourceManager
.load({
urls: [
"https://mdn.alipayobjects.com/portal_h1wdez/afts/file/A*Po6oQJyLdb0AAAAAAAAAAAAAAQAAAQ?a=.json",
"https://mdn.alipayobjects.com/portal_h1wdez/afts/file/A*CnqHS5nRzTIAAAAAAAAAAAAAAQAAAQ?b=.atlas",
"https://mdn.alipayobjects.com/portal_h1wdez/afts/img/A*WDXeRIpd-lAAAAAAAAAAAAAAAQAAAQ/original?c=.png"
],
type: "spine",
})
.then((spineResource: any) => {
const spineEntity = new Entity(engine);
spineEntity.transform.setPosition(0, -250, 0);
const spine = spineEntity.addComponent(SpineAnimationRenderer);
spine.resource = spineResource;
spine.defaultState.animationName = 'wind-idle';
spine.defaultState.scale = 0.5;
rootEntity.addChild(spineEntity);
const { skeleton } = spine;
spineEntity.addComponent(class extends Script {
private _vec3 = new Vector3();
onUpdate(): void {
const { inputManager } = engine;
const pointers = inputManager.pointers;
if (pointers.length > 0) {
const { position } = pointers[0];
const worldPos = this._vec3;
camera.screenToWorldPoint(
new Vector3(position.x, position.y, 2000),
worldPos,
);
skeleton.y = worldPos.y - 480;
skeleton.x = worldPos.x;
}
}
});
});

engine.run();
});
66 changes: 0 additions & 66 deletions examples/spine-skin-change.ts

This file was deleted.