mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
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:
parent
adfb71b5d3
commit
329ff5b073
@ -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;
|
||||||
|
|||||||
@ -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";
|
||||||
|
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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) {
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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": "调试骨架",
|
||||||
|
|||||||
@ -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"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user