mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-02 13:49:07 +08:00
[ts] 4.3 porting WIP.
This commit is contained in:
parent
702f23efcc
commit
bb06f81a06
@ -1,16 +0,0 @@
|
|||||||
skeleton-scale.png
|
|
||||||
size:565,275
|
|
||||||
filter:Linear,Linear
|
|
||||||
pma:true
|
|
||||||
eye-indifferent
|
|
||||||
bounds:404,16,93,89
|
|
||||||
goggles
|
|
||||||
bounds:302,107,261,166
|
|
||||||
head
|
|
||||||
bounds:2,2,271,298
|
|
||||||
rotate:90
|
|
||||||
mouth-smile
|
|
||||||
bounds:499,12,93,59
|
|
||||||
rotate:90
|
|
||||||
square
|
|
||||||
bounds:302,5,100,100
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 109 KiB |
Binary file not shown.
@ -177,25 +177,25 @@ export abstract class ToProperty {
|
|||||||
export class FromRotate extends FromProperty {
|
export class FromRotate extends FromProperty {
|
||||||
value (skeleton: Skeleton, source: BonePose, local: boolean, offsets: Array<number>): number {
|
value (skeleton: Skeleton, source: BonePose, local: boolean, offsets: Array<number>): number {
|
||||||
if (local) return source.rotation + offsets[TransformConstraintData.ROTATION];
|
if (local) return source.rotation + offsets[TransformConstraintData.ROTATION];
|
||||||
const sx = skeleton.scaleX, sy = skeleton.scaleY, a = source.a / sx, c = source.c / sy;
|
const sx = skeleton.scaleX, sy = skeleton.scaleY;
|
||||||
let value = Math.atan2(c, a) * MathUtils.radDeg
|
let value = Math.atan2(source.c / sy, source.a / sx) * MathUtils.radDeg
|
||||||
+ ((a * source.d / sy - source.b * c / sx) > 0 ? offsets[TransformConstraintData.ROTATION] : -offsets[TransformConstraintData.ROTATION]);
|
+ ((source.a * source.d - source.b * source.c) * sx * sy > 0 ? offsets[TransformConstraintData.ROTATION] : -offsets[TransformConstraintData.ROTATION]);
|
||||||
if (value < 0) value += 360;
|
if (value < 0) value += 360;
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ToRotate extends ToProperty {
|
export class ToRotate extends ToProperty {
|
||||||
mix (pose: TransformConstraintPose): number {
|
mix (pose: TransformConstraintPose): number {
|
||||||
return pose.mixRotate;
|
return pose.mixRotate;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply (skeleton: Skeleton, pose: TransformConstraintPose, bone: BonePose, value: number, local: boolean, additive: boolean): void {
|
apply (skeleton: Skeleton, pose: TransformConstraintPose, bone: BonePose, value: number, local: boolean, additive: boolean): void {
|
||||||
if (local) {
|
if (local)
|
||||||
if (!additive) value -= bone.rotation;
|
bone.rotation += (additive ? value : value - bone.rotation) * pose.mixRotate;
|
||||||
bone.rotation += value * pose.mixRotate;
|
else {
|
||||||
} else {
|
const sx = skeleton.scaleX, sy = skeleton.scaleY, ix = 1 / sx, iy = 1 / sy;
|
||||||
const sx = skeleton.scaleX, sy = skeleton.scaleY;
|
const a = bone.a * ix, b = bone.b * ix, c = bone.c * iy, d = bone.d * iy;
|
||||||
const a = bone.a / sx, b = bone.b / sx, c = bone.c / sy, d = bone.d / sy;
|
|
||||||
value *= MathUtils.degRad;
|
value *= MathUtils.degRad;
|
||||||
if (!additive) value -= Math.atan2(c, a);
|
if (!additive) value -= Math.atan2(c, a);
|
||||||
if (value > MathUtils.PI)
|
if (value > MathUtils.PI)
|
||||||
@ -226,10 +226,9 @@ export class ToX extends ToProperty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply (skeleton: Skeleton, pose: TransformConstraintPose, bone: BonePose, value: number, local: boolean, additive: boolean): void {
|
apply (skeleton: Skeleton, pose: TransformConstraintPose, bone: BonePose, value: number, local: boolean, additive: boolean): void {
|
||||||
if (local) {
|
if (local)
|
||||||
if (!additive) value -= bone.x;
|
bone.x += (additive ? value : value - bone.x) * pose.mixX;
|
||||||
bone.x += value * pose.mixX;
|
else {
|
||||||
} else {
|
|
||||||
if (!additive) value -= bone.worldX / skeleton.scaleX;
|
if (!additive) value -= bone.worldX / skeleton.scaleX;
|
||||||
bone.worldX += value * pose.mixX * skeleton.scaleX;
|
bone.worldX += value * pose.mixX * skeleton.scaleX;
|
||||||
}
|
}
|
||||||
@ -250,10 +249,9 @@ export class ToY extends ToProperty {
|
|||||||
}
|
}
|
||||||
|
|
||||||
apply (skeleton: Skeleton, pose: TransformConstraintPose, bone: BonePose, value: number, local: boolean, additive: boolean): void {
|
apply (skeleton: Skeleton, pose: TransformConstraintPose, bone: BonePose, value: number, local: boolean, additive: boolean): void {
|
||||||
if (local) {
|
if (local)
|
||||||
if (!additive) value -= bone.y;
|
bone.y += (additive ? value : value - bone.y) * pose.mixY;
|
||||||
bone.y += value * pose.mixY;
|
else {
|
||||||
} else {
|
|
||||||
if (!additive) value -= bone.worldY / skeleton.scaleY;
|
if (!additive) value -= bone.worldY / skeleton.scaleY;
|
||||||
bone.worldY += value * pose.mixY * skeleton.scaleY;
|
bone.worldY += value * pose.mixY * skeleton.scaleY;
|
||||||
}
|
}
|
||||||
@ -276,20 +274,20 @@ export class ToScaleX extends ToProperty {
|
|||||||
apply (skeleton: Skeleton, pose: TransformConstraintPose, bone: BonePose, value: number, local: boolean, additive: boolean): void {
|
apply (skeleton: Skeleton, pose: TransformConstraintPose, bone: BonePose, value: number, local: boolean, additive: boolean): void {
|
||||||
if (local) {
|
if (local) {
|
||||||
if (additive)
|
if (additive)
|
||||||
bone.scaleX *= 1 + ((value - 1) * pose.mixScaleX);
|
bone.scaleX *= 1 + (value - 1) * pose.mixScaleX;
|
||||||
else if (bone.scaleX != 0) //
|
else if (bone.scaleX != 0) //
|
||||||
bone.scaleX = 1 + (value / bone.scaleX - 1) * pose.mixScaleX;
|
bone.scaleX += (value - bone.scaleX) * pose.mixScaleX;
|
||||||
} else {
|
} else if (additive) {
|
||||||
let s: number;
|
const s = 1 + (value - 1) * pose.mixScaleX;
|
||||||
if (additive)
|
|
||||||
s = 1 + (value - 1) * pose.mixScaleX;
|
|
||||||
else {
|
|
||||||
const a = bone.a / skeleton.scaleX, c = bone.c / skeleton.scaleY;
|
|
||||||
s = Math.sqrt(a * a + c * c);
|
|
||||||
if (s != 0) s = 1 + (value / s - 1) * pose.mixScaleX;
|
|
||||||
}
|
|
||||||
bone.a *= s;
|
bone.a *= s;
|
||||||
bone.c *= s;
|
bone.c *= s;
|
||||||
|
} else {
|
||||||
|
let a = bone.a / skeleton.scaleX, c = bone.c / skeleton.scaleY, s = Math.sqrt(a * a + c * c);
|
||||||
|
if (s != 0) {
|
||||||
|
s = 1 + (value - s) * pose.mixScaleX / s;
|
||||||
|
bone.a *= s;
|
||||||
|
bone.c *= s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -310,20 +308,20 @@ export class ToScaleY extends ToProperty {
|
|||||||
apply (skeleton: Skeleton, pose: TransformConstraintPose, bone: BonePose, value: number, local: boolean, additive: boolean): void {
|
apply (skeleton: Skeleton, pose: TransformConstraintPose, bone: BonePose, value: number, local: boolean, additive: boolean): void {
|
||||||
if (local) {
|
if (local) {
|
||||||
if (additive)
|
if (additive)
|
||||||
bone.scaleY *= 1 + ((value - 1) * pose.mixScaleY);
|
bone.scaleY *= 1 + (value - 1) * pose.mixScaleY;
|
||||||
else if (bone.scaleY != 0) //
|
else if (bone.scaleY != 0) //
|
||||||
bone.scaleY = 1 + (value / bone.scaleY - 1) * pose.mixScaleY;
|
bone.scaleY += (value - bone.scaleY) * pose.mixScaleY;
|
||||||
} else {
|
} else if (additive) {
|
||||||
let s: number;
|
const s = 1 + (value - 1) * pose.mixScaleY;
|
||||||
if (additive)
|
|
||||||
s = 1 + (value - 1) * pose.mixScaleY;
|
|
||||||
else {
|
|
||||||
const b = bone.b / skeleton.scaleX, d = bone.d / skeleton.scaleY;
|
|
||||||
s = Math.sqrt(b * b + d * d);
|
|
||||||
if (s != 0) s = 1 + (value / s - 1) * pose.mixScaleY;
|
|
||||||
}
|
|
||||||
bone.b *= s;
|
bone.b *= s;
|
||||||
bone.d *= s;
|
bone.d *= s;
|
||||||
|
} else {
|
||||||
|
let b = bone.b / skeleton.scaleX, d = bone.d / skeleton.scaleY, s = Math.sqrt(b * b + d * d);
|
||||||
|
if (s != 0) {
|
||||||
|
s = 1 + (value - s) * pose.mixScaleY / s;
|
||||||
|
bone.b *= s;
|
||||||
|
bone.d *= s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -331,9 +329,8 @@ export class ToScaleY extends ToProperty {
|
|||||||
export class FromShearY extends FromProperty {
|
export class FromShearY extends FromProperty {
|
||||||
value (skeleton: Skeleton, source: BonePose, local: boolean, offsets: Array<number>): number {
|
value (skeleton: Skeleton, source: BonePose, local: boolean, offsets: Array<number>): number {
|
||||||
if (local) return source.shearY + offsets[TransformConstraintData.SHEARY];
|
if (local) return source.shearY + offsets[TransformConstraintData.SHEARY];
|
||||||
const sx = 1 / skeleton.scaleX, sy = 1 / skeleton.scaleY;
|
const ix = 1 / skeleton.scaleX, iy = 1 / skeleton.scaleY;
|
||||||
return (Math.atan2(source.d * sy, source.b * sx) - Math.atan2(source.c * sy, source.a * sx))
|
return (Math.atan2(source.d * iy, source.b * ix) - Math.atan2(source.c * iy, source.a * ix)) * MathUtils.radDeg - 90 + offsets[TransformConstraintData.SHEARY];
|
||||||
* MathUtils.radDeg - 90 + offsets[TransformConstraintData.SHEARY];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,168 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/lil-gui@0.20.0/dist/lil-gui.umd.min.js"></script>
|
|
||||||
<link href="https://cdn.jsdelivr.net/npm/lil-gui@0.20.0/dist/lil-gui.min.css" rel="stylesheet">
|
|
||||||
</head>
|
|
||||||
<script src="../dist/iife/spine-webgl.js"></script>
|
|
||||||
<style>
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<body>
|
|
||||||
<canvas id="canvas" style="position: absolute; width: 100%; height: 100%;"></canvas>
|
|
||||||
<script>
|
|
||||||
class App {
|
|
||||||
constructor() {
|
|
||||||
this.skeleton = null;
|
|
||||||
this.animationState = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
autoUpdate = true;
|
|
||||||
|
|
||||||
loadAssets(canvas) {
|
|
||||||
// Load the skeleton file.
|
|
||||||
canvas.assetManager.loadBinary("/assets/skeleton-scale.skel");
|
|
||||||
// Load the atlas and its pages.
|
|
||||||
canvas.assetManager.loadTextureAtlas("/assets/skeleton-scale.atlas");
|
|
||||||
}
|
|
||||||
|
|
||||||
initialize(canvas) {
|
|
||||||
let assetManager = canvas.assetManager;
|
|
||||||
|
|
||||||
// Create the texture atlas.
|
|
||||||
var atlas = assetManager.require("/assets/skeleton-scale.atlas");
|
|
||||||
|
|
||||||
// Create a AtlasAttachmentLoader that resolves region, mesh, boundingbox and path attachments
|
|
||||||
var atlasLoader = new spine.AtlasAttachmentLoader(atlas);
|
|
||||||
|
|
||||||
// Create a SkeletonBinary instance for parsing the .skel file.
|
|
||||||
var skeletonBinary = new spine.SkeletonBinary(atlasLoader);
|
|
||||||
|
|
||||||
// Set the scale to apply during parsing, parse the file, and create a new skeleton.
|
|
||||||
skeletonBinary.scale = .5;
|
|
||||||
var skeletonData = skeletonBinary.readSkeletonData(assetManager.require("/assets/skeleton-scale.skel"));
|
|
||||||
this.skeleton = new spine.Skeleton(skeletonData);
|
|
||||||
const skeleton = this.skeleton;
|
|
||||||
|
|
||||||
// Create an AnimationState, and set the "run" animation in looping mode.
|
|
||||||
var animationStateData = new spine.AnimationStateData(skeletonData);
|
|
||||||
this.animationState = new spine.AnimationState(animationStateData);
|
|
||||||
const tracks = this.skeleton.data.animations.map((animation, index) => {
|
|
||||||
const track = this.animationState.setAnimation(index, animation.name, true);
|
|
||||||
track.alpha = 0;
|
|
||||||
return track;
|
|
||||||
})
|
|
||||||
|
|
||||||
const myObject = {
|
|
||||||
sx: 1,
|
|
||||||
sy: 1,
|
|
||||||
autoUpdate: this.autoUpdate,
|
|
||||||
track_time: 0,
|
|
||||||
track_scale: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
const gui = new lil.GUI({});
|
|
||||||
|
|
||||||
gui.add(myObject, 'autoUpdate').name('autoUpdate').onChange(value => {
|
|
||||||
this.autoUpdate = value;
|
|
||||||
this.fakeUpdate();
|
|
||||||
});
|
|
||||||
gui.add(myObject, 'sx').min(-3).max(3).step(0.1).name('sx').onChange(value => {
|
|
||||||
skeleton.scaleX = value;
|
|
||||||
this.fakeUpdate();
|
|
||||||
});
|
|
||||||
gui.add(myObject, 'sy').min(-3).max(3).step(0.1).name('sy').onChange(value => {
|
|
||||||
skeleton.scaleY = value;
|
|
||||||
this.fakeUpdate();
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const constraint of skeleton.constraints) {
|
|
||||||
const name = constraint.data.name.split("-")[2];
|
|
||||||
const folder = gui.addFolder(constraint.data.name);
|
|
||||||
folder.open(false);
|
|
||||||
for (const mixType of Object.keys(constraint.data.setup)) {
|
|
||||||
const guiName = `${name}_${mixType}`;
|
|
||||||
myObject[guiName] = false;
|
|
||||||
folder.add(myObject, guiName).name(guiName).onChange(value => {
|
|
||||||
constraint.applied[mixType] = value ? 1 : 0;
|
|
||||||
this.fakeUpdate();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const folder = gui.addFolder("animations");
|
|
||||||
for (const track of tracks) {
|
|
||||||
myObject[track.animation.name] = false;
|
|
||||||
folder.add(myObject, track.animation.name).name(track.animation.name).onChange(value => {
|
|
||||||
track.alpha = value ? 1 : 0;
|
|
||||||
this.fakeUpdate();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
folder.add(myObject, 'track_time').min(0).max(60).step(1).name('track_time').onChange(value => {
|
|
||||||
for (const track of tracks) {
|
|
||||||
track.trackTime = value / 30;
|
|
||||||
}
|
|
||||||
this.fakeUpdate();
|
|
||||||
});
|
|
||||||
folder.add(myObject, 'track_scale').min(0).max(2).step(0.1).name('track_scale').onChange(value => {
|
|
||||||
for (const track of tracks) {
|
|
||||||
track.timeScale = value;
|
|
||||||
}
|
|
||||||
this.fakeUpdate();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fakeUpdate() {
|
|
||||||
this.animationState.update(0);
|
|
||||||
this.animationState.apply(this.skeleton);
|
|
||||||
this.skeleton.updateWorldTransform(spine.Physics.update);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(canvas, delta) {
|
|
||||||
|
|
||||||
if (!this.autoUpdate) return;
|
|
||||||
|
|
||||||
// Update the animation state using the delta time.
|
|
||||||
this.animationState.update(delta);
|
|
||||||
// Apply the animation state to the skeleton.
|
|
||||||
this.animationState.apply(this.skeleton);
|
|
||||||
// Let the skeleton update the transforms of its bones.
|
|
||||||
this.skeleton.updateWorldTransform(spine.Physics.update);
|
|
||||||
}
|
|
||||||
|
|
||||||
render(canvas) {
|
|
||||||
let renderer = canvas.renderer;
|
|
||||||
// Resize the viewport to the full canvas.
|
|
||||||
renderer.resize(spine.ResizeMode.Expand);
|
|
||||||
|
|
||||||
// Clear the canvas with a light gray color.
|
|
||||||
canvas.clear(0.2, 0.2, 0.2, 1);
|
|
||||||
|
|
||||||
// Begin rendering.
|
|
||||||
renderer.begin();
|
|
||||||
// Draw the skeleton
|
|
||||||
renderer.drawSkeleton(this.skeleton, true);
|
|
||||||
// Complete rendering.
|
|
||||||
renderer.end();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new spine.SpineCanvas(document.getElementById("canvas"), {
|
|
||||||
app: new App()
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>`
|
|
||||||
Loading…
x
Reference in New Issue
Block a user