From c33326e872ac2a6e420481c0ac0f4670fe75f6d4 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Sat, 9 Oct 2021 21:22:50 -1000 Subject: [PATCH] Changed physics to match new plan. --- .../esotericsoftware/spine/IkConstraint.java | 9 ++ .../spine/PathConstraint.java | 9 ++ .../spine/PhysicsConstraint.java | 138 +++++++++-------- .../spine/PhysicsConstraintData.java | 141 ++++++++++++++---- .../com/esotericsoftware/spine/Skeleton.java | 76 ++++------ .../spine/TransformConstraint.java | 10 ++ 6 files changed, 245 insertions(+), 138 deletions(-) diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java index f4f1987eb..a07c96de0 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java @@ -79,6 +79,15 @@ public class IkConstraint implements Updatable { stretch = constraint.stretch; } + public void setToSetupPose () { + IkConstraintData data = this.data; + mix = data.mix; + softness = data.softness; + bendDirection = data.bendDirection; + compress = data.compress; + stretch = data.stretch; + } + /** Applies the constraint to the constrained bones. */ public void update () { if (mix == 0) return; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java index 0a80cf54b..78b069fcb 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java @@ -91,6 +91,15 @@ public class PathConstraint implements Updatable { mixY = constraint.mixY; } + public void setToSetupPose () { + PathConstraintData data = this.data; + position = data.position; + spacing = data.spacing; + mixRotate = data.mixRotate; + mixX = data.mixX; + mixY = data.mixY; + } + /** Applies the constraint to the constrained bones. */ public void update () { Attachment attachment = target.attachment; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java index b538f403c..baadc420e 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java @@ -31,15 +31,19 @@ package com.esotericsoftware.spine; import com.badlogic.gdx.utils.Array; +import com.esotericsoftware.spine.PhysicsConstraintData.Node; +import com.esotericsoftware.spine.PhysicsConstraintData.NodeData; +import com.esotericsoftware.spine.PhysicsConstraintData.Spring; +import com.esotericsoftware.spine.PhysicsConstraintData.SpringData; + /** Stores the current pose for a physics constraint. A physics constraint applies physics to bones. *

* See Physics constraints in the Spine User Guide. */ public class PhysicsConstraint implements Updatable { final PhysicsConstraintData data; - final Array bones; - // BOZO! - stiffness -> strength. stiffness, damping, rope, stretch -> move to spring. - float mix, friction, gravity, wind, stiffness, damping; - boolean rope, stretch; + final Array nodes; + final Array springs; + float mix, length, strength, damping, gravity, wind; boolean active; @@ -47,18 +51,21 @@ public class PhysicsConstraint implements Updatable { if (data == null) throw new IllegalArgumentException("data cannot be null."); if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); this.data = data; + + nodes = new Array(data.nodes.size); + for (NodeData nodeData : data.nodes) + nodes.add(new Node(nodeData, skeleton)); + + springs = new Array(data.springs.size); + for (SpringData springData : data.springs) + springs.add(new Spring(springData, this, skeleton)); + mix = data.mix; - friction = data.friction; + length = data.length; + strength = data.strength; + damping = data.damping; gravity = data.gravity; wind = data.wind; - stiffness = data.stiffness; - damping = data.damping; - rope = data.rope; - stretch = data.stretch; - - bones = new Array(data.bones.size); - for (BoneData boneData : data.bones) - bones.add(skeleton.bones.get(boneData.index)); } /** Copy constructor. */ @@ -66,27 +73,52 @@ public class PhysicsConstraint implements Updatable { if (constraint == null) throw new IllegalArgumentException("constraint cannot be null."); if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); data = constraint.data; - bones = new Array(constraint.bones.size); - for (Bone bone : constraint.bones) - bones.add(skeleton.bones.get(bone.data.index)); + + nodes = new Array(constraint.nodes.size); + for (Node node : constraint.nodes) + nodes.add(new Node(node)); + + springs = new Array(constraint.springs.size); + for (Spring spring : constraint.springs) + springs.add(new Spring(spring, this)); + mix = constraint.mix; - friction = constraint.friction; + length = constraint.length; + strength = constraint.strength; + damping = constraint.damping; gravity = constraint.gravity; wind = constraint.wind; - stiffness = constraint.stiffness; - damping = constraint.damping; - rope = constraint.rope; - stretch = constraint.stretch; + } + + public void setToSetupPose () { + Object[] nodes = this.nodes.items; + for (int i = 0, n = this.nodes.size; i < n; i++) + ((Node)nodes[i]).setToSetupPose(); + + Object[] springs = this.springs.items; + for (int i = 0, n = this.springs.size; i < n; i++) + ((Spring)springs[i]).setToSetupPose(); + + PhysicsConstraintData data = this.data; + mix = data.mix; + length = data.length; + strength = data.strength; + damping = data.damping; + gravity = data.gravity; + wind = data.wind; } /** Applies the constraint to the constrained bones. */ public void update () { - + // BOZO! - Physics. } - /** The bones that will be modified by this physics constraint. */ - public Array getBones () { - return bones; + public Array getNodes () { + return nodes; + } + + public Array getSprings () { + return springs; } /** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */ @@ -98,12 +130,28 @@ public class PhysicsConstraint implements Updatable { this.mix = mix; } - public float getFriction () { - return friction; + public float getLength () { + return length; } - public void setFriction (float friction) { - this.friction = friction; + public void setLength (float length) { + this.length = length; + } + + public float getStrength () { + return strength; + } + + public void setStrength (float strength) { + this.strength = strength; + } + + public float getDamping () { + return damping; + } + + public void setDamping (float damping) { + this.damping = damping; } public float getGravity () { @@ -122,38 +170,6 @@ public class PhysicsConstraint implements Updatable { this.wind = wind; } - public float getStiffness () { - return stiffness; - } - - public void setStiffness (float stiffness) { - this.stiffness = stiffness; - } - - public float getDamping () { - return damping; - } - - public void setDamping (float damping) { - this.damping = damping; - } - - public boolean getRope () { - return rope; - } - - public void setRope (boolean rope) { - this.rope = rope; - } - - public boolean getStretch () { - return stretch; - } - - public void setStretch (boolean stretch) { - this.stretch = stretch; - } - public boolean isActive () { return active; } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraintData.java index 9f9ad330e..cf273fb42 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraintData.java @@ -29,23 +29,29 @@ package com.esotericsoftware.spine; +import static com.esotericsoftware.spine.utils.SpineUtils.*; + import com.badlogic.gdx.utils.Array; +import com.badlogic.gdx.utils.Null; /** Stores the setup pose for a {@link PhysicsConstraint}. *

* See Physics constraints in the Spine User Guide. */ public class PhysicsConstraintData extends ConstraintData { - final Array bones = new Array(); - float mix, friction, gravity, wind, stiffness, damping; - boolean rope, stretch; + final Array nodes = new Array(); + final Array springs = new Array(); + float mix, length, strength, damping, gravity, wind; public PhysicsConstraintData (String name) { super(name); } - /** The bones that are constrained by this physics constraint. */ - public Array getBones () { - return bones; + public Array getNodes () { + return nodes; + } + + public Array getSprings () { + return springs; } /** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */ @@ -57,12 +63,28 @@ public class PhysicsConstraintData extends ConstraintData { this.mix = mix; } - public float getFriction () { - return friction; + public float getLength () { + return length; } - public void setFriction (float friction) { - this.friction = friction; + public void setLength (float length) { + this.length = length; + } + + public float getStrength () { + return strength; + } + + public void setStrength (float strength) { + this.strength = strength; + } + + public float getDamping () { + return damping; + } + + public void setDamping (float damping) { + this.damping = damping; } public float getGravity () { @@ -81,35 +103,94 @@ public class PhysicsConstraintData extends ConstraintData { this.wind = wind; } - public float getStiffness () { - return stiffness; + static public class NodeData { + public int parentBone = -1; + public int[] bones; + public float x, y; } - public void setStiffness (float stiffness) { - this.stiffness = stiffness; + static public class Node { + public final NodeData data; + public final @Null Bone parentBone; + public final Bone[] bones; + public float x, y, px, py, ax, ay; + + public Node (NodeData data, Skeleton skeleton) { + this.data = data; + + parentBone = data.parentBone == -1 ? null : skeleton.bones.get(data.parentBone); + + bones = new Bone[data.bones.length]; + for (int i = 0, n = bones.length; i < n; i++) + bones[i] = skeleton.bones.get(data.bones[i]); + + setToSetupPose(); + } + + public Node (Node node) { + this.data = node.data; + parentBone = node.parentBone; + bones = new Bone[node.bones.length]; + arraycopy(node.bones, 0, bones, 0, bones.length); + x = node.x; + y = node.y; + px = node.px; + py = node.py; + ax = node.ax; + ay = node.ay; + } + + public void setToSetupPose () { + x = data.x; + y = data.y; + px = x; + py = y; + ax = 0; + ay = 0; + } } - public float getDamping () { - return damping; + static public class SpringData { + public int node1, node2; + public int[] bones; + public float length, strength, damping; + public boolean rope, stretch; } - public void setDamping (float damping) { - this.damping = damping; - } + static public class Spring { + public final SpringData data; + public final Node node1, node2; + public final Bone[] bones; + public float length, strength, damping; - public boolean getRope () { - return rope; - } + public Spring (SpringData data, PhysicsConstraint constraint, Skeleton skeleton) { + this.data = data; - public void setRope (boolean rope) { - this.rope = rope; - } + node1 = constraint.nodes.get(data.node1); + node2 = constraint.nodes.get(data.node2); - public boolean getStretch () { - return stretch; - } + bones = new Bone[data.bones.length]; + for (int i = 0, n = bones.length; i < n; i++) + bones[i] = skeleton.bones.get(data.bones[i]); - public void setStretch (boolean stretch) { - this.stretch = stretch; + setToSetupPose(); + } + + public Spring (Spring spring, PhysicsConstraint constraint) { + this.data = spring.data; + node1 = constraint.nodes.get(data.node1); + node2 = constraint.nodes.get(data.node2); + bones = new Bone[spring.bones.length]; + arraycopy(spring.bones, 0, bones, 0, bones.length); + length = spring.length; + strength = spring.strength; + damping = spring.damping; + } + + public void setToSetupPose () { + length = data.length; + strength = data.strength; + damping = data.damping; + } } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java index f60d8d9e2..b46f98fd1 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java @@ -37,6 +37,7 @@ import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.FloatArray; import com.badlogic.gdx.utils.Null; +import com.esotericsoftware.spine.PhysicsConstraintData.Node; import com.esotericsoftware.spine.Skin.SkinEntry; import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.MeshAttachment; @@ -337,17 +338,29 @@ public class Skeleton { constraint.active = !constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true)); if (!constraint.active) return; - Object[] constrained = constraint.bones.items; - int boneCount = constraint.bones.size; - for (int i = 0; i < boneCount; i++) - sortBone((Bone)constrained[i]); + Object[] nodes = constraint.nodes.items; + int nodeCount = constraint.nodes.size; + for (int i = 0; i < nodeCount; i++) { + Node node = (Node)nodes[i]; + if (node.parentBone != null) sortBone(node.parentBone); + for (Bone bone : node.bones) + sortBone(bone); + } updateCache.add(constraint); - for (int i = 0; i < boneCount; i++) - sortReset(((Bone)constrained[i]).children); - for (int i = 0; i < boneCount; i++) - ((Bone)constrained[i]).sorted = true; + for (int i = 0; i < nodeCount; i++) { + Node node = (Node)nodes[i]; + if (node.parentBone != null) sortReset(node.parentBone.children); + for (Bone bone : node.bones) + sortReset(bone.children); + } + for (int i = 0; i < nodeCount; i++) { + Node node = (Node)nodes[i]; + if (node.parentBone != null) node.parentBone.sorted = true; + for (Bone bone : node.bones) + bone.sorted = true; + } } private void sortBone (Bone bone) { @@ -435,51 +448,20 @@ public class Skeleton { ((Bone)bones[i]).setToSetupPose(); Object[] ikConstraints = this.ikConstraints.items; - for (int i = 0, n = this.ikConstraints.size; i < n; i++) { - IkConstraint constraint = (IkConstraint)ikConstraints[i]; - constraint.mix = constraint.data.mix; - constraint.softness = constraint.data.softness; - constraint.bendDirection = constraint.data.bendDirection; - constraint.compress = constraint.data.compress; - constraint.stretch = constraint.data.stretch; - } + for (int i = 0, n = this.ikConstraints.size; i < n; i++) + ((IkConstraint)ikConstraints[i]).setToSetupPose(); Object[] transformConstraints = this.transformConstraints.items; - for (int i = 0, n = this.transformConstraints.size; i < n; i++) { - TransformConstraint constraint = (TransformConstraint)transformConstraints[i]; - TransformConstraintData data = constraint.data; - constraint.mixRotate = data.mixRotate; - constraint.mixX = data.mixX; - constraint.mixY = data.mixY; - constraint.mixScaleX = data.mixScaleX; - constraint.mixScaleY = data.mixScaleY; - constraint.mixShearY = data.mixShearY; - } + for (int i = 0, n = this.transformConstraints.size; i < n; i++) + ((TransformConstraint)transformConstraints[i]).setToSetupPose(); Object[] pathConstraints = this.pathConstraints.items; - for (int i = 0, n = this.pathConstraints.size; i < n; i++) { - PathConstraint constraint = (PathConstraint)pathConstraints[i]; - PathConstraintData data = constraint.data; - constraint.position = data.position; - constraint.spacing = data.spacing; - constraint.mixRotate = data.mixRotate; - constraint.mixX = data.mixX; - constraint.mixY = data.mixY; - } + for (int i = 0, n = this.pathConstraints.size; i < n; i++) + ((PathConstraint)pathConstraints[i]).setToSetupPose(); Object[] physicsConstraints = this.physicsConstraints.items; - for (int i = 0, n = this.physicsConstraints.size; i < n; i++) { - PhysicsConstraint constraint = (PhysicsConstraint)physicsConstraints[i]; - PhysicsConstraintData data = constraint.data; - constraint.mix = data.mix; - constraint.friction = data.friction; - constraint.gravity = data.gravity; - constraint.wind = data.wind; - constraint.stiffness = data.stiffness; - constraint.damping = data.damping; - constraint.rope = data.rope; - constraint.stretch = data.stretch; - } + for (int i = 0, n = this.physicsConstraints.size; i < n; i++) + ((PhysicsConstraint)physicsConstraints[i]).setToSetupPose(); } /** Sets the slots and draw order to their setup pose values. */ diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java index 8a866e70e..dd3c5dff3 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java @@ -80,6 +80,16 @@ public class TransformConstraint implements Updatable { mixShearY = constraint.mixShearY; } + public void setToSetupPose () { + TransformConstraintData data = this.data; + mixRotate = data.mixRotate; + mixX = data.mixX; + mixY = data.mixY; + mixScaleX = data.mixScaleX; + mixScaleY = data.mixScaleY; + mixShearY = data.mixShearY; + } + /** Applies the constraint to the constrained bones. */ public void update () { if (mixRotate == 0 && mixX == 0 && mixY == 0 && mixScaleX == 0 && mixScaleX == 0 && mixShearY == 0) return;