mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-09 08:38:43 +08:00
[libgdx] Added a Physics enum to updateWorldTransform and Updateable#update to control how physics and other non-deterministic updates are applied.
This commit is contained in:
parent
9678808aaf
commit
4116af02fa
@ -34,6 +34,7 @@ import com.badlogic.gdx.utils.Null;
|
||||
|
||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.attachments.AttachmentLoader;
|
||||
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
||||
import com.esotericsoftware.spine.attachments.ClippingAttachment;
|
||||
@ -83,7 +84,7 @@ public class BonePlotting {
|
||||
float time = 0;
|
||||
while (time < animation.getDuration()) {
|
||||
animation.apply(skeleton, time, time, false, null, 1, MixBlend.first, MixDirection.in);
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
System.out.println(animation.getName() + "," //
|
||||
+ bone.getWorldX() + "," + bone.getWorldY() + "," + bone.getWorldRotationX());
|
||||
|
||||
@ -54,6 +54,7 @@ import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||
import com.esotericsoftware.spine.attachments.Sequence;
|
||||
@ -104,7 +105,7 @@ public class Box2DExample extends ApplicationAdapter {
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
skeleton.x = -32;
|
||||
skeleton.y = 1;
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
// See Box2DTest in libgdx for more detailed information about Box2D setup.
|
||||
camera = new OrthographicCamera(48, 32);
|
||||
@ -150,7 +151,7 @@ public class Box2DExample extends ApplicationAdapter {
|
||||
|
||||
animation.apply(skeleton, time, time, true, events, 1, MixBlend.first, MixDirection.in);
|
||||
skeleton.x += 8 * delta;
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
skeletonRenderer.draw(batch, skeleton);
|
||||
|
||||
batch.end();
|
||||
|
||||
@ -42,6 +42,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||
|
||||
/** Demonstrates rendering an animation to a frame buffer (FBO) and then rendering the FBO to the screen. */
|
||||
@ -75,7 +76,7 @@ public class FboTest extends ApplicationAdapter {
|
||||
// Create a skeleton instance, set the position of its root bone, and update its world transform.
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
skeleton.setPosition(250, 20);
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
// Create an FBO and a texture region with Y flipped.
|
||||
fbo = new FrameBuffer(Pixmap.Format.RGBA8888, 512, 512, false);
|
||||
|
||||
@ -38,6 +38,7 @@ import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.Vector3;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||
|
||||
/** Demonstrates how to let the target bone of an IK constraint follow the mouse or touch position, which in turn repositions part
|
||||
@ -97,7 +98,7 @@ public class IKTest extends ApplicationAdapter {
|
||||
// later.
|
||||
state.update(Gdx.graphics.getDeltaTime());
|
||||
state.apply(skeleton);
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
// Position the "crosshair" bone at the mouse
|
||||
// location. We do this before calling
|
||||
@ -122,7 +123,7 @@ public class IKTest extends ApplicationAdapter {
|
||||
// Calculate final world transform with the
|
||||
// crosshair bone set to the mouse cursor
|
||||
// position.
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
// Clear the screen, update the camera and
|
||||
// render the skeleton.
|
||||
|
||||
@ -37,6 +37,8 @@ import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
/** Demonstrates creating and configuring a new skin at runtime. */
|
||||
public class MixAndMatchTest extends ApplicationAdapter {
|
||||
OrthographicCamera camera;
|
||||
@ -92,7 +94,7 @@ public class MixAndMatchTest extends ApplicationAdapter {
|
||||
ScreenUtils.clear(0, 0, 0, 0);
|
||||
|
||||
state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT.
|
||||
skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT.
|
||||
skeleton.updateWorldTransform(Physics.update); // Uses the bones' local SRT to compute their world SRT.
|
||||
|
||||
// Configure the camera, and PolygonSpriteBatch
|
||||
camera.update();
|
||||
|
||||
@ -58,6 +58,7 @@ import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
/** Demonstrates simplistic usage of lighting with normal maps.
|
||||
* <p>
|
||||
@ -110,7 +111,7 @@ public class NormalMapTest extends ApplicationAdapter {
|
||||
skeleton = new Skeleton(skeleton);
|
||||
skeleton.setX(ui.prefs.getFloat("x", Gdx.graphics.getWidth() / 2));
|
||||
skeleton.setY(ui.prefs.getFloat("y", Gdx.graphics.getHeight() / 4));
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
Gdx.input.setInputProcessor(new InputMultiplexer(ui.stage, new InputAdapter() {
|
||||
public boolean touchDown (int screenX, int screenY, int pointer, int button) {
|
||||
@ -136,7 +137,7 @@ public class NormalMapTest extends ApplicationAdapter {
|
||||
float lastTime = time;
|
||||
time += Gdx.graphics.getDeltaTime();
|
||||
if (animation != null) animation.apply(skeleton, lastTime, time, true, null, 1, MixBlend.first, MixDirection.in);
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
lightPosition.x = Gdx.input.getX();
|
||||
lightPosition.y = (Gdx.graphics.getHeight() - 1 - Gdx.input.getY());
|
||||
|
||||
@ -48,6 +48,7 @@ import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||
|
||||
/** Demonstrates rendering an animation to a frame buffer (FBO) and then writing each frame as a PNG. */
|
||||
@ -81,7 +82,7 @@ public class PngExportTest extends ApplicationAdapter {
|
||||
// Create a skeleton instance, set the position of its root bone, and update its world transform.
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
skeleton.setPosition(250, 20);
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
// Create an FBO and a texture region.
|
||||
fbo = new FrameBuffer(Pixmap.Format.RGBA8888, 512, 512, false);
|
||||
@ -104,7 +105,7 @@ public class PngExportTest extends ApplicationAdapter {
|
||||
int frame = 1;
|
||||
while (time < animation.getDuration()) {
|
||||
animation.apply(skeleton, time, time, false, null, 1, MixBlend.first, MixDirection.in);
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
// Render the skeleton to the FBO.
|
||||
ScreenUtils.clear(0, 0, 0, 0);
|
||||
|
||||
@ -36,6 +36,7 @@ import com.badlogic.gdx.graphics.GL20;
|
||||
import com.badlogic.gdx.graphics.OrthographicCamera;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||
|
||||
/** Demonstrates loading, animating, and rendering a skeleton.
|
||||
@ -86,7 +87,7 @@ public class SimpleTest1 extends ApplicationAdapter {
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT.
|
||||
skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT.
|
||||
skeleton.updateWorldTransform(Physics.update); // Uses the bones' local SRT to compute their world SRT.
|
||||
|
||||
// Configure the camera, SpriteBatch, and SkeletonRendererDebug.
|
||||
camera.update();
|
||||
|
||||
@ -41,6 +41,7 @@ import com.badlogic.gdx.math.Vector3;
|
||||
|
||||
import com.esotericsoftware.spine.AnimationState.AnimationStateListener;
|
||||
import com.esotericsoftware.spine.AnimationState.TrackEntry;
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
||||
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||
|
||||
@ -147,7 +148,7 @@ public class SimpleTest2 extends ApplicationAdapter {
|
||||
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
if (state.apply(skeleton)) // Poses skeleton using current animations. This sets the bones' local SRT.
|
||||
skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT.
|
||||
skeleton.updateWorldTransform(Physics.update); // Uses the bones' local SRT to compute their world SRT.
|
||||
|
||||
// Configure the camera, SpriteBatch, and SkeletonRendererDebug.
|
||||
camera.update();
|
||||
|
||||
@ -37,6 +37,8 @@ import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
/** Demonstrates applying multiple animations at once using {@link AnimationState} tracks. */
|
||||
public class SimpleTest3 extends ApplicationAdapter {
|
||||
OrthographicCamera camera;
|
||||
@ -84,7 +86,7 @@ public class SimpleTest3 extends ApplicationAdapter {
|
||||
ScreenUtils.clear(0, 0, 0, 0);
|
||||
|
||||
if (state.apply(skeleton)) // Poses skeleton using current animations. This sets the bones' local SRT.
|
||||
skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT.
|
||||
skeleton.updateWorldTransform(Physics.update); // Uses the bones' local SRT to compute their world SRT.
|
||||
|
||||
// Configure the camera, SpriteBatch, and SkeletonRendererDebug.
|
||||
camera.update();
|
||||
|
||||
@ -38,6 +38,7 @@ import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.utils.SkeletonDataLoader;
|
||||
import com.esotericsoftware.spine.utils.SkeletonDataLoader.SkeletonDataParameter;
|
||||
|
||||
@ -102,7 +103,7 @@ public class SkeletonAssetManagerTest extends ApplicationAdapter {
|
||||
state.update(Gdx.graphics.getDeltaTime()); // Update the animation time.
|
||||
|
||||
state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT.
|
||||
skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT.
|
||||
skeleton.updateWorldTransform(Physics.update); // Uses the bones' local SRT to compute their world SRT.
|
||||
|
||||
// Configure the camera, SpriteBatch, and SkeletonRendererDebug.
|
||||
camera.update();
|
||||
|
||||
@ -37,6 +37,7 @@ import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
|
||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.attachments.SkeletonAttachment;
|
||||
|
||||
/** Demonstrates using {@link SkeletonAttachment} to use an entire skeleton as an attachment. */
|
||||
@ -93,11 +94,11 @@ public class SkeletonAttachmentTest extends ApplicationAdapter {
|
||||
public void render () {
|
||||
spineboyState.update(Gdx.graphics.getDeltaTime());
|
||||
spineboyState.apply(spineboy);
|
||||
spineboy.updateWorldTransform();
|
||||
spineboy.updateWorldTransform(Physics.update);
|
||||
|
||||
goblinState.update(Gdx.graphics.getDeltaTime());
|
||||
goblinState.apply(goblin);
|
||||
goblin.updateWorldTransform(attachmentBone);
|
||||
goblin.updateWorldTransform(Physics.update, attachmentBone);
|
||||
|
||||
ScreenUtils.clear(0, 0, 0, 0);
|
||||
|
||||
|
||||
@ -39,6 +39,8 @@ import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||
import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
/** Boilerplate for basic skeleton rendering, used for various testing. */
|
||||
public class TestHarness extends ApplicationAdapter {
|
||||
// static String JSON = "coin/coin-pro.json";
|
||||
@ -79,7 +81,7 @@ public class TestHarness extends ApplicationAdapter {
|
||||
// state.setAnimation(0, "rotate", false);
|
||||
state.update(0);
|
||||
state.apply(skeleton);
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
}
|
||||
|
||||
public void render () {
|
||||
@ -87,7 +89,7 @@ public class TestHarness extends ApplicationAdapter {
|
||||
state.update(0.25f); // Update the animation time.
|
||||
}
|
||||
state.apply(skeleton); // Poses skeleton using current animations. This sets the bones' local SRT.
|
||||
skeleton.updateWorldTransform(); // Uses the bones' local SRT to compute their world SRT.
|
||||
skeleton.updateWorldTransform(Physics.update); // Uses the bones' local SRT to compute their world SRT.
|
||||
|
||||
ScreenUtils.clear(0, 0, 0, 0);
|
||||
|
||||
|
||||
@ -39,6 +39,7 @@ import com.badlogic.gdx.utils.ScreenUtils;
|
||||
|
||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
/** Demonstrates using the timeline API. See {@link SimpleTest1} for a higher level API using {@link AnimationState}.
|
||||
* <p>
|
||||
@ -79,7 +80,7 @@ public class TimelineApiTest extends ApplicationAdapter {
|
||||
jumpAnimation = skeletonData.findAnimation("jump");
|
||||
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
skeleton.setPosition(-50, 20);
|
||||
}
|
||||
|
||||
@ -127,7 +128,7 @@ public class TimelineApiTest extends ApplicationAdapter {
|
||||
walkAnimation.apply(skeleton, time, time, true, events, 1, MixBlend.first, MixDirection.in);
|
||||
}
|
||||
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
batch.begin();
|
||||
renderer.draw(batch, skeleton);
|
||||
|
||||
@ -38,6 +38,7 @@ import com.badlogic.gdx.utils.Array;
|
||||
import com.badlogic.gdx.utils.Null;
|
||||
|
||||
import com.esotericsoftware.spine.BoneData.TransformMode;
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
/** Stores a bone's current pose.
|
||||
* <p>
|
||||
@ -82,7 +83,7 @@ public class Bone implements Updatable {
|
||||
}
|
||||
|
||||
/** Computes the world transform using the parent bone and this bone's local applied transform. */
|
||||
public void update () {
|
||||
public void update (Physics physics) {
|
||||
updateWorldTransform(ax, ay, arotation, ascaleX, ascaleY, ashearX, ashearY);
|
||||
}
|
||||
|
||||
@ -618,8 +619,8 @@ public class Bone implements Updatable {
|
||||
|
||||
/** Rotates the world transform the specified amount.
|
||||
* <p>
|
||||
* After changes are made to the world transform, {@link #updateAppliedTransform()} should be called and {@link #update()} will
|
||||
* need to be called on any child bones, recursively. */
|
||||
* After changes are made to the world transform, {@link #updateAppliedTransform()} should be called and
|
||||
* {@link #update(Physics)} will need to be called on any child bones, recursively. */
|
||||
public void rotateWorld (float degrees) {
|
||||
degrees *= degRad;
|
||||
float sin = sin(degrees), cos = cos(degrees);
|
||||
|
||||
@ -32,6 +32,8 @@ package com.esotericsoftware.spine;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.utils.Null;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
/** Stores the setup pose for a {@link Bone}. */
|
||||
public class BoneData {
|
||||
final int index;
|
||||
@ -175,8 +177,8 @@ public class BoneData {
|
||||
this.transformMode = transformMode;
|
||||
}
|
||||
|
||||
/** When true, {@link Skeleton#updateWorldTransform()} only updates this bone if the {@link Skeleton#getSkin()} contains this
|
||||
* bone.
|
||||
/** When true, {@link Skeleton#updateWorldTransform(Physics)} only updates this bone if the {@link Skeleton#getSkin()} contains
|
||||
* this bone.
|
||||
* <p>
|
||||
* See {@link Skin#getBones()}. */
|
||||
public boolean getSkinRequired () {
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
/** The base class for all constraint datas. */
|
||||
abstract public class ConstraintData {
|
||||
final String name;
|
||||
@ -46,7 +48,7 @@ abstract public class ConstraintData {
|
||||
}
|
||||
|
||||
/** The ordinal of this constraint for the order a skeleton's constraints will be applied by
|
||||
* {@link Skeleton#updateWorldTransform()}. */
|
||||
* {@link Skeleton#updateWorldTransform(Physics)}. */
|
||||
public int getOrder () {
|
||||
return order;
|
||||
}
|
||||
@ -55,8 +57,8 @@ abstract public class ConstraintData {
|
||||
this.order = order;
|
||||
}
|
||||
|
||||
/** When true, {@link Skeleton#updateWorldTransform()} only updates this constraint if the {@link Skeleton#getSkin()} contains
|
||||
* this constraint.
|
||||
/** When true, {@link Skeleton#updateWorldTransform(Physics)} only updates this constraint if the {@link Skeleton#getSkin()}
|
||||
* contains this constraint.
|
||||
* <p>
|
||||
* See {@link Skin#getConstraints()}. */
|
||||
public boolean getSkinRequired () {
|
||||
|
||||
@ -33,6 +33,8 @@ import static com.esotericsoftware.spine.utils.SpineUtils.*;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
/** Stores the current pose for an IK constraint. An IK constraint adjusts the rotation of 1 or 2 constrained bones so the tip of
|
||||
* the last bone is as close to the target bone as possible.
|
||||
* <p>
|
||||
@ -87,7 +89,7 @@ public class IkConstraint implements Updatable {
|
||||
}
|
||||
|
||||
/** Applies the constraint to the constrained bones. */
|
||||
public void update () {
|
||||
public void update (Physics physics) {
|
||||
if (mix == 0) return;
|
||||
Bone target = this.target;
|
||||
Object[] bones = this.bones.items;
|
||||
|
||||
@ -39,6 +39,7 @@ import com.badlogic.gdx.utils.FloatArray;
|
||||
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
|
||||
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
|
||||
import com.esotericsoftware.spine.PathConstraintData.SpacingMode;
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.attachments.Attachment;
|
||||
import com.esotericsoftware.spine.attachments.PathAttachment;
|
||||
|
||||
@ -101,7 +102,7 @@ public class PathConstraint implements Updatable {
|
||||
}
|
||||
|
||||
/** Applies the constraint to the constrained bones. */
|
||||
public void update () {
|
||||
public void update (Physics physics) {
|
||||
Attachment attachment = target.attachment;
|
||||
if (!(attachment instanceof PathAttachment)) return;
|
||||
|
||||
|
||||
@ -29,14 +29,23 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
import static com.badlogic.gdx.math.Interpolation.*;
|
||||
import static com.esotericsoftware.spine.utils.SpineUtils.*;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
// BOZO - Physics steps/something in metrics view.
|
||||
|
||||
/** Stores the current pose for a physics constraint. A physics constraint applies physics to bones.
|
||||
* <p>
|
||||
* See <a href="http://esotericsoftware.com/spine-physics-constraints">Physics constraints</a> in the Spine User Guide. */
|
||||
public class PhysicsConstraint implements Updatable {
|
||||
final PhysicsConstraintData data;
|
||||
final Array<Bone> bones;
|
||||
State[] states = {};
|
||||
float mix;
|
||||
|
||||
boolean active;
|
||||
@ -66,19 +75,158 @@ public class PhysicsConstraint implements Updatable {
|
||||
mix = constraint.mix;
|
||||
}
|
||||
|
||||
public void setToSetupPose () {
|
||||
/** Caches information about bones. Must be called if {@link PathConstraintData#getBones()} is modified. */
|
||||
public void updateBones () {
|
||||
int count = 0;
|
||||
if (data.x) count = 1;
|
||||
if (data.y) count++;
|
||||
if (data.rotate) count++;
|
||||
if (data.scaleX) count++;
|
||||
if (data.shearX) count++;
|
||||
count *= bones.size * 2;
|
||||
if (states.length != count) {
|
||||
states = new State[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
states[i] = new State();
|
||||
}
|
||||
}
|
||||
|
||||
public void reset () {
|
||||
remaining = 0;
|
||||
lastTime = skeleton.time;
|
||||
|
||||
for (int i = 0, n = states.length; i < n; i++) {
|
||||
State state = states[i];
|
||||
state.last = false;
|
||||
state.offset = 0;
|
||||
state.velocity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void setToSetupPose () {
|
||||
reset();
|
||||
|
||||
PhysicsConstraintData data = this.data;
|
||||
mix = data.mix;
|
||||
}
|
||||
|
||||
/** Applies the constraint to the constrained bones. */
|
||||
public void update () {
|
||||
public void update (Physics physics) {
|
||||
if (mix == 0) return;
|
||||
|
||||
// BOZO
|
||||
data.rotate = true; // BOZO - Remove.
|
||||
updateBones(); // BOZO - Remove.
|
||||
|
||||
Object[] bones = this.bones.items;
|
||||
int boneCount = this.bones.size;
|
||||
|
||||
switch (physics) {
|
||||
case none:
|
||||
return;
|
||||
case reset:
|
||||
reset();
|
||||
// Fall through.
|
||||
case update:
|
||||
for (int i = 0; i < boneCount; i++) {
|
||||
Bone bone = (Bone)bones[i];
|
||||
if (data.rotate) {
|
||||
Vector2 tip = bone.localToWorld(new Vector2(bone.data.length, 0));
|
||||
State state = states[i];
|
||||
if (!state.last)
|
||||
state.last = true;
|
||||
else if (state.x != bone.worldX || state.y != bone.worldY) {
|
||||
float angleToOldTip = new Vector2(state.tipx, state.tipy).sub(bone.worldX, bone.worldY).angleDeg()
|
||||
+ state.offset - bone.getWorldRotationX();
|
||||
angleToOldTip -= (16384 - (int)(16384.499999999996 - angleToOldTip / 360)) * 360;
|
||||
state.offset = linear.apply(0, angleToOldTip, data.inertia);
|
||||
// if (angleToOldTip > 0.0001f || angleToOldTip < -0.0001f) //
|
||||
// System.out.println(angleToOldTip);
|
||||
// if (applyShear) {
|
||||
// if (rotationOffset > 0)
|
||||
// rotationOffset = Math.max(0, rotationOffset - shearOffset);
|
||||
// else
|
||||
// rotationOffset = Math.min(0, rotationOffset - shearOffset);
|
||||
// }
|
||||
}
|
||||
tip = bone.localToWorld(new Vector2(bone.data.length, 0));
|
||||
// if (bone.worldX!=271.64316f)
|
||||
// System.out.println(bone.worldX);
|
||||
if (bone.worldY != 662.5888f) System.out.println(bone.worldY);
|
||||
// System.out.println(bone.worldY);
|
||||
state.x = bone.worldX;
|
||||
state.y = bone.worldY;
|
||||
state.tipx = tip.x;
|
||||
state.tipy = tip.y;
|
||||
}
|
||||
// BOZO - Update physics x, y, scaleX, shearX.
|
||||
}
|
||||
}
|
||||
|
||||
boolean angle = data.rotate || data.scaleX || data.shearX;
|
||||
|
||||
remaining += Math.max(skeleton.time - lastTime, 0);
|
||||
lastTime = skeleton.time;
|
||||
|
||||
float step = 0.016f; // BOZO - Keep fixed step? Make it configurable?
|
||||
float cos = 0, sin = 0;
|
||||
while (remaining >= step) {
|
||||
remaining -= step;
|
||||
|
||||
for (int i = 0; i < boneCount; i++) {
|
||||
Bone bone = (Bone)bones[i];
|
||||
if (angle) {
|
||||
float r = bone.getWorldRotationX() * degRad;
|
||||
cos = (float)Math.cos(r);
|
||||
sin = (float)Math.sin(r);
|
||||
}
|
||||
if (data.rotate) {
|
||||
State state = states[i];
|
||||
// BOZO - Keep length affecting rotation? Calculate world length?
|
||||
float windForce = bone.data.length * 0.5f * (-data.wind * sin - data.gravity * cos);
|
||||
float springForce = state.offset * data.strength;
|
||||
float frictionForce = data.friction * state.velocity;
|
||||
state.velocity += (windForce - springForce - frictionForce) / data.mass;
|
||||
state.offset += state.velocity * step;
|
||||
state.velocity *= data.damping;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mix == 1) {
|
||||
for (int i = 0; i < boneCount; i++) {
|
||||
Bone bone = (Bone)bones[i];
|
||||
if (angle) {
|
||||
float r = bone.getWorldRotationX() * degRad;
|
||||
cos = (float)Math.cos(r);
|
||||
sin = (float)Math.sin(r);
|
||||
}
|
||||
if (data.rotate) {
|
||||
State state = states[i];
|
||||
bone.rotateWorld(state.offset);
|
||||
bone.updateAppliedTransform();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// BOZO - PhysicsConstraint mix.
|
||||
}
|
||||
}
|
||||
|
||||
public void step () {
|
||||
// BOZO - PhysicsConstraint#step.
|
||||
}
|
||||
|
||||
/** The bones that will be modified by this physics constraint. */
|
||||
public Array<Bone> getBones () {
|
||||
return bones;
|
||||
}
|
||||
|
||||
/** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */
|
||||
public float getMix () {
|
||||
return mix;
|
||||
}
|
||||
|
||||
public void setMix (float mix) {
|
||||
this.mix = mix;
|
||||
}
|
||||
|
||||
public boolean isActive () {
|
||||
@ -93,4 +241,9 @@ public class PhysicsConstraint implements Updatable {
|
||||
public String toString () {
|
||||
return data.name;
|
||||
}
|
||||
|
||||
static class State {
|
||||
boolean last;
|
||||
float x, y, tipx, tipy, offset, velocity;
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,9 +36,9 @@ import com.badlogic.gdx.utils.Array;
|
||||
* See <a href="http://esotericsoftware.com/spine-physics-constraints">Physics constraints</a> in the Spine User Guide. */
|
||||
public class PhysicsConstraintData extends ConstraintData {
|
||||
final Array<BoneData> bones = new Array();
|
||||
float speed = 1, mass = 1;
|
||||
float speed = 1, mass = 1; // BOZO - Keep speed?
|
||||
float strength, friction, damping, inertia, wind, gravity, mix;
|
||||
boolean translate, rotate, scale, shear;
|
||||
boolean x, y, rotate, scaleX, shearX;
|
||||
|
||||
public PhysicsConstraintData (String name) {
|
||||
super(name);
|
||||
@ -113,12 +113,20 @@ public class PhysicsConstraintData extends ConstraintData {
|
||||
this.gravity = gravity;
|
||||
}
|
||||
|
||||
public boolean getTranslate () {
|
||||
return translate;
|
||||
public boolean getX () {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setTranslate (boolean translate) {
|
||||
this.translate = translate;
|
||||
public void setX (boolean x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public boolean getY () {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY (boolean y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public boolean getRotate () {
|
||||
@ -129,20 +137,20 @@ public class PhysicsConstraintData extends ConstraintData {
|
||||
this.rotate = rotate;
|
||||
}
|
||||
|
||||
public boolean getScale () {
|
||||
return scale;
|
||||
public boolean getScaleX () {
|
||||
return scaleX;
|
||||
}
|
||||
|
||||
public void setScale (boolean scale) {
|
||||
this.scale = scale;
|
||||
public void setScaleX (boolean scaleX) {
|
||||
this.scaleX = scaleX;
|
||||
}
|
||||
|
||||
public boolean getShear () {
|
||||
return shear;
|
||||
public boolean getShearX () {
|
||||
return shearX;
|
||||
}
|
||||
|
||||
public void setShear (boolean shear) {
|
||||
this.shear = shear;
|
||||
public void setShearX (boolean shearX) {
|
||||
this.shearX = shearX;
|
||||
}
|
||||
|
||||
/** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */
|
||||
|
||||
@ -384,7 +384,7 @@ public class Skeleton {
|
||||
* <p>
|
||||
* See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
|
||||
* Runtimes Guide. */
|
||||
public void updateWorldTransform () {
|
||||
public void updateWorldTransform (Physics physics) {
|
||||
Object[] bones = this.bones.items;
|
||||
for (int i = 0, n = this.bones.size; i < n; i++) {
|
||||
Bone bone = (Bone)bones[i];
|
||||
@ -399,7 +399,7 @@ public class Skeleton {
|
||||
|
||||
Object[] updateCache = this.updateCache.items;
|
||||
for (int i = 0, n = this.updateCache.size; i < n; i++)
|
||||
((Updatable)updateCache[i]).update();
|
||||
((Updatable)updateCache[i]).update(physics);
|
||||
}
|
||||
|
||||
/** Temporarily sets the root bone as a child of the specified bone, then updates the world transform for each bone and applies
|
||||
@ -407,7 +407,7 @@ public class Skeleton {
|
||||
* <p>
|
||||
* See <a href="http://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
|
||||
* Runtimes Guide. */
|
||||
public void updateWorldTransform (Bone parent) {
|
||||
public void updateWorldTransform (Physics physics, Bone parent) {
|
||||
if (parent == null) throw new IllegalArgumentException("parent cannot be null.");
|
||||
|
||||
Object[] bones = this.bones.items;
|
||||
@ -443,7 +443,7 @@ public class Skeleton {
|
||||
Object[] updateCache = this.updateCache.items;
|
||||
for (int i = 0, n = this.updateCache.size; i < n; i++) {
|
||||
Updatable updatable = (Updatable)updateCache[i];
|
||||
if (updatable != rootBone) updatable.update();
|
||||
if (updatable != rootBone) updatable.update(physics);
|
||||
}
|
||||
}
|
||||
|
||||
@ -833,4 +833,19 @@ public class Skeleton {
|
||||
public String toString () {
|
||||
return data.name != null ? data.name : super.toString();
|
||||
}
|
||||
|
||||
/** Determines how physics and other non-deterministic updates are applied. */
|
||||
static public enum Physics {
|
||||
/** Physics are not updated or applied. */
|
||||
none,
|
||||
|
||||
/** Physics are not updated but the pose from physics is applied. */
|
||||
pose,
|
||||
|
||||
/** Physics are updated and the pose from physics is applied. */
|
||||
update,
|
||||
|
||||
/** Physics are reset to the current pose. */
|
||||
reset
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,6 +34,8 @@ import static com.esotericsoftware.spine.utils.SpineUtils.*;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
/** Stores the current pose for a transform constraint. A transform constraint adjusts the world transform of the constrained
|
||||
* bones to match that of the target bone.
|
||||
* <p>
|
||||
@ -90,7 +92,7 @@ public class TransformConstraint implements Updatable {
|
||||
}
|
||||
|
||||
/** Applies the constraint to the constrained bones. */
|
||||
public void update () {
|
||||
public void update (Physics physics) {
|
||||
if (mixRotate == 0 && mixX == 0 && mixY == 0 && mixScaleX == 0 && mixScaleY == 0 && mixShearY == 0) return;
|
||||
if (data.local) {
|
||||
if (data.relative)
|
||||
|
||||
@ -29,9 +29,12 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
/** The interface for items updated by {@link Skeleton#updateWorldTransform()}. */
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
|
||||
/** The interface for items updated by {@link Skeleton#updateWorldTransform(Physics)}. */
|
||||
public interface Updatable {
|
||||
public void update ();
|
||||
/** @param physics Determines how physics and other non-deterministic updates are applied. */
|
||||
public void update (Physics physics);
|
||||
|
||||
/** Returns false when this item has not been updated because a skin is required and the {@link Skeleton#getSkin() active skin}
|
||||
* does not contain this item.
|
||||
|
||||
@ -52,6 +52,7 @@ import com.badlogic.gdx.utils.viewport.ScreenViewport;
|
||||
import com.esotericsoftware.spine.Animation.MixBlend;
|
||||
import com.esotericsoftware.spine.AnimationState.AnimationStateAdapter;
|
||||
import com.esotericsoftware.spine.AnimationState.TrackEntry;
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.utils.TwoColorPolygonBatch;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
@ -154,10 +155,7 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
}
|
||||
|
||||
skeleton = new Skeleton(skeletonData);
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.setToSetupPose();
|
||||
skeleton = new Skeleton(skeleton); // Tests copy constructors.
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
state = new AnimationState(new AnimationStateData(skeletonData));
|
||||
state.addListener(new AnimationStateAdapter() {
|
||||
@ -269,7 +267,7 @@ public class SkeletonViewer extends ApplicationAdapter {
|
||||
delta = Math.min(delta, 0.032f) * ui.speedSlider.getValue();
|
||||
state.update(delta);
|
||||
state.apply(skeleton);
|
||||
skeleton.updateWorldTransform();
|
||||
skeleton.updateWorldTransform(Physics.update);
|
||||
|
||||
batch.begin();
|
||||
renderer.draw(batch, skeleton);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user