Changed scaleX and scaleY props meaning, they are now offset ratio with the bounds. Removed usage of skeleton scale, in favor of C3Matrix scale.

Add getter/setter to editor instance for numeric properties.
Width and height changes scale the skeleton, not only bbox.
This commit is contained in:
Davide Tantillo 2026-01-09 15:58:47 +01:00
parent adfb71b5d3
commit 329ff5b073
8 changed files with 176 additions and 107 deletions

View File

@ -41,20 +41,24 @@ export class C3Matrix {
public prevX = Infinity; public prevX = Infinity;
public prevY = Infinity; public prevY = Infinity;
public prevAngle = Infinity; public prevAngle = Infinity;
public prevScaleX = Infinity;
public prevScaleY = Infinity;
private tempPoint = new Vector2(); private tempPoint = new Vector2();
public update (x: number, y: number, angle: number) { public update (x: number, y: number, angle: number, scaleX = 1, scaleY = 1) {
if (this.prevX === x && this.prevY === y && this.prevAngle === angle) return false; if (this.prevX === x && this.prevY === y && this.prevAngle === angle && this.prevScaleX === scaleX && this.prevScaleY === scaleY) return false;
this.prevX = x; this.prevX = x;
this.prevY = y; this.prevY = y;
this.prevAngle = angle; this.prevAngle = angle;
this.prevScaleX = scaleX;
this.prevScaleY = scaleY;
const cos = Math.cos(angle); const cos = Math.cos(angle);
const sin = Math.sin(angle); const sin = Math.sin(angle);
this.a = cos; this.a = scaleX * cos;
this.b = sin; this.b = scaleX * sin;
this.c = -sin; this.c = -scaleY * sin;
this.d = cos; this.d = scaleY * cos;
this.tx = x; this.tx = x;
this.ty = y; this.ty = y;
return true; return true;

View File

@ -27,7 +27,7 @@
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/ *****************************************************************************/
import { type BlendMode, type Bone, ClippingAttachment, MathUtils, MeshAttachment, PathAttachment, RegionAttachment, RenderCommand, type Skeleton, SkeletonRendererCore, Utils, Vector2 } from "@esotericsoftware/spine-core"; import { type BlendMode, type Bone, ClippingAttachment, MathUtils, MeshAttachment, PathAttachment, RegionAttachment, type RenderCommand, type Skeleton, SkeletonRendererCore, Utils, Vector2 } from "@esotericsoftware/spine-core";
import type { C3Matrix } from "./C3Matrix"; import type { C3Matrix } from "./C3Matrix";
import { BlendingModeSpineToC3, type C3TextureEditor, type C3TextureRuntime } from "./C3Texture"; import { BlendingModeSpineToC3, type C3TextureEditor, type C3TextureRuntime } from "./C3Texture";

View File

@ -41,6 +41,8 @@ interface GameObject {
state?: AnimationState, state?: AnimationState,
} }
export type SpineBoundsProviderType = "setup" | "animation-skin" | "AABB";
export interface SpineBoundsProvider { export interface SpineBoundsProvider {
/** Returns the bounding box for the skeleton, in skeleton space. */ /** Returns the bounding box for the skeleton, in skeleton space. */
calculateBounds (gameObject: GameObject): Rectangle; calculateBounds (gameObject: GameObject): Rectangle;

View File

@ -1,4 +1,4 @@
import type { AnimationState, AnimationStateListener, AssetLoader, Bone, C3Matrix, C3RendererRuntime, Event, NumberArrayLike, RegionAttachment, Skeleton, Skin, Slot, TextureAtlas, } from "@esotericsoftware/spine-construct3-lib"; import type { AnimationState, AnimationStateListener, AssetLoader, Bone, C3Matrix, C3RendererRuntime, Event, NumberArrayLike, RegionAttachment, Skeleton, Skin, Slot, SpineBoundsProvider, SpineBoundsProviderType, TextureAtlas, } from "@esotericsoftware/spine-construct3-lib";
const C3 = globalThis.C3; const C3 = globalThis.C3;
const spine = globalThis.spine; const spine = globalThis.spine;
@ -17,9 +17,10 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
propScaleX = 1; propScaleX = 1;
propScaleY = 1; propScaleY = 1;
propDebugSkeleton = false; propDebugSkeleton = false;
propBoundsProvider: SpineBoundsProviderType = "setup";
isFlippedX = false; isFlippedX = false;
isPlaying = false; isPlaying = true;
animationSpeed = 1.0; animationSpeed = 1.0;
physicsMode = spine.Physics.update; physicsMode = spine.Physics.update;
customSkins: Record<string, Skin> = {}; customSkins: Record<string, Skin> = {};
@ -43,6 +44,13 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
private matrix: C3Matrix; private matrix: C3Matrix;
private requestRedraw = false; private requestRedraw = false;
private spineBounds = {
x: 0,
y: 0,
width: 200,
height: 200,
};
private verticesTemp = spine.Utils.newFloatArray(2 * 1024); private verticesTemp = spine.Utils.newFloatArray(2 * 1024);
private boneFollowers = new Map<string, { uid: number, offsetX: number, offsetY: number, offsetAngle: number }>(); private boneFollowers = new Map<string, { uid: number, offsetX: number, offsetY: number, offsetAngle: number }>();
@ -71,7 +79,9 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
this.propSkin = skinProp === "" ? [] : skinProp.split(","); this.propSkin = skinProp === "" ? [] : skinProp.split(",");
this.propAnimation = properties[4] as string; this.propAnimation = properties[4] as string;
this.propDebugSkeleton = properties[5] as boolean; this.propDebugSkeleton = properties[5] as boolean;
const boundsProviderIndex = properties[6] as number;
this.propBoundsProvider = boundsProviderIndex === 0 ? "setup" : "animation-skin";
// properties[7] is PROP_BOUNDS_PROVIDER_MOVE
this.propOffsetX = properties[8] as number; this.propOffsetX = properties[8] as number;
this.propOffsetY = properties[9] as number; this.propOffsetY = properties[9] as number;
this.propOffsetAngle = properties[10] as number; this.propOffsetAngle = properties[10] as number;
@ -115,7 +125,9 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
this.matrix.update( this.matrix.update(
this.x + this.propOffsetX, this.x + this.propOffsetX,
this.y + this.propOffsetY, this.y + this.propOffsetY,
this.angle + this.propOffsetAngle); this.angle + this.propOffsetAngle,
this.width / this.spineBounds.width * this.propScaleX * (this.isFlippedX ? -1 : 1),
this.height / this.spineBounds.height * this.propScaleY);
if (this.isPlaying) this.update(this.dt); if (this.isPlaying) this.update(this.dt);
} }
@ -266,8 +278,8 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
pose.y = y; pose.y = y;
} else { } else {
const { x, y } = matrix.gameToSkeleton(touchX - handleObject.offsetX, touchY - handleObject.offsetY); const { x, y } = matrix.gameToSkeleton(touchX - handleObject.offsetX, touchY - handleObject.offsetY);
pose.x = x / skeleton.scaleX; pose.x = x;
pose.y = -y / skeleton.scaleY * spine.Skeleton.yDir; pose.y = -y * spine.Skeleton.yDir;
} }
} else if (!this.prevLeftClickDown) { } else if (!this.prevLeftClickDown) {
const applied = bone.applied; const applied = bone.applied;
@ -422,8 +434,7 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
this._setSkin(); this._setSkin();
this.skeleton.scaleX = this.isFlippedX ? -this.propScaleX : this.propScaleX; this.calculateBounds();
this.skeleton.scaleY = this.propScaleY;
this.update(0); this.update(0);
@ -431,6 +442,28 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
this._trigger(C3.Plugins.EsotericSoftware_SpineConstruct3.Cnds.OnSkeletonLoaded); this._trigger(C3.Plugins.EsotericSoftware_SpineConstruct3.Cnds.OnSkeletonLoaded);
} }
} }
private calculateBounds () {
const { skeleton } = this;
if (!skeleton) return;
let boundsProvider: SpineBoundsProvider;
console.log(this.propBoundsProvider);
if (this.propBoundsProvider === "animation-skin") {
const { propSkin, propAnimation } = this;
if ((propSkin && propSkin.length > 0) || propAnimation) {
boundsProvider = new spine.SkinsAndAnimationBoundsProvider(propAnimation, propSkin);
} else {
boundsProvider = new spine.SetupPoseBoundsProvider();
}
} else if (this.propBoundsProvider === "setup") {
boundsProvider = new spine.SetupPoseBoundsProvider();
} else {
boundsProvider = new spine.AABBRectangleBoundsProvider(0, 0, 100, 100);
}
this.spineBounds = boundsProvider.calculateBounds(this);
}
/**********/ /**********/
/* /*
@ -742,7 +775,6 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
const { x, y } = matrix.boneToGame(bone); const { x, y } = matrix.boneToGame(bone);
const boneRotation = bone.applied.getWorldRotationX(); const boneRotation = bone.applied.getWorldRotationX();
// Apply rotation to offset
const rotationRadians = boneRotation * Math.PI / 180; const rotationRadians = boneRotation * Math.PI / 180;
const cos = Math.cos(rotationRadians); const cos = Math.cos(rotationRadians);
const sin = Math.sin(rotationRadians); const sin = Math.sin(rotationRadians);
@ -912,11 +944,6 @@ class SpineC3Instance extends globalThis.ISDKWorldInstanceBase {
public flipX (isFlippedX: boolean) { public flipX (isFlippedX: boolean) {
this.isFlippedX = isFlippedX; this.isFlippedX = isFlippedX;
const { skeleton } = this;
if (skeleton) {
skeleton.scaleX = isFlippedX ? -this.propScaleX : this.propScaleX;
}
} }
public setPhysicsMode (mode: 0 | 1 | 2 | 3) { public setPhysicsMode (mode: 0 | 1 | 2 | 3) {

View File

@ -1,6 +1,6 @@
// / <reference types="editor/sdk" /> // / <reference types="editor/sdk" />
import type { AnimationState, AssetLoader, C3Matrix, C3RendererEditor, Skeleton, SpineBoundsProvider, TextureAtlas, } from "@esotericsoftware/spine-construct3-lib"; import type { AnimationState, AssetLoader, C3Matrix, C3RendererEditor, Skeleton, SpineBoundsProvider, SpineBoundsProviderType, TextureAtlas, } from "@esotericsoftware/spine-construct3-lib";
import type { SpineC3PluginType } from "./type"; import type { SpineC3PluginType } from "./type";
const SDK = globalThis.SDK; const SDK = globalThis.SDK;
@ -9,8 +9,6 @@ const PLUGIN_CLASS = SDK.Plugins.EsotericSoftware_SpineConstruct3;
let spine: typeof globalThis.spine; let spine: typeof globalThis.spine;
type SpineBoundsProviderType = "setup" | "animation-skin" | "AABB";
class SpineC3PluginInstance extends SDK.IWorldInstanceBase { class SpineC3PluginInstance extends SDK.IWorldInstanceBase {
private layoutView?: SDK.UI.ILayoutView; private layoutView?: SDK.UI.ILayoutView;
private renderer?: SDK.Gfx.IWebGLRenderer; private renderer?: SDK.Gfx.IWebGLRenderer;
@ -33,6 +31,8 @@ class SpineC3PluginInstance extends SDK.IWorldInstanceBase {
private positionModePrevX = 0; private positionModePrevX = 0;
private positionModePrevY = 0; private positionModePrevY = 0;
private positionModePrevAngle = 0; private positionModePrevAngle = 0;
private positionModePrevWidth = 0;
private positionModePrevHeight = 0;
/* /*
* C3 GameObjects have two sizes: * C3 GameObjects have two sizes:
@ -46,14 +46,14 @@ class SpineC3PluginInstance extends SDK.IWorldInstanceBase {
* In a Spine C3 GameObject: * In a Spine C3 GameObject:
* - the original size is equivalent to spineBounds that is set selecting the BoundsProvider * - the original size is equivalent to spineBounds that is set selecting the BoundsProvider
* - changing the C3 GameObject size from the editor will scale the skeleton by using skeleton.scaleX/Y * - changing the C3 GameObject size from the editor will scale the skeleton by using skeleton.scaleX/Y
* This information is stored into (PROP_SKELETON_SCALE_X and Y) and later passed to the runtime * This information is stored into (PROP_SKELETON_OFFSET_SCALE_X and Y) and later passed to the runtime
* - the origin is position at the skeleton root * - the origin is position at the skeleton root
* *
* positioningBounds allows to offset the position and the size of the C3 GameObject * positioningBounds allows to offset the position and the size of the C3 GameObject
* with the one of the skeleton. When selected it allows to: * with the one of the skeleton. When selected it allows to:
* - move the C3 GameObjects position (visually the rectangle) keeping the skeleton still. * - move the C3 GameObjects position (visually the rectangle) keeping the skeleton still.
* This is obtained by adding an offset to the GameObject position. * This is obtained by adding an offset to the GameObject position.
* This information is stored into (PROP_SKELETON_SCALE_X and Y) and later passed to the runtime * This information is stored into (PROP_SKELETON_OFFSET_SCALE_X and Y) and later passed to the runtime
* - scale the C3 GameObjects keeping the skeleton.scaleX/Y as-is. * - scale the C3 GameObjects keeping the skeleton.scaleX/Y as-is.
*/ */
private spineBounds = { private spineBounds = {
@ -137,6 +137,8 @@ class SpineC3PluginInstance extends SDK.IWorldInstanceBase {
} }
if (id === PLUGIN_CLASS.PROP_BOUNDS_PROVIDER) { if (id === PLUGIN_CLASS.PROP_BOUNDS_PROVIDER) {
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_PROVIDER_MOVE, false);
this.positioningBounds = false;
this.resetBounds(true); this.resetBounds(true);
this.layoutView?.Refresh(); this.layoutView?.Refresh();
return return
@ -148,11 +150,8 @@ class SpineC3PluginInstance extends SDK.IWorldInstanceBase {
this.positionModePrevX = this._inst.GetX(); this.positionModePrevX = this._inst.GetX();
this.positionModePrevY = this._inst.GetY(); this.positionModePrevY = this._inst.GetY();
this.positionModePrevAngle = this._inst.GetAngle(); this.positionModePrevAngle = this._inst.GetAngle();
} else { this.positionModePrevWidth = this._inst.GetWidth();
const scaleX = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_X) as number; this.positionModePrevHeight = this._inst.GetHeight();
const scaleY = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_Y) as number;
this.spineBounds.width = this._inst.GetWidth() / scaleX;
this.spineBounds.height = this._inst.GetHeight() / scaleY;
} }
this.positioningBounds = value; this.positioningBounds = value;
return return
@ -175,35 +174,26 @@ class SpineC3PluginInstance extends SDK.IWorldInstanceBase {
const rectX = _inst.GetX(); const rectX = _inst.GetX();
const rectY = _inst.GetY(); const rectY = _inst.GetY();
const rectAngle = _inst.GetAngle();
let offsetX = _inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_X) as number;
let offsetY = _inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_Y) as number;
let offsetAngle = _inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_ANGLE) as number;
if (!this.positioningBounds) { if (this.positioningBounds) {
offsetX += rectX; const rectAngle = _inst.GetAngle();
offsetY += rectY;
offsetAngle += rectAngle; this.propOffsetX += this.positionModePrevX - rectX;
this.propOffsetY += this.positionModePrevY - rectY;
this.propOffsetAngle = this.propOffsetAngle + this.positionModePrevAngle - rectAngle;
const baseScaleX = _inst.GetWidth() / this.spineBounds.width;
const baseScaleY = _inst.GetHeight() / this.spineBounds.height;
skeleton.scaleX = baseScaleX;
skeleton.scaleY = baseScaleY;
_inst.SetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_X, baseScaleX);
_inst.SetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_Y, baseScaleY);
} else {
offsetX += this.positionModePrevX;
offsetY += this.positionModePrevY;
offsetAngle += this.positionModePrevAngle;
_inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_X, offsetX - rectX);
_inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_Y, offsetY - rectY);
_inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_ANGLE, offsetAngle - rectAngle);
this.positionModePrevX = rectX; this.positionModePrevX = rectX;
this.positionModePrevY = rectY; this.positionModePrevY = rectY;
this.positionModePrevAngle = rectAngle; this.positionModePrevAngle = rectAngle;
skeleton.scaleX = _inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_X) as number; const currentWidth = _inst.GetWidth();
skeleton.scaleY = _inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_Y) as number; const currentHeight = _inst.GetHeight();
if (currentWidth !== this.positionModePrevWidth || currentHeight !== this.positionModePrevHeight) {
this.propScaleX = this.propScaleX * this.positionModePrevWidth / currentWidth;
this.propScaleY = this.propScaleY * this.positionModePrevHeight / currentHeight;
this.positionModePrevWidth = currentWidth;
this.positionModePrevHeight = currentHeight;
}
} }
this.update(0); this.update(0);
@ -349,18 +339,21 @@ class SpineC3PluginInstance extends SDK.IWorldInstanceBase {
} }
public resetBounds (keepScale = false) { public resetBounds (keepScale = false) {
const { _inst } = this;
if (!this.skeleton || !this.textureAtlas) { if (!this.skeleton || !this.textureAtlas) {
this._inst.SetSize(200, 200); _inst.SetSize(200, 200);
this.spineBounds.width = 200; this.spineBounds.width = 200;
this.spineBounds.height = 200; this.spineBounds.height = 200;
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_X, 0); this.propOffsetX = 0;
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_Y, 0); this.propOffsetY = 0;
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_ANGLE, 0); this.propOffsetAngle = 0;
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_X, 1); this.propScaleX = 1;
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_Y, 1); this.propScaleY = 1;
return; return;
} }
const { width: oldBoundsWidth, height: oldBoundsHeight } = this.spineBounds;
this.setBoundsFromBoundsProvider(); this.setBoundsFromBoundsProvider();
if (this.getErrorsString()) { if (this.getErrorsString()) {
this.spineBoundsInit = false; this.spineBoundsInit = false;
@ -369,43 +362,37 @@ class SpineC3PluginInstance extends SDK.IWorldInstanceBase {
this.spineBoundsInit = true; this.spineBoundsInit = true;
const { x, y, width, height } = this.spineBounds; let { x, y, width, height } = this.spineBounds;
this._inst.SetOrigin(-x / width, -y / height); _inst.SetOrigin(-x / width, -y / height);
let scaleX = 1;
let scaleY = 1;
if (keepScale) { if (keepScale) {
scaleX = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_X) as number; width *= (_inst.GetWidth() / oldBoundsWidth) * this.propScaleX;
scaleY = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_Y) as number; height *= (_inst.GetHeight() / oldBoundsHeight) * this.propScaleY;
} }
this._inst.SetSize(width * scaleX, height * scaleY);
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_X, 0); _inst.SetSize(width, height);
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_Y, 0); _inst.SetXY(_inst.GetX() + this.propOffsetX, _inst.GetY() + this.propOffsetY);
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_ANGLE, 0); _inst.SetAngle(_inst.GetAngle() + this.propOffsetAngle);
this.propOffsetX = 0;
this.propOffsetY = 0;
this.propOffsetAngle = 0;
this.propScaleX = 1;
this.propScaleY = 1;
return; return;
} }
private initBounds () { private initBounds () {
if (this.spineBoundsInit) return; if (this.spineBoundsInit || !this.skeleton) return;
const offsetX = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_X) as number; const matchesOldBounds = this._inst.GetWidth() === this.spineBounds.width && this._inst.GetHeight() === this.spineBounds.height;
const offsetY = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_Y) as number;
const offsetAngle = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_ANGLE) as number;
const shiftedBounds = offsetX !== 0 || offsetY !== 0 || offsetAngle !== 0;
const scaleX = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_X) as number;
const scaleY = this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_SCALE_Y) as number;
const scaledBounds = scaleX !== 1 || scaleY !== 1;
if (!shiftedBounds && !scaledBounds) {
this.resetBounds();
return;
}
this.setBoundsFromBoundsProvider(); this.setBoundsFromBoundsProvider();
this.spineBounds.width = this._inst.GetWidth() / scaleX;
this.spineBounds.height = this._inst.GetHeight() / scaleY; const { x, y, width, height } = this.spineBounds;
this._inst.SetOrigin(-x / width, -y / height);
if (matchesOldBounds) this._inst.SetSize(width, height);
this.spineBoundsInit = true; this.spineBoundsInit = true;
} }
@ -473,13 +460,59 @@ class SpineC3PluginInstance extends SDK.IWorldInstanceBase {
state.update(delta); state.update(delta);
skeleton.update(delta); skeleton.update(delta);
state.apply(skeleton); state.apply(skeleton);
const actualScaleX = (this._inst.GetWidth() / this.spineBounds.width) * this.propScaleX;
const actualScaleY = (this._inst.GetHeight() / this.spineBounds.height) * this.propScaleY;
this.matrix.update( this.matrix.update(
this._inst.GetX() + (this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_X) as number), this._inst.GetX() + this.propOffsetX,
this._inst.GetY() + (this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_Y) as number), this._inst.GetY() + this.propOffsetY,
this._inst.GetAngle() + (this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_ANGLE) as number)); this._inst.GetAngle() + this.propOffsetAngle,
actualScaleX,
actualScaleY);
skeleton.updateWorldTransform(spine.Physics.update); skeleton.updateWorldTransform(spine.Physics.update);
} }
private get propScaleX () {
return this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_OFFSET_SCALE_X) as number
}
private set propScaleX (value: number) {
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_OFFSET_SCALE_X, value);
}
private get propScaleY () {
return this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_OFFSET_SCALE_Y) as number
}
private set propScaleY (value: number) {
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_SKELETON_OFFSET_SCALE_Y, value);
}
private get propOffsetX () {
return this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_X) as number;
}
private set propOffsetX (value: number) {
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_X, value);
}
private get propOffsetY () {
return this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_Y) as number;
}
private set propOffsetY (value: number) {
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_Y, value);
}
private get propOffsetAngle () {
return this._inst.GetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_ANGLE) as number;
}
private set propOffsetAngle (value: number) {
this._inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_OFFSET_ANGLE, value);
}
GetTexture () { GetTexture () {
const image = this.GetObjectType().GetImage(); const image = this.GetObjectType().GetImage();
return super.GetTexture(image); return super.GetTexture(image);

View File

@ -46,13 +46,13 @@
"name": "Position bounds", "name": "Position bounds",
"desc": "Keep the skeleton in a fixed position while adjusting the size and position of the bounds." "desc": "Keep the skeleton in a fixed position while adjusting the size and position of the bounds."
}, },
"spine-scale-x": { "spine-offset-scale-x": {
"name": "Scale X", "name": "Offset Scale X",
"desc": "Scale X" "desc": "Offset Scale X"
}, },
"spine-scale-y": { "spine-offset-scale-y": {
"name": "Scale Y", "name": "Offset Scale Y",
"desc": "Scale Y" "desc": "Offset Scale Y"
}, },
"spine-debug-skeleton": { "spine-debug-skeleton": {
"name": "Debug skeleton", "name": "Debug skeleton",

View File

@ -46,13 +46,13 @@
"name": "位置边界", "name": "位置边界",
"desc": "在调整边界大小和位置时保持骨架固定在一个位置。" "desc": "在调整边界大小和位置时保持骨架固定在一个位置。"
}, },
"spine-scale-x": { "spine-offset-scale-x": {
"name": "X缩放", "name": "偏移缩放X",
"desc": "X缩放" "desc": "偏移缩放X"
}, },
"spine-scale-y": { "spine-offset-scale-y": {
"name": "Y缩放", "name": "偏移缩放Y",
"desc": "Y缩放" "desc": "偏移缩放Y"
}, },
"spine-debug-skeleton": { "spine-debug-skeleton": {
"name": "调试骨架", "name": "调试骨架",

View File

@ -1,3 +1,5 @@
import type { SpineBoundsProviderType } from "@esotericsoftware/spine-construct3-lib";
import type { SDKEditorInstanceClass } from "./instance.ts"; import type { SDKEditorInstanceClass } from "./instance.ts";
const SDK = globalThis.SDK; const SDK = globalThis.SDK;
@ -29,12 +31,12 @@ const PLUGIN_CLASS = class SpineC3Plugin extends SDK.IPluginBase {
static PROP_BOUNDS_OFFSET_X = "spine-bounds-offset-x"; static PROP_BOUNDS_OFFSET_X = "spine-bounds-offset-x";
static PROP_BOUNDS_OFFSET_Y = "spine-bounds-offset-y"; static PROP_BOUNDS_OFFSET_Y = "spine-bounds-offset-y";
static PROP_BOUNDS_OFFSET_ANGLE = "spine-bounds-offset-angle"; static PROP_BOUNDS_OFFSET_ANGLE = "spine-bounds-offset-angle";
static PROP_SKELETON_SCALE_X = "spine-scale-x"; static PROP_SKELETON_OFFSET_SCALE_X = "spine-offset-scale-x";
static PROP_SKELETON_SCALE_Y = "spine-scale-y"; static PROP_SKELETON_OFFSET_SCALE_Y = "spine-offset-scale-y";
static PROP_DEBUG_SKELETON = "spine-debug-skeleton"; static PROP_DEBUG_SKELETON = "spine-debug-skeleton";
static TYPE_BOUNDS_SETUP = "setup"; static TYPE_BOUNDS_SETUP: SpineBoundsProviderType = "setup";
static TYPE_BOUNDS_ANIMATION_SKIN = "animation-skin"; static TYPE_BOUNDS_ANIMATION_SKIN: SpineBoundsProviderType = "animation-skin";
constructor () { constructor () {
super(PLUGIN_ID); super(PLUGIN_ID);
@ -91,11 +93,12 @@ const PLUGIN_CLASS = class SpineC3Plugin extends SDK.IPluginBase {
new SDK.PluginProperty("float", SpineC3Plugin.PROP_BOUNDS_OFFSET_X, 0), new SDK.PluginProperty("float", SpineC3Plugin.PROP_BOUNDS_OFFSET_X, 0),
new SDK.PluginProperty("float", SpineC3Plugin.PROP_BOUNDS_OFFSET_Y, 0), new SDK.PluginProperty("float", SpineC3Plugin.PROP_BOUNDS_OFFSET_Y, 0),
new SDK.PluginProperty("float", SpineC3Plugin.PROP_BOUNDS_OFFSET_ANGLE, 0), new SDK.PluginProperty("float", SpineC3Plugin.PROP_BOUNDS_OFFSET_ANGLE, 0),
new SDK.PluginProperty("float", SpineC3Plugin.PROP_SKELETON_SCALE_X, 1), new SDK.PluginProperty("float", SpineC3Plugin.PROP_SKELETON_OFFSET_SCALE_X, 1),
new SDK.PluginProperty("float", SpineC3Plugin.PROP_SKELETON_SCALE_Y, 1), new SDK.PluginProperty("float", SpineC3Plugin.PROP_SKELETON_OFFSET_SCALE_Y, 1),
new SDK.PluginProperty("link", "set-bounds", { new SDK.PluginProperty("link", "set-bounds", {
linkCallback: (instance) => { linkCallback: (instance) => {
const sdkInst = instance as SDKEditorInstanceClass; const sdkInst = instance as SDKEditorInstanceClass;
sdkInst._inst.SetPropertyValue(PLUGIN_CLASS.PROP_BOUNDS_PROVIDER_MOVE, false);
sdkInst.resetBounds(true); sdkInst.resetBounds(true);
}, },
callbackType: "for-each-instance" callbackType: "for-each-instance"