Support for path constraint rotation, closed paths, outside curve position.

This commit is contained in:
NathanSweet 2016-05-25 17:19:35 +02:00
parent c406e44785
commit 00c5313bd1
2 changed files with 78 additions and 21 deletions

View File

@ -1,6 +1,8 @@
package com.esotericsoftware.spine;
import static com.badlogic.gdx.math.MathUtils.*;
import com.badlogic.gdx.math.Vector2;
import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.PathAttachment;
@ -10,7 +12,7 @@ public class PathConstraint implements Updatable {
Bone bone;
Slot target;
float position, rotateMix, translateMix;
final Vector2 temp = new Vector2();
final Vector2 worldPosition = new Vector2(), tangent = new Vector2();
public PathConstraint (PathConstraintData data, Skeleton skeleton) {
this.data = data;
@ -42,9 +44,21 @@ public class PathConstraint implements Updatable {
float translateMix = this.translateMix;
if (translateMix > 0) {
path.computeWorldPosition(target, position, temp);
bone.worldX += (temp.x - bone.worldX) * translateMix;
bone.worldY += (temp.y - bone.worldY) * translateMix;
path.computeWorldPosition(target, position, worldPosition, null);
bone.worldX += (worldPosition.x - bone.worldX) * translateMix;
bone.worldY += (worldPosition.y - bone.worldY) * translateMix;
}
float rotateMix = this.rotateMix;
if (rotateMix > 0) {
path.computeWorldPosition(target, position, worldPosition, tangent);
float r = worldPosition.sub(tangent).angle() - bone.getWorldRotationX();
float cos = cosDeg(r), sin = sinDeg(r);
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
bone.a = cos * a - sin * c;
bone.b = cos * b - sin * d;
bone.c = sin * a + cos * c;
bone.d = sin * b + cos * d;
}
}

View File

@ -32,6 +32,7 @@
package com.esotericsoftware.spine.attachments;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.esotericsoftware.spine.Slot;
@ -50,21 +51,23 @@ public class PathAttachment extends VertexAttachment {
super.computeWorldVertices(slot, worldVertices);
}
public void computeWorldPosition (Slot slot, float position, Vector2 out) {
public void computeWorldPosition (Slot slot, float position, Vector2 out, Vector2 tangent) {
// BOZO - Remove check?
if (worldVerticesLength < 12) return;
// BOZO - Path constraint rotation.
// BOZO - Closed paths.
// BOZO - Before/after open paths.
float x1, y1, cx1, cy1, cx2, cy2, x2, y2;
if (!constantSpeed) {
int curves = worldVerticesLength / 6 - 1;
int curves = worldVerticesLength / 6;
if (!closed) curves--;
position = MathUtils.clamp(position, 0, 1);
int curve = position < 1 ? (int)(curves * position) : curves - 1;
position = (position - curve / (float)curves) * curves;
float[] worldVertices = this.worldVertices;
if (closed && curve == curves - 1) {
super.computeWorldVertices(slot, curves * 6 - 4, 4, worldVertices, 0);
super.computeWorldVertices(slot, 0, 4, worldVertices, 4);
} else
super.computeWorldVertices(slot, curve * 6 + 2, 8, worldVertices, 0);
x1 = worldVertices[0];
@ -76,10 +79,19 @@ public class PathAttachment extends VertexAttachment {
x2 = worldVertices[6];
y2 = worldVertices[7];
} else {
// BOZO - Use offset and count for all attachment compute methods.
float[] worldVertices = this.worldVertices;
int verticesLength = worldVerticesLength - 4;
int verticesLength;
if (closed) {
verticesLength = worldVerticesLength;
super.computeWorldVertices(slot, 2, verticesLength - 2, worldVertices, 0);
super.computeWorldVertices(slot, 0, 2, worldVertices, verticesLength - 2);
worldVertices[verticesLength] = worldVertices[0];
worldVertices[verticesLength + 1] = worldVertices[1];
verticesLength += 2;
} else {
verticesLength = worldVerticesLength - 4;
super.computeWorldVertices(slot, 2, verticesLength, worldVertices, 0);
}
// Curve lengths.
float[] lengths = this.lengths;
@ -118,10 +130,35 @@ public class PathAttachment extends VertexAttachment {
x1 = x2;
y1 = y2;
}
position *= length;
// Outside curve.
if (!closed && (position < 0 || position > length)) {
if (position < 0) {
x1 = worldVertices[0];
y1 = worldVertices[1];
cx1 = worldVertices[2] - x1;
cy1 = worldVertices[3] - y1;
} else {
x1 = worldVertices[verticesLength - 2];
y1 = worldVertices[verticesLength - 1];
cx1 = x1 - worldVertices[verticesLength - 4];
cy1 = y1 - worldVertices[verticesLength - 3];
position -= length;
}
float r = MathUtils.atan2(cy1, cx1);
float cos = MathUtils.cos(r), sin = MathUtils.sin(r);
out.x = x1 + cos * position;
out.y = y1 + sin * position;
if (tangent != null) {
tangent.x = out.x - cos;
tangent.y = out.y - sin;
}
return;
}
// Determine curve containing position.
int curve;
position *= length;
length = lengths[0];
if (position <= length) {
curve = 0;
@ -191,10 +228,16 @@ public class PathAttachment extends VertexAttachment {
}
}
// Calculate point.
float ttt = position * position * position, u = 1 - position;
float uuu = u * u * u, ut3 = u * position * 3, uut3 = u * ut3, utt3 = position * ut3;
out.set(x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt);
// Calculate point and tangent.
position += 0.0001f;
float tt = position * position, ttt = tt * position, u = 1 - position, uu = u * u, uuu = uu * u;
float ut = u * position, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * position;
out.x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt;
out.y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt;
if (tangent != null) {
tangent.x = x1 * uu + cx1 * ut * 2 + cx2 * tt;
tangent.y = y1 * uu + cy1 * ut * 2 + cy2 * tt;
}
}
public Color getColor () {
@ -220,7 +263,7 @@ public class PathAttachment extends VertexAttachment {
public void setWorldVerticesLength (int worldVerticesLength) {
super.setWorldVerticesLength(worldVerticesLength);
// BOZO! - Don't reallocate for editor.
worldVertices = new float[Math.max(2, worldVerticesLength)];
lengths = new float[Math.max(10, worldVerticesLength / 6 - 1)];
worldVertices = new float[Math.max(2, worldVerticesLength + 4)];
lengths = new float[Math.max(10, worldVerticesLength / 6)];
}
}