[libgdx] Physics progress, springs have a bone for rotate/scale.

This commit is contained in:
Nathan Sweet 2022-10-18 16:32:48 -04:00
parent c2e323937d
commit dffd590966
3 changed files with 63 additions and 33 deletions

View File

@ -42,6 +42,8 @@ import com.esotericsoftware.spine.PhysicsConstraintData.SpringData;
* <p> * <p>
* See <a href="http://esotericsoftware.com/spine-physics-constraints">Physics constraints</a> in the Spine User Guide. */ * See <a href="http://esotericsoftware.com/spine-physics-constraints">Physics constraints</a> in the Spine User Guide. */
public class PhysicsConstraint implements Updatable { public class PhysicsConstraint implements Updatable {
static final Vector2 temp = new Vector2();
final PhysicsConstraintData data; final PhysicsConstraintData data;
final Array<Node> nodes; final Array<Node> nodes;
final Array<Spring> springs; final Array<Spring> springs;
@ -51,7 +53,6 @@ public class PhysicsConstraint implements Updatable {
final Skeleton skeleton; final Skeleton skeleton;
float remaining, lastTime; float remaining, lastTime;
final Vector2 temp = new Vector2();
public PhysicsConstraint (PhysicsConstraintData data, Skeleton skeleton) { public PhysicsConstraint (PhysicsConstraintData data, Skeleton skeleton) {
if (data == null) throw new IllegalArgumentException("data cannot be null."); if (data == null) throw new IllegalArgumentException("data cannot be null.");
@ -123,9 +124,11 @@ public class PhysicsConstraint implements Updatable {
/** Applies the constraint to the constrained bones. */ /** Applies the constraint to the constrained bones. */
public void update () { public void update () {
if (mix == 0) return;
Object[] nodes = this.nodes.items; Object[] nodes = this.nodes.items;
int nodeCount = this.nodes.size; int nodeCount = this.nodes.size;
Vector2 temp = this.temp; Vector2 temp = PhysicsConstraint.temp;
for (int i = 0; i < nodeCount; i++) { for (int i = 0; i < nodeCount; i++) {
Node node = (Node)nodes[i]; Node node = (Node)nodes[i];
if (node.parentBone == null) continue; if (node.parentBone == null) continue;
@ -142,26 +145,29 @@ public class PhysicsConstraint implements Updatable {
while (remaining >= 0.016f) { while (remaining >= 0.016f) {
remaining -= 0.016f; remaining -= 0.016f;
for (int i = 0; i < springCount; i++) for (int i = 0; i < springCount; i++)
((Spring)springs[i]).update(); ((Spring)springs[i]).step();
for (int i = 0; i < nodeCount; i++) for (int i = 0; i < nodeCount; i++)
((Node)nodes[i]).update(this); ((Node)nodes[i]).step(this);
} }
if (mix == 1) {
for (int i = 0; i < nodeCount; i++) { for (int i = 0; i < nodeCount; i++) {
Node node = (Node)nodes[i]; Node node = (Node)nodes[i];
Object[] bones = node.bones; Object[] bones = node.bones;
int ii = 0, nn = bones.length; for (int ii = 0, nn = bones.length; ii < nn; ii++) {
if (mix == 1) {
for (; ii < nn; ii++) {
Bone bone = (Bone)bones[ii]; Bone bone = (Bone)bones[ii];
bone.worldX = node.x; bone.worldX = node.x;
bone.worldY = node.y; bone.worldY = node.y;
bone.worldToLocal(temp.set(bone.worldX, bone.worldY)); bone.parent.worldToLocal(temp.set(node.x, node.y));
bone.ax = temp.x; bone.ax = temp.x;
bone.ay = temp.y; bone.ay = temp.y;
} }
}
} else { } else {
for (; ii < nn; ii++) { for (int i = 0; i < nodeCount; i++) {
Node node = (Node)nodes[i];
Object[] bones = node.bones;
for (int ii = 0, nn = bones.length; ii < nn; ii++) {
Bone bone = (Bone)bones[ii]; Bone bone = (Bone)bones[ii];
bone.worldX = bone.worldX + (node.x - bone.worldX) * mix; bone.worldX = bone.worldX + (node.x - bone.worldX) * mix;
bone.worldY = bone.worldY + (node.y - bone.worldY) * mix; bone.worldY = bone.worldY + (node.y - bone.worldY) * mix;
@ -295,12 +301,8 @@ public class PhysicsConstraint implements Updatable {
vy = 0; vy = 0;
} }
public void update (PhysicsConstraint constraint) { public void step (PhysicsConstraint constraint) {
if (parentBone != null) { if (parentBone != null) return;
vx = 0;
vy = 0;
return;
}
x += vx; x += vx;
y += vy; y += vy;
vx = vx * constraint.friction + constraint.wind; vx = vx * constraint.friction + constraint.wind;
@ -308,35 +310,36 @@ public class PhysicsConstraint implements Updatable {
} }
} }
static public class Spring { static public class Spring implements Updatable {
public final SpringData data; public final SpringData data;
public final PhysicsConstraint constraint;
public Node node1, node2; public Node node1, node2;
public Bone[] bones; public Bone bone;
public float length, stiffness, damping; public float length, stiffness, damping;
Spring (SpringData data) { // Editor. Spring (SpringData data, PhysicsConstraint constraint) { // Editor.
this.data = data; this.data = data;
this.constraint = constraint;
} }
public Spring (SpringData data, PhysicsConstraint constraint, Skeleton skeleton) { public Spring (SpringData data, PhysicsConstraint constraint, Skeleton skeleton) {
this.data = data; this.data = data;
this.constraint = constraint;
node1 = constraint.nodes.get(data.node1); node1 = constraint.nodes.get(data.node1);
node2 = constraint.nodes.get(data.node2); node2 = constraint.nodes.get(data.node2);
bones = new Bone[data.bones.length]; bone = skeleton.bones.get(data.bone);
for (int i = 0, n = bones.length; i < n; i++)
bones[i] = skeleton.bones.get(data.bones[i]);
setToSetupPose(); setToSetupPose();
} }
public Spring (Spring spring, PhysicsConstraint constraint) { public Spring (Spring spring, PhysicsConstraint constraint) {
this.data = spring.data; this.data = spring.data;
this.constraint = constraint;
node1 = constraint.nodes.get(data.node1); node1 = constraint.nodes.get(data.node1);
node2 = constraint.nodes.get(data.node2); node2 = constraint.nodes.get(data.node2);
bones = new Bone[spring.bones.length]; bone = spring.bone;
arraycopy(spring.bones, 0, bones, 0, bones.length);
length = spring.length; length = spring.length;
stiffness = spring.stiffness; stiffness = spring.stiffness;
damping = spring.damping; damping = spring.damping;
@ -348,9 +351,10 @@ public class PhysicsConstraint implements Updatable {
damping = data.damping; damping = data.damping;
} }
public void update () { public void step () {
float x = node2.x - node1.x, y = node2.y - node1.y, d = (float)Math.sqrt(Math.max(x * x + y * y, 0.00001f)); float x = node2.x - node1.x, y = node2.y - node1.y, d = x * x + y * y;
if (data.rope && d <= length) return; if (data.rope && d <= length) return;
d = (float)Math.sqrt(Math.max(d, 0.00001f));
x /= d; x /= d;
y /= d; y /= d;
float m1 = node1.massInverse, m2 = node2.massInverse; float m1 = node1.massInverse, m2 = node2.massInverse;
@ -362,5 +366,21 @@ public class PhysicsConstraint implements Updatable {
node2.vx -= x * m2; node2.vx -= x * m2;
node2.vy -= y * m2; node2.vy -= y * m2;
} }
public void update () {
float dx = node2.x - node1.x, dy = node2.y - node1.y;
float s = (float)Math.sqrt(dx * dx + dy * dy) / length, r = atan2(dy, dx), sin = sin(r), cos = cos(r);
if (constraint.mix == 1) {
bone.updateWorldTransform(bone.ax, bone.ay,
atan2(bone.a * sin - bone.c * cos, bone.d * cos - bone.b * sin) * radDeg + bone.arotation - bone.ashearX,
bone.ascaleX * s, bone.ascaleY, bone.ashearX, bone.ashearY);
} else {
// BOZO
}
}
public boolean isActive () {
return constraint.active;
}
} }
} }

View File

@ -115,8 +115,7 @@ public class PhysicsConstraintData extends ConstraintData {
} }
static public class SpringData { static public class SpringData {
public int node1, node2; public int node1, node2, bone;
public int[] bones;
public float length, stiffness, damping; public float length, stiffness, damping;
public boolean rope; public boolean rope;
} }

View File

@ -38,6 +38,7 @@ import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.Null; import com.badlogic.gdx.utils.Null;
import com.esotericsoftware.spine.PhysicsConstraint.Node; import com.esotericsoftware.spine.PhysicsConstraint.Node;
import com.esotericsoftware.spine.PhysicsConstraint.Spring;
import com.esotericsoftware.spine.Skin.SkinEntry; import com.esotericsoftware.spine.Skin.SkinEntry;
import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.MeshAttachment; import com.esotericsoftware.spine.attachments.MeshAttachment;
@ -355,16 +356,26 @@ public class Skeleton {
for (int i = 0; i < nodeCount; i++) { for (int i = 0; i < nodeCount; i++) {
Node node = (Node)nodes[i]; Node node = (Node)nodes[i];
if (node.parentBone != null) sortReset(node.parentBone.children);
for (Bone bone : node.bones) for (Bone bone : node.bones)
sortReset(bone.children); sortReset(bone.children);
} }
for (int i = 0; i < nodeCount; i++) { for (int i = 0; i < nodeCount; i++) {
Node node = (Node)nodes[i]; Node node = (Node)nodes[i];
if (node.parentBone != null) node.parentBone.sorted = true;
for (Bone bone : node.bones) for (Bone bone : node.bones)
bone.sorted = true; bone.sorted = true;
} }
Object[] springs = constraint.springs.items;
for (int i = 0, n = constraint.springs.size; i < n; i++) {
Spring spring = (Spring)springs[i];
if (spring.bone == null) continue;
sortBone(spring.bone);
updateCache.add(spring);
sortReset(spring.bone.children);
spring.bone.sorted = true;
for (Bone child : spring.bone.children)
sortBone(child);
}
} }
private void sortBone (Bone bone) { private void sortBone (Bone bone) {