[libgdx] Added global physics timelines.

This commit is contained in:
Nathan Sweet 2023-11-12 19:46:41 -04:00
parent c2906998ad
commit 7f89281d57
4 changed files with 216 additions and 62 deletions

View File

@ -460,6 +460,20 @@ public class Animation {
return current + (value - current) * alpha;
}
public float getAbsoluteValue (float time, float alpha, MixBlend blend, float current, float setup, float value) {
if (time < frames[0]) {
switch (blend) {
case setup:
return setup;
case first:
return current + (setup - current) * alpha;
}
return current;
}
if (blend == MixBlend.setup) return setup + (value - setup) * alpha;
return current + (value - current) * alpha;
}
public float getScaleValue (float time, float alpha, MixBlend blend, MixDirection direction, float current, float setup) {
float[] frames = this.frames;
if (time < frames[0]) {
@ -2242,20 +2256,48 @@ public class Animation {
}
}
/** The base class for {@link PhysicsConstraint} timelines. */
/** The base class for most {@link PhysicsConstraint} timelines. */
static public abstract class PhysicsConstraintTimeline extends CurveTimeline1 {
final int constraintIndex;
/** @param physicsConstraintIndex -1 for all physics constraints in the skeleton. */
public PhysicsConstraintTimeline (int frameCount, int bezierCount, int physicsConstraintIndex, Property property) {
super(frameCount, bezierCount, property.ordinal() + "|" + physicsConstraintIndex);
constraintIndex = physicsConstraintIndex;
}
/** The index of the physics constraint in {@link Skeleton#getPhysicsConstraints()} that will be changed when this timeline
* is applied. */
* is applied, or -1 if all physics constraints in the skeleton will be changed. */
public int getPhysicsConstraintIndex () {
return constraintIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
PhysicsConstraint constraint;
if (constraintIndex == -1) {
float value = time >= frames[0] ? getCurveValue(time) : 0;
Object[] constraints = skeleton.physicsConstraints.items;
for (int i = 0, n = skeleton.physicsConstraints.size; i < n; i++) {
constraint = (PhysicsConstraint)constraints[i];
if (constraint.active && global(constraint.data))
set(constraint, getAbsoluteValue(time, alpha, blend, get(constraint), setup(constraint), value));
}
} else {
constraint = skeleton.physicsConstraints.get(constraintIndex);
if (constraint.active) set(constraint, getAbsoluteValue(time, alpha, blend, get(constraint), setup(constraint)));
}
}
abstract protected float setup (PhysicsConstraint constraint);
abstract protected float get (PhysicsConstraint constraint);
abstract protected void set (PhysicsConstraint constraint, float value);
abstract protected boolean global (PhysicsConstraintData constraint);
}
/** Changes a physics constraint's {@link PhysicsConstraint#getInertia()}. */
@ -2264,12 +2306,20 @@ public class Animation {
super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintInertia);
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
protected float setup (PhysicsConstraint constraint) {
return constraint.data.inertia;
}
PhysicsConstraint constraint = skeleton.physicsConstraints.get(constraintIndex);
if (constraint.active)
constraint.inertia = getAbsoluteValue(time, alpha, blend, constraint.inertia, constraint.data.inertia);
protected float get (PhysicsConstraint constraint) {
return constraint.inertia;
}
protected void set (PhysicsConstraint constraint, float value) {
constraint.inertia = value;
}
protected boolean global (PhysicsConstraintData constraint) {
return constraint.inertiaGlobal;
}
}
@ -2279,12 +2329,20 @@ public class Animation {
super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintStrength);
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
protected float setup (PhysicsConstraint constraint) {
return constraint.data.strength;
}
PhysicsConstraint constraint = skeleton.physicsConstraints.get(constraintIndex);
if (constraint.active)
constraint.strength = getAbsoluteValue(time, alpha, blend, constraint.strength, constraint.data.strength);
protected float get (PhysicsConstraint constraint) {
return constraint.strength;
}
protected void set (PhysicsConstraint constraint, float value) {
constraint.strength = value;
}
protected boolean global (PhysicsConstraintData constraint) {
return constraint.strengthGlobal;
}
}
@ -2294,12 +2352,20 @@ public class Animation {
super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintDamping);
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
protected float setup (PhysicsConstraint constraint) {
return constraint.data.damping;
}
PhysicsConstraint constraint = skeleton.physicsConstraints.get(constraintIndex);
if (constraint.active)
constraint.damping = getAbsoluteValue(time, alpha, blend, constraint.damping, constraint.data.damping);
protected float get (PhysicsConstraint constraint) {
return constraint.damping;
}
protected void set (PhysicsConstraint constraint, float value) {
constraint.damping = value;
}
protected boolean global (PhysicsConstraintData constraint) {
return constraint.dampingGlobal;
}
}
@ -2309,14 +2375,20 @@ public class Animation {
super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintMass);
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
protected float setup (PhysicsConstraint constraint) {
return 1 / constraint.data.massInverse;
}
PhysicsConstraint constraint = skeleton.physicsConstraints.get(constraintIndex);
if (constraint.active) {
constraint.massInverse = 1
/ getAbsoluteValue(time, alpha, blend, 1 / constraint.massInverse, 1 / constraint.data.massInverse);
}
protected float get (PhysicsConstraint constraint) {
return 1 / constraint.massInverse;
}
protected void set (PhysicsConstraint constraint, float value) {
constraint.massInverse = 1 / value;
}
protected boolean global (PhysicsConstraintData constraint) {
return constraint.massGlobal;
}
}
@ -2326,11 +2398,20 @@ public class Animation {
super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintWind);
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
protected float setup (PhysicsConstraint constraint) {
return constraint.data.wind;
}
PhysicsConstraint constraint = skeleton.physicsConstraints.get(constraintIndex);
if (constraint.active) constraint.wind = getAbsoluteValue(time, alpha, blend, constraint.wind, constraint.data.wind);
protected float get (PhysicsConstraint constraint) {
return constraint.wind;
}
protected void set (PhysicsConstraint constraint, float value) {
constraint.wind = value;
}
protected boolean global (PhysicsConstraintData constraint) {
return constraint.windGlobal;
}
}
@ -2340,12 +2421,20 @@ public class Animation {
super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintGravity);
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
protected float setup (PhysicsConstraint constraint) {
return constraint.data.gravity;
}
PhysicsConstraint constraint = skeleton.physicsConstraints.get(constraintIndex);
if (constraint.active)
constraint.gravity = getAbsoluteValue(time, alpha, blend, constraint.gravity, constraint.data.gravity);
protected float get (PhysicsConstraint constraint) {
return constraint.gravity;
}
protected void set (PhysicsConstraint constraint, float value) {
constraint.gravity = value;
}
protected boolean global (PhysicsConstraintData constraint) {
return constraint.gravityGlobal;
}
}
@ -2355,11 +2444,20 @@ public class Animation {
super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintMix);
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction) {
protected float setup (PhysicsConstraint constraint) {
return constraint.data.mix;
}
PhysicsConstraint constraint = skeleton.physicsConstraints.get(constraintIndex);
if (constraint.active) constraint.mix = getAbsoluteValue(time, alpha, blend, constraint.mix, constraint.data.mix);
protected float get (PhysicsConstraint constraint) {
return constraint.mix;
}
protected void set (PhysicsConstraint constraint, float value) {
constraint.mix = value;
}
protected boolean global (PhysicsConstraintData constraint) {
return constraint.mixGlobal;
}
}
@ -2375,8 +2473,8 @@ public class Animation {
constraintIndex = physicsConstraintIndex;
}
/** The index of the physics constraint in {@link Skeleton#getPhysicsConstraints()} that will be reset by this timeline, or
* -1 if all physics constraints in the skeleton will be reset. */
/** The index of the physics constraint in {@link Skeleton#getPhysicsConstraints()} that will be reset when this timeline is
* applied, or -1 if all physics constraints in the skeleton will be reset. */
public int getPhysicsConstraintIndex () {
return constraintIndex;
}

