mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-28 04:31:27 +08:00
Multiple constrained bones for transform constraints.
This commit is contained in:
parent
8b3b0169ad
commit
92d7ef32f4
@ -27,14 +27,14 @@ public class PathConstraint implements Updatable {
|
|||||||
if (data == null) throw new IllegalArgumentException("data cannot be null.");
|
if (data == null) throw new IllegalArgumentException("data cannot be null.");
|
||||||
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
||||||
this.data = data;
|
this.data = data;
|
||||||
position = data.position;
|
|
||||||
spacing = data.spacing;
|
|
||||||
rotateMix = data.rotateMix;
|
|
||||||
translateMix = data.translateMix;
|
|
||||||
bones = new Array(data.bones.size);
|
bones = new Array(data.bones.size);
|
||||||
for (BoneData boneData : data.bones)
|
for (BoneData boneData : data.bones)
|
||||||
bones.add(skeleton.findBone(boneData.name));
|
bones.add(skeleton.findBone(boneData.name));
|
||||||
target = skeleton.findSlot(data.target.name);
|
target = skeleton.findSlot(data.target.name);
|
||||||
|
position = data.position;
|
||||||
|
spacing = data.spacing;
|
||||||
|
rotateMix = data.rotateMix;
|
||||||
|
translateMix = data.translateMix;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Copy constructor. */
|
/** Copy constructor. */
|
||||||
|
|||||||
@ -227,21 +227,17 @@ public class Skeleton {
|
|||||||
|
|
||||||
sortBone(constraint.target);
|
sortBone(constraint.target);
|
||||||
|
|
||||||
// BOZO! - Update transform constraints to support multiple constrained bones.
|
Array<Bone> constrained = constraint.bones;
|
||||||
// Array<Bone> constrained = constraint.bones;
|
int boneCount = constrained.size;
|
||||||
// int boneCount = constrained.size;
|
for (int ii = 0; ii < boneCount; ii++)
|
||||||
// for (int ii = 0; ii < boneCount; ii++)
|
sortBone(constrained.get(ii));
|
||||||
// sortBone(constrained.get(ii));
|
|
||||||
sortBone(constraint.bone);
|
|
||||||
|
|
||||||
updateCache.add(constraint);
|
updateCache.add(constraint);
|
||||||
|
|
||||||
// for (int ii = 0; ii < boneCount; ii++)
|
for (int ii = 0; ii < boneCount; ii++)
|
||||||
// reset(constrained.get(ii).children);
|
sortReset(constrained.get(ii).children);
|
||||||
sortReset(constraint.bone.children); // BOZO - Remove.
|
for (int ii = 0; ii < boneCount; ii++)
|
||||||
// for (int ii = 0; ii < boneCount; ii++)
|
constrained.get(ii).sorted = true;
|
||||||
// constrained.get(ii).sorted = true;
|
|
||||||
constraint.bone.sorted = true; // BOZO - Remove.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0, n = bones.size; i < n; i++)
|
for (int i = 0, n = bones.size; i < n; i++)
|
||||||
|
|||||||
@ -217,7 +217,8 @@ public class SkeletonBinary {
|
|||||||
// Transform constraints.
|
// Transform constraints.
|
||||||
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
||||||
TransformConstraintData data = new TransformConstraintData(input.readString());
|
TransformConstraintData data = new TransformConstraintData(input.readString());
|
||||||
data.bone = skeletonData.bones.get(input.readInt(true));
|
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++)
|
||||||
|
data.bones.add(skeletonData.bones.get(input.readInt(true)));
|
||||||
data.target = skeletonData.bones.get(input.readInt(true));
|
data.target = skeletonData.bones.get(input.readInt(true));
|
||||||
data.offsetRotation = input.readFloat();
|
data.offsetRotation = input.readFloat();
|
||||||
data.offsetX = input.readFloat() * scale;
|
data.offsetX = input.readFloat() * scale;
|
||||||
|
|||||||
@ -179,9 +179,12 @@ public class SkeletonJson {
|
|||||||
for (JsonValue constraintMap = root.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) {
|
for (JsonValue constraintMap = root.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) {
|
||||||
TransformConstraintData data = new TransformConstraintData(constraintMap.getString("name"));
|
TransformConstraintData data = new TransformConstraintData(constraintMap.getString("name"));
|
||||||
|
|
||||||
String boneName = constraintMap.getString("bone");
|
for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) {
|
||||||
data.bone = skeletonData.findBone(boneName);
|
String boneName = boneMap.asString();
|
||||||
if (data.bone == null) throw new SerializationException("Bone not found: " + boneName);
|
BoneData bone = skeletonData.findBone(boneName);
|
||||||
|
if (bone == null) throw new SerializationException("Path bone not found: " + boneName);
|
||||||
|
data.bones.add(bone);
|
||||||
|
}
|
||||||
|
|
||||||
String targetName = constraintMap.getString("target");
|
String targetName = constraintMap.getString("target");
|
||||||
data.target = skeletonData.findBone(targetName);
|
data.target = skeletonData.findBone(targetName);
|
||||||
|
|||||||
@ -4,10 +4,12 @@ package com.esotericsoftware.spine;
|
|||||||
import static com.badlogic.gdx.math.MathUtils.*;
|
import static com.badlogic.gdx.math.MathUtils.*;
|
||||||
|
|
||||||
import com.badlogic.gdx.math.Vector2;
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
|
||||||
public class TransformConstraint implements Updatable {
|
public class TransformConstraint implements Updatable {
|
||||||
final TransformConstraintData data;
|
final TransformConstraintData data;
|
||||||
Bone bone, target;
|
final Array<Bone> bones;
|
||||||
|
Bone target;
|
||||||
float rotateMix, translateMix, scaleMix, shearMix;
|
float rotateMix, translateMix, scaleMix, shearMix;
|
||||||
final Vector2 temp = new Vector2();
|
final Vector2 temp = new Vector2();
|
||||||
|
|
||||||
@ -19,7 +21,9 @@ public class TransformConstraint implements Updatable {
|
|||||||
translateMix = data.translateMix;
|
translateMix = data.translateMix;
|
||||||
scaleMix = data.scaleMix;
|
scaleMix = data.scaleMix;
|
||||||
shearMix = data.shearMix;
|
shearMix = data.shearMix;
|
||||||
bone = skeleton.findBone(data.bone.name);
|
bones = new Array(data.bones.size);
|
||||||
|
for (BoneData boneData : data.bones)
|
||||||
|
bones.add(skeleton.findBone(boneData.name));
|
||||||
target = skeleton.findBone(data.target.name);
|
target = skeleton.findBone(data.target.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,12 +32,14 @@ public class TransformConstraint implements Updatable {
|
|||||||
if (constraint == null) throw new IllegalArgumentException("constraint cannot be null.");
|
if (constraint == null) throw new IllegalArgumentException("constraint cannot be null.");
|
||||||
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
||||||
data = constraint.data;
|
data = constraint.data;
|
||||||
|
bones = new Array(constraint.bones.size);
|
||||||
|
for (Bone bone : constraint.bones)
|
||||||
|
bones.add(skeleton.bones.get(bone.data.index));
|
||||||
|
target = skeleton.bones.get(constraint.target.data.index);
|
||||||
rotateMix = constraint.rotateMix;
|
rotateMix = constraint.rotateMix;
|
||||||
translateMix = constraint.translateMix;
|
translateMix = constraint.translateMix;
|
||||||
scaleMix = constraint.scaleMix;
|
scaleMix = constraint.scaleMix;
|
||||||
shearMix = constraint.shearMix;
|
shearMix = constraint.shearMix;
|
||||||
bone = skeleton.bones.get(constraint.bone.data.index);
|
|
||||||
target = skeleton.bones.get(constraint.target.data.index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply () {
|
public void apply () {
|
||||||
@ -41,64 +47,64 @@ public class TransformConstraint implements Updatable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void update () {
|
public void update () {
|
||||||
Bone bone = this.bone;
|
float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
|
||||||
Bone target = this.target;
|
Bone target = this.target;
|
||||||
|
float ta = target.a, tb = target.b, tc = target.c, td = target.d;
|
||||||
|
Array<Bone> bones = this.bones;
|
||||||
|
for (int i = 0, n = bones.size; i < n; i++) {
|
||||||
|
Bone bone = bones.get(i);
|
||||||
|
|
||||||
if (rotateMix > 0) {
|
if (rotateMix > 0) {
|
||||||
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
||||||
float r = atan2(target.c, target.a) - atan2(c, a) + data.offsetRotation * degRad;
|
float r = atan2(tc, ta) - atan2(c, a) + data.offsetRotation * degRad;
|
||||||
if (r > PI)
|
if (r > PI)
|
||||||
r -= PI2;
|
r -= PI2;
|
||||||
else if (r < -PI) r += PI2;
|
else if (r < -PI) r += PI2;
|
||||||
r *= rotateMix;
|
r *= rotateMix;
|
||||||
float cos = cos(r), sin = sin(r);
|
float cos = cos(r), sin = sin(r);
|
||||||
bone.a = cos * a - sin * c;
|
bone.a = cos * a - sin * c;
|
||||||
bone.b = cos * b - sin * d;
|
bone.b = cos * b - sin * d;
|
||||||
bone.c = sin * a + cos * c;
|
bone.c = sin * a + cos * c;
|
||||||
bone.d = sin * b + cos * d;
|
bone.d = sin * b + cos * d;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scaleMix > 0) {
|
if (translateMix > 0) {
|
||||||
float bs = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c);
|
Vector2 temp = this.temp;
|
||||||
float ts = (float)Math.sqrt(target.a * target.a + target.c * target.c);
|
target.localToWorld(temp.set(data.offsetX, data.offsetY));
|
||||||
float s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0;
|
bone.worldX += (temp.x - bone.worldX) * translateMix;
|
||||||
bone.a *= s;
|
bone.worldY += (temp.y - bone.worldY) * translateMix;
|
||||||
bone.c *= s;
|
}
|
||||||
bs = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d);
|
|
||||||
ts = (float)Math.sqrt(target.b * target.b + target.d * target.d);
|
|
||||||
s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0;
|
|
||||||
bone.b *= s;
|
|
||||||
bone.d *= s;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shearMix > 0) {
|
if (scaleMix > 0) {
|
||||||
float b = bone.b, d = bone.d;
|
float bs = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c);
|
||||||
float by = atan2(d, b);
|
float ts = (float)Math.sqrt(ta * ta + tc * tc);
|
||||||
float r = atan2(target.d, target.b) - atan2(target.c, target.a) - (by - atan2(bone.c, bone.a));
|
float s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0;
|
||||||
if (r > PI)
|
bone.a *= s;
|
||||||
r -= PI2;
|
bone.c *= s;
|
||||||
else if (r < -PI) r += PI2;
|
bs = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d);
|
||||||
r = by + (r + data.offsetShearY * degRad) * shearMix;
|
ts = (float)Math.sqrt(tb * tb + td * td);
|
||||||
float s = (float)Math.sqrt(b * b + d * d);
|
s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0;
|
||||||
bone.b = cos(r) * s;
|
bone.b *= s;
|
||||||
bone.d = sin(r) * s;
|
bone.d *= s;
|
||||||
}
|
}
|
||||||
|
|
||||||
float translateMix = this.translateMix;
|
if (shearMix > 0) {
|
||||||
if (translateMix > 0) {
|
float b = bone.b, d = bone.d;
|
||||||
Vector2 temp = this.temp;
|
float by = atan2(d, b);
|
||||||
target.localToWorld(temp.set(data.offsetX, data.offsetY));
|
float r = atan2(td, tb) - atan2(tc, ta) - (by - atan2(bone.c, bone.a));
|
||||||
bone.worldX += (temp.x - bone.worldX) * translateMix;
|
if (r > PI)
|
||||||
bone.worldY += (temp.y - bone.worldY) * translateMix;
|
r -= PI2;
|
||||||
|
else if (r < -PI) r += PI2;
|
||||||
|
r = by + (r + data.offsetShearY * degRad) * shearMix;
|
||||||
|
float s = (float)Math.sqrt(b * b + d * d);
|
||||||
|
bone.b = cos(r) * s;
|
||||||
|
bone.d = sin(r) * s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bone getBone () {
|
public Array<Bone> getBones () {
|
||||||
return bone;
|
return bones;
|
||||||
}
|
|
||||||
|
|
||||||
public void setBone (Bone bone) {
|
|
||||||
this.bone = bone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bone getTarget () {
|
public Bone getTarget () {
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.spine;
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
|
||||||
public class TransformConstraintData {
|
public class TransformConstraintData {
|
||||||
final String name;
|
final String name;
|
||||||
BoneData bone, target;
|
final Array<BoneData> bones = new Array();
|
||||||
|
BoneData target;
|
||||||
float rotateMix, translateMix, scaleMix, shearMix;
|
float rotateMix, translateMix, scaleMix, shearMix;
|
||||||
float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
|
float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
|
||||||
|
|
||||||
@ -16,13 +19,8 @@ public class TransformConstraintData {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoneData getBone () {
|
public Array<BoneData> getBones () {
|
||||||
return bone;
|
return bones;
|
||||||
}
|
|
||||||
|
|
||||||
public void setBone (BoneData bone) {
|
|
||||||
if (bone == null) throw new IllegalArgumentException("bone cannot be null.");
|
|
||||||
this.bone = bone;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BoneData getTarget () {
|
public BoneData getTarget () {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user