View File

@ -36,6 +36,7 @@ public class PhysicsConstraintData extends ConstraintData {
BoneData bone;
float x, y, rotate, scaleX, shearX;
float step, inertia, strength, damping, massInverse, wind, gravity, mix;
boolean inertiaGlobal, strengthGlobal, dampingGlobal, massGlobal, windGlobal, gravityGlobal, mixGlobal;
public PhysicsConstraintData (String name) {
super(name);
@ -154,4 +155,60 @@ public class PhysicsConstraintData extends ConstraintData {
public void setMix (float mix) {
this.mix = mix;
}
public boolean getInertiaGlobal () {
return inertiaGlobal;
}
public void setInertiaGlobal (boolean inertiaGlobal) {
this.inertiaGlobal = inertiaGlobal;
}
public boolean getStrengthGlobal () {
return strengthGlobal;
}
public void setStrengthGlobal (boolean strengthGlobal) {
this.strengthGlobal = strengthGlobal;
}
public boolean getDampingGlobal () {
return dampingGlobal;
}
public void setDampingGlobal (boolean dampingGlobal) {
this.dampingGlobal = dampingGlobal;
}
public boolean getMassGlobal () {
return massGlobal;
}
public void setMassGlobal (boolean massGlobal) {
this.massGlobal = massGlobal;
}
public boolean getWindGlobal () {
return windGlobal;
}
public void setWindGlobal (boolean windGlobal) {
this.windGlobal = windGlobal;
}
public boolean getGravityGlobal () {
return gravityGlobal;
}
public void setGravityGlobal (boolean gravityGlobal) {
this.gravityGlobal = gravityGlobal;
}
public boolean getMixGlobal () {
return mixGlobal;
}
public void setMixGlobal (boolean mixGlobal) {
this.mixGlobal = mixGlobal;
}
}

View File

@ -328,6 +328,14 @@ public class SkeletonBinary extends SkeletonLoader {
data.wind = input.readFloat();
data.gravity = input.readFloat();
data.mix = input.readFloat();
flags = input.read();
if ((flags & 1) != 0) data.inertiaGlobal = true;
if ((flags & 2) != 0) data.strengthGlobal = true;
if ((flags & 4) != 0) data.dampingGlobal = true;
if ((flags & 8) != 0) data.massGlobal = true;
if ((flags & 16) != 0) data.windGlobal = true;
if ((flags & 32) != 0) data.gravityGlobal = true;
if ((flags & 64) != 0) data.mixGlobal = true;
o[i] = data;
}
@ -959,7 +967,7 @@ public class SkeletonBinary extends SkeletonLoader {
// Physics timelines.
for (int i = 0, n = input.readInt(true); i < n; i++) {
int index = input.readInt(true);
int index = input.readInt(true) - 1;
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
int type = input.readByte(), frameCount = input.readInt(true);
if (type == PHYSICS_RESET) {
@ -1066,15 +1074,6 @@ public class SkeletonBinary extends SkeletonLoader {
}
}
// Physics constraint reset all timeline.
int resetCount = input.readInt(true);
if (resetCount > 0) {
PhysicsConstraintResetTimeline timeline = new PhysicsConstraintResetTimeline(resetCount, -1);
for (int i = 0; i < resetCount; i++)
timeline.setFrame(i, input.readFloat());
timelines.add(timeline);
}
// Draw order timeline.
int drawOrderCount = input.readInt(true);
if (drawOrderCount > 0) {

View File

@ -313,6 +313,13 @@ public class SkeletonJson extends SkeletonLoader {
data.wind = constraintMap.getFloat("wind", 0);
data.gravity = constraintMap.getFloat("gravity", 0);
data.mix = constraintMap.getFloat("mix", 1);
data.inertiaGlobal = constraintMap.getBoolean("inertiaGlobal", false);
data.strengthGlobal = constraintMap.getBoolean("strengthGlobal", false);
data.dampingGlobal = constraintMap.getBoolean("dampingGlobal", false);
data.massGlobal = constraintMap.getBoolean("massGlobal", false);
data.windGlobal = constraintMap.getBoolean("windGlobal", false);
data.gravityGlobal = constraintMap.getBoolean("gravityGlobal", false);
data.mixGlobal = constraintMap.getBoolean("mixGlobal", false);
skeletonData.physicsConstraints.add(data);
}
@ -924,9 +931,12 @@ public class SkeletonJson extends SkeletonLoader {
// Physics constraint timelines.
for (JsonValue constraintMap = map.getChild("physics"); constraintMap != null; constraintMap = constraintMap.next) {
PhysicsConstraintData constraint = skeletonData.findPhysicsConstraint(constraintMap.name);
if (constraint == null) throw new SerializationException("Physics constraint not found: " + constraintMap.name);
int index = skeletonData.physicsConstraints.indexOf(constraint, true);
int index = -1;
if (!constraintMap.name.isEmpty()) {
PhysicsConstraintData constraint = skeletonData.findPhysicsConstraint(constraintMap.name);
if (constraint == null) throw new SerializationException("Physics constraint not found: " + constraintMap.name);
index = skeletonData.physicsConstraints.indexOf(constraint, true);
}
for (JsonValue timelineMap = constraintMap.child; timelineMap != null; timelineMap = timelineMap.next) {
JsonValue keyMap = timelineMap.child;
if (keyMap == null) continue;
@ -1032,16 +1042,6 @@ public class SkeletonJson extends SkeletonLoader {
}
}
// Physics constraint reset all timeline.
JsonValue resetMap = map.get("physicsReset");
if (resetMap != null) {
PhysicsConstraintResetTimeline timeline = new PhysicsConstraintResetTimeline(resetMap.size, -1);
int frame = 0;
for (JsonValue keyMap = resetMap.child; keyMap != null; keyMap = keyMap.next, frame++)
timeline.setFrame(frame, keyMap.getFloat("time", 0));
timelines.add(timeline);
}
// Draw order timeline.
JsonValue drawOrderMap = map.get("drawOrder");
if (drawOrderMap != null) {