mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
Initial libgdx runtime.
This commit is contained in:
parent
e2120ca07b
commit
2c78e22855
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,2 +1,6 @@
|
|||||||
spine-cpp/Debug/*
|
spine-cpp/Debug/*
|
||||||
spine-libgdx/bin/*
|
spine-libgdx/bin/*
|
||||||
|
spine-libgdx/libs/gdx-backend-lwjgl-natives.jar
|
||||||
|
spine-libgdx/libs/gdx-backend-lwjgl.jar
|
||||||
|
spine-libgdx/libs/gdx-natives.jar
|
||||||
|
spine-libgdx/libs/gdx.jar
|
||||||
|
|||||||
9
spine-libgdx/.classpath
Normal file
9
spine-libgdx/.classpath
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" path="src"/>
|
||||||
|
<classpathentry kind="src" path="test"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
|
||||||
|
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/gdx"/>
|
||||||
|
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/gdx-backend-lwjgl"/>
|
||||||
|
<classpathentry kind="output" path="bin"/>
|
||||||
|
</classpath>
|
||||||
17
spine-libgdx/.project
Normal file
17
spine-libgdx/.project
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>spine-libgdx</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
95
spine-libgdx/.settings/org.eclipse.jdt.core.prefs
Normal file
95
spine-libgdx/.settings/org.eclipse.jdt.core.prefs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
|
||||||
|
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.5
|
||||||
|
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||||
|
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||||
|
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.deadCode=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.deprecation=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nullReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedImport=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedLocal=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.5
|
||||||
477
spine-libgdx/src/com/esotericsoftware/spine/Animation.java
Normal file
477
spine-libgdx/src/com/esotericsoftware/spine/Animation.java
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
|
||||||
|
public class Animation {
|
||||||
|
private final Array<Timeline> timelines;
|
||||||
|
private float duration;
|
||||||
|
|
||||||
|
public Animation (Array<Timeline> timelines, float duration) {
|
||||||
|
if (timelines == null) throw new IllegalArgumentException("timelines cannot be null.");
|
||||||
|
this.timelines = timelines;
|
||||||
|
this.duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Timeline> getTimelines () {
|
||||||
|
return timelines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the duration of the animation in seconds. Defaults to the max {@link Timeline#getDuration() duration} of the
|
||||||
|
* timelines. */
|
||||||
|
public float getDuration () {
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDuration (float duration) {
|
||||||
|
this.duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Poses the skeleton at the specified time for this animation. */
|
||||||
|
public void apply (Skeleton skeleton, float time, boolean loop) {
|
||||||
|
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
||||||
|
|
||||||
|
if (loop && duration != 0) time %= duration;
|
||||||
|
|
||||||
|
Array<Timeline> timeline = this.timelines;
|
||||||
|
for (int i = 0, n = timeline.size; i < n; i++)
|
||||||
|
timeline.get(i).apply(skeleton, time, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Poses the skeleton at the specified time for this animation mixed with the current pose.
|
||||||
|
* @param alpha The amount of this animation that affects the current pose. */
|
||||||
|
public void mix (Skeleton skeleton, float time, boolean loop, float alpha) {
|
||||||
|
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
||||||
|
|
||||||
|
if (loop && duration != 0) time %= duration;
|
||||||
|
|
||||||
|
Array<Timeline> timeline = this.timelines;
|
||||||
|
for (int i = 0, n = timeline.size; i < n; i++)
|
||||||
|
timeline.get(i).apply(skeleton, time, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param target After the first and before the last entry. */
|
||||||
|
static int binarySearch (float[] values, float target, int step) {
|
||||||
|
int low = 0;
|
||||||
|
int high = values.length / step - 2;
|
||||||
|
if (high == 0) return step;
|
||||||
|
int current = high >>> 1;
|
||||||
|
while (true) {
|
||||||
|
if (values[(current + 1) * step] <= target)
|
||||||
|
low = current + 1;
|
||||||
|
else
|
||||||
|
high = current;
|
||||||
|
if (low == high) return (low + 1) * step;
|
||||||
|
current = (low + high) >>> 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int linearSearch (float[] values, float target, int step) {
|
||||||
|
for (int i = 0, last = values.length - step; i <= last; i += step) {
|
||||||
|
if (values[i] <= target) continue;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The keyframes for a single animation timeline. */
|
||||||
|
static public interface Timeline {
|
||||||
|
/** Returns the time in seconds of the last keyframe. */
|
||||||
|
public float getDuration ();
|
||||||
|
|
||||||
|
public int getKeyframeCount ();
|
||||||
|
|
||||||
|
/** Sets the value(s) for the specified time. */
|
||||||
|
public void apply (Skeleton skeleton, float time, float alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Base class for frames that use an interpolation bezier curve. */
|
||||||
|
static public abstract class CurveTimeline implements Timeline {
|
||||||
|
static private final float LINEAR = 0;
|
||||||
|
static private final float STEPPED = -1;
|
||||||
|
static private final int BEZIER_SEGMENTS = 10;
|
||||||
|
|
||||||
|
private final float[] curves; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ...
|
||||||
|
|
||||||
|
public CurveTimeline (int keyframeCount) {
|
||||||
|
curves = new float[(keyframeCount - 1) * 6];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLinear (int keyframeIndex) {
|
||||||
|
curves[keyframeIndex * 6] = LINEAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStepped (int keyframeIndex) {
|
||||||
|
curves[keyframeIndex * 6] = STEPPED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next.
|
||||||
|
* cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of
|
||||||
|
* the difference between the keyframe's values. */
|
||||||
|
public void setCurve (int keyframeIndex, float cx1, float cy1, float cx2, float cy2) {
|
||||||
|
float subdiv_step = 1f / BEZIER_SEGMENTS;
|
||||||
|
float subdiv_step2 = subdiv_step * subdiv_step;
|
||||||
|
float subdiv_step3 = subdiv_step2 * subdiv_step;
|
||||||
|
float pre1 = 3 * subdiv_step;
|
||||||
|
float pre2 = 3 * subdiv_step2;
|
||||||
|
float pre4 = 6 * subdiv_step2;
|
||||||
|
float pre5 = 6 * subdiv_step3;
|
||||||
|
float tmp1x = -cx1 * 2 + cx2;
|
||||||
|
float tmp1y = -cy1 * 2 + cy2;
|
||||||
|
float tmp2x = (cx1 - cx2) * 3 + 1;
|
||||||
|
float tmp2y = (cy1 - cy2) * 3 + 1;
|
||||||
|
int i = keyframeIndex * 6;
|
||||||
|
float[] curves = this.curves;
|
||||||
|
curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3;
|
||||||
|
curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3;
|
||||||
|
curves[i + 2] = tmp1x * pre4 + tmp2x * pre5;
|
||||||
|
curves[i + 3] = tmp1y * pre4 + tmp2y * pre5;
|
||||||
|
curves[i + 4] = tmp2x * pre5;
|
||||||
|
curves[i + 5] = tmp2y * pre5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getCurvePercent (int keyframeIndex, float percent) {
|
||||||
|
int curveIndex = keyframeIndex * 6;
|
||||||
|
float[] curves = this.curves;
|
||||||
|
float dfx = curves[curveIndex];
|
||||||
|
if (dfx == LINEAR) return percent;
|
||||||
|
if (dfx == STEPPED) return 0;
|
||||||
|
float dfy = curves[curveIndex + 1];
|
||||||
|
float ddfx = curves[curveIndex + 2];
|
||||||
|
float ddfy = curves[curveIndex + 3];
|
||||||
|
float dddfx = curves[curveIndex + 4];
|
||||||
|
float dddfy = curves[curveIndex + 5];
|
||||||
|
float x = dfx, y = dfy;
|
||||||
|
int i = BEZIER_SEGMENTS - 2;
|
||||||
|
while (true) {
|
||||||
|
if (x >= percent) {
|
||||||
|
float lastX = x - dfx;
|
||||||
|
float lastY = y - dfy;
|
||||||
|
return lastY + (y - lastY) * (percent - lastX) / (x - lastX);
|
||||||
|
}
|
||||||
|
if (i == 0) break;
|
||||||
|
i--;
|
||||||
|
dfx += ddfx;
|
||||||
|
dfy += ddfy;
|
||||||
|
ddfx += dddfx;
|
||||||
|
ddfy += dddfy;
|
||||||
|
x += dfx;
|
||||||
|
y += dfy;
|
||||||
|
}
|
||||||
|
return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public class RotateTimeline extends CurveTimeline {
|
||||||
|
static private final int LAST_FRAME_TIME = -2;
|
||||||
|
static private final int FRAME_VALUE = 1;
|
||||||
|
|
||||||
|
private int boneIndex;
|
||||||
|
private final float[] frames; // time, value, ...
|
||||||
|
|
||||||
|
public RotateTimeline (int keyframeCount) {
|
||||||
|
super(keyframeCount);
|
||||||
|
frames = new float[keyframeCount * 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getDuration () {
|
||||||
|
return frames[frames.length - 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKeyframeCount () {
|
||||||
|
return frames.length / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoneIndex (int boneIndex) {
|
||||||
|
this.boneIndex = boneIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBoneIndex () {
|
||||||
|
return boneIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[] getKeyframes () {
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the time and value of the specified keyframe. */
|
||||||
|
public void setKeyframe (int keyframeIndex, float time, float value) {
|
||||||
|
keyframeIndex *= 2;
|
||||||
|
frames[keyframeIndex] = time;
|
||||||
|
frames[keyframeIndex + 1] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply (Skeleton skeleton, float time, float alpha) {
|
||||||
|
float[] frames = this.frames;
|
||||||
|
if (time < frames[0]) return; // Time is before first frame.
|
||||||
|
|
||||||
|
Bone bone = skeleton.bones.get(boneIndex);
|
||||||
|
|
||||||
|
if (time >= frames[frames.length - 2]) { // Time is after last frame.
|
||||||
|
float amount = bone.data.rotation + frames[frames.length - 1] - bone.rotation;
|
||||||
|
while (amount > 180)
|
||||||
|
amount -= 360;
|
||||||
|
while (amount < -180)
|
||||||
|
amount += 360;
|
||||||
|
bone.rotation += amount * alpha;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolate between the last frame and the current frame.
|
||||||
|
int frameIndex = binarySearch(frames, time, 2);
|
||||||
|
float lastFrameValue = frames[frameIndex - 1];
|
||||||
|
float frameTime = frames[frameIndex];
|
||||||
|
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime), 0, 1);
|
||||||
|
percent = getCurvePercent(frameIndex / 2 - 1, percent);
|
||||||
|
|
||||||
|
float amount = frames[frameIndex + FRAME_VALUE] - lastFrameValue;
|
||||||
|
while (amount > 180)
|
||||||
|
amount -= 360;
|
||||||
|
while (amount < -180)
|
||||||
|
amount += 360;
|
||||||
|
amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation;
|
||||||
|
while (amount > 180)
|
||||||
|
amount -= 360;
|
||||||
|
while (amount < -180)
|
||||||
|
amount += 360;
|
||||||
|
bone.rotation += amount * alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public class TranslateTimeline extends CurveTimeline {
|
||||||
|
static final int LAST_FRAME_TIME = -3;
|
||||||
|
static final int FRAME_X = 1;
|
||||||
|
static final int FRAME_Y = 2;
|
||||||
|
|
||||||
|
int boneIndex;
|
||||||
|
final float[] frames; // time, value, value, ...
|
||||||
|
|
||||||
|
public TranslateTimeline (int keyframeCount) {
|
||||||
|
super(keyframeCount);
|
||||||
|
frames = new float[keyframeCount * 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getDuration () {
|
||||||
|
return frames[frames.length - 3];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKeyframeCount () {
|
||||||
|
return frames.length / 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBoneIndex (int boneIndex) {
|
||||||
|
this.boneIndex = boneIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBoneIndex () {
|
||||||
|
return boneIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[] getKeyframes () {
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the time and value of the specified keyframe. */
|
||||||
|
public void setKeyframe (int keyframeIndex, float time, float x, float y) {
|
||||||
|
keyframeIndex *= 3;
|
||||||
|
frames[keyframeIndex] = time;
|
||||||
|
frames[keyframeIndex + 1] = x;
|
||||||
|
frames[keyframeIndex + 2] = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply (Skeleton skeleton, float time, float alpha) {
|
||||||
|
float[] frames = this.frames;
|
||||||
|
if (time < frames[0]) return; // Time is before first frame.
|
||||||
|
|
||||||
|
Bone bone = skeleton.bones.get(boneIndex);
|
||||||
|
|
||||||
|
if (time >= frames[frames.length - 3]) { // Time is after last frame.
|
||||||
|
bone.x += (bone.data.x + frames[frames.length - 2] - bone.x) * alpha;
|
||||||
|
bone.y += (bone.data.y + frames[frames.length - 1] - bone.y) * alpha;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolate between the last frame and the current frame.
|
||||||
|
int frameIndex = binarySearch(frames, time, 3);
|
||||||
|
float lastFrameX = frames[frameIndex - 2];
|
||||||
|
float lastFrameY = frames[frameIndex - 1];
|
||||||
|
float frameTime = frames[frameIndex];
|
||||||
|
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime), 0, 1);
|
||||||
|
percent = getCurvePercent(frameIndex / 3 - 1, percent);
|
||||||
|
|
||||||
|
bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + FRAME_X] - lastFrameX) * percent - bone.x) * alpha;
|
||||||
|
bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + FRAME_Y] - lastFrameY) * percent - bone.y) * alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public class ScaleTimeline extends TranslateTimeline {
|
||||||
|
public ScaleTimeline (int keyframeCount) {
|
||||||
|
super(keyframeCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply (Skeleton skeleton, float time, float alpha) {
|
||||||
|
float[] frames = this.frames;
|
||||||
|
if (time < frames[0]) return; // Time is before first frame.
|
||||||
|
|
||||||
|
Bone bone = skeleton.bones.get(boneIndex);
|
||||||
|
if (time >= frames[frames.length - 3]) { // Time is after last frame.
|
||||||
|
bone.scaleX += (bone.data.scaleX - 1 + frames[frames.length - 2] - bone.scaleX) * alpha;
|
||||||
|
bone.scaleY += (bone.data.scaleY - 1 + frames[frames.length - 1] - bone.scaleY) * alpha;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolate between the last frame and the current frame.
|
||||||
|
int frameIndex = binarySearch(frames, time, 3);
|
||||||
|
float lastFrameX = frames[frameIndex - 2];
|
||||||
|
float lastFrameY = frames[frameIndex - 1];
|
||||||
|
float frameTime = frames[frameIndex];
|
||||||
|
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime), 0, 1);
|
||||||
|
percent = getCurvePercent(frameIndex / 3 - 1, percent);
|
||||||
|
|
||||||
|
bone.scaleX += (bone.data.scaleX - 1 + lastFrameX + (frames[frameIndex + FRAME_X] - lastFrameX) * percent - bone.scaleX)
|
||||||
|
* alpha;
|
||||||
|
bone.scaleY += (bone.data.scaleY - 1 + lastFrameY + (frames[frameIndex + FRAME_Y] - lastFrameY) * percent - bone.scaleY)
|
||||||
|
* alpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public class ColorTimeline extends CurveTimeline {
|
||||||
|
static private final int LAST_FRAME_TIME = -5;
|
||||||
|
static private final int FRAME_R = 1;
|
||||||
|
static private final int FRAME_G = 2;
|
||||||
|
static private final int FRAME_B = 3;
|
||||||
|
static private final int FRAME_A = 4;
|
||||||
|
|
||||||
|
private int slotIndex;
|
||||||
|
private final float[] frames; // time, r, g, b, a, ...
|
||||||
|
|
||||||
|
public ColorTimeline (int keyframeCount) {
|
||||||
|
super(keyframeCount);
|
||||||
|
frames = new float[keyframeCount * 5];
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getDuration () {
|
||||||
|
return frames[frames.length - 5];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKeyframeCount () {
|
||||||
|
return frames.length / 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlotIndex (int slotIndex) {
|
||||||
|
this.slotIndex = slotIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSlotIndex () {
|
||||||
|
return slotIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[] getKeyframes () {
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the time and value of the specified keyframe. */
|
||||||
|
public void setKeyframe (int keyframeIndex, float time, float r, float g, float b, float a) {
|
||||||
|
keyframeIndex *= 5;
|
||||||
|
frames[keyframeIndex] = time;
|
||||||
|
frames[keyframeIndex + 1] = r;
|
||||||
|
frames[keyframeIndex + 2] = g;
|
||||||
|
frames[keyframeIndex + 3] = b;
|
||||||
|
frames[keyframeIndex + 4] = a;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply (Skeleton skeleton, float time, float alpha) {
|
||||||
|
float[] frames = this.frames;
|
||||||
|
if (time < frames[0]) return; // Time is before first frame.
|
||||||
|
|
||||||
|
Color color = skeleton.slots.get(slotIndex).color;
|
||||||
|
|
||||||
|
if (time >= frames[frames.length - 5]) { // Time is after last frame.
|
||||||
|
int i = frames.length - 1;
|
||||||
|
float r = frames[i - 3];
|
||||||
|
float g = frames[i - 2];
|
||||||
|
float b = frames[i - 1];
|
||||||
|
float a = frames[i];
|
||||||
|
color.set(r, g, b, a);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolate between the last frame and the current frame.
|
||||||
|
int frameIndex = binarySearch(frames, time, 5);
|
||||||
|
float lastFrameR = frames[frameIndex - 4];
|
||||||
|
float lastFrameG = frames[frameIndex - 3];
|
||||||
|
float lastFrameB = frames[frameIndex - 2];
|
||||||
|
float lastFrameA = frames[frameIndex - 1];
|
||||||
|
float frameTime = frames[frameIndex];
|
||||||
|
float percent = MathUtils.clamp(1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime), 0, 1);
|
||||||
|
percent = getCurvePercent(frameIndex / 5 - 1, percent);
|
||||||
|
|
||||||
|
float r = lastFrameR + (frames[frameIndex + FRAME_R] - lastFrameR) * percent;
|
||||||
|
float g = lastFrameG + (frames[frameIndex + FRAME_G] - lastFrameG) * percent;
|
||||||
|
float b = lastFrameB + (frames[frameIndex + FRAME_B] - lastFrameB) * percent;
|
||||||
|
float a = lastFrameA + (frames[frameIndex + FRAME_A] - lastFrameA) * percent;
|
||||||
|
if (alpha < 1)
|
||||||
|
color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha);
|
||||||
|
else
|
||||||
|
color.set(r, g, b, a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static public class AttachmentTimeline implements Timeline {
|
||||||
|
private int slotIndex;
|
||||||
|
private final float[] frames; // time, ...
|
||||||
|
private final String[] attachmentNames;
|
||||||
|
|
||||||
|
public AttachmentTimeline (int keyframeCount) {
|
||||||
|
frames = new float[keyframeCount];
|
||||||
|
attachmentNames = new String[keyframeCount];
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getDuration () {
|
||||||
|
return frames[frames.length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getKeyframeCount () {
|
||||||
|
return frames.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSlotIndex () {
|
||||||
|
return slotIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlotIndex (int slotIndex) {
|
||||||
|
this.slotIndex = slotIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[] getKeyframes () {
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getAttachmentNames () {
|
||||||
|
return attachmentNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the time and value of the specified keyframe. */
|
||||||
|
public void setKeyframe (int keyframeIndex, float time, String attachmentName) {
|
||||||
|
frames[keyframeIndex] = time;
|
||||||
|
attachmentNames[keyframeIndex] = attachmentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply (Skeleton skeleton, float time, float alpha) {
|
||||||
|
float[] frames = this.frames;
|
||||||
|
if (time < frames[0]) return; // Time is before first frame.
|
||||||
|
|
||||||
|
int frameIndex;
|
||||||
|
if (time >= frames[frames.length - 1]) // Time is after last frame.
|
||||||
|
frameIndex = frames.length - 1;
|
||||||
|
else
|
||||||
|
frameIndex = binarySearch(frames, time, 1) - 1;
|
||||||
|
|
||||||
|
String attachmentName = attachmentNames[frameIndex];
|
||||||
|
skeleton.slots.get(slotIndex).setAttachment(
|
||||||
|
attachmentName == null ? null : skeleton.getAttachment(slotIndex, attachmentName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
91
spine-libgdx/src/com/esotericsoftware/spine/Attachment.java
Normal file
91
spine-libgdx/src/com/esotericsoftware/spine/Attachment.java
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
|
|
||||||
|
abstract public class Attachment {
|
||||||
|
final String name;
|
||||||
|
boolean resolved;
|
||||||
|
private float x, y, scaleX, scaleY, rotation, width, height;
|
||||||
|
|
||||||
|
public Attachment (String name) {
|
||||||
|
if (name == null) throw new IllegalArgumentException("name cannot be null.");
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract public void updateOffset ();
|
||||||
|
|
||||||
|
abstract public void draw (SpriteBatch batch, Slot slot);
|
||||||
|
|
||||||
|
public float getX () {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX (float x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getY () {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY (float y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getScaleX () {
|
||||||
|
return scaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScaleX (float scaleX) {
|
||||||
|
this.scaleX = scaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getScaleY () {
|
||||||
|
return scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScaleY (float scaleY) {
|
||||||
|
this.scaleY = scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRotation () {
|
||||||
|
return rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotation (float rotation) {
|
||||||
|
this.rotation = rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getWidth () {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWidth (float width) {
|
||||||
|
this.width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getHeight () {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setHeight (float height) {
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isResolved () {
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResolved (boolean resolved) {
|
||||||
|
this.resolved = resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName () {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString () {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
public interface AttachmentResolver {
|
||||||
|
public void resolve (Attachment attachment);
|
||||||
|
}
|
||||||
185
spine-libgdx/src/com/esotericsoftware/spine/Bone.java
Normal file
185
spine-libgdx/src/com/esotericsoftware/spine/Bone.java
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import static com.badlogic.gdx.math.Matrix3.*;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
|
import com.badlogic.gdx.math.Matrix3;
|
||||||
|
|
||||||
|
public class Bone {
|
||||||
|
final BoneData data;
|
||||||
|
final Bone parent;
|
||||||
|
float x, y;
|
||||||
|
float rotation;
|
||||||
|
float scaleX = 1, scaleY = 1;
|
||||||
|
|
||||||
|
float m00, m01, worldX; // a b x
|
||||||
|
float m10, m11, worldY; // c d y
|
||||||
|
float worldRotation;
|
||||||
|
float worldScaleX, worldScaleY;
|
||||||
|
|
||||||
|
/** @param parent May be null. */
|
||||||
|
public Bone (BoneData data, Bone parent) {
|
||||||
|
if (data == null) throw new IllegalArgumentException("data cannot be null.");
|
||||||
|
this.data = data;
|
||||||
|
this.parent = parent;
|
||||||
|
setToBindPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
* @param parent May be null. */
|
||||||
|
public Bone (Bone bone, Bone parent) {
|
||||||
|
if (bone == null) throw new IllegalArgumentException("bone cannot be null.");
|
||||||
|
this.parent = parent;
|
||||||
|
data = bone.data;
|
||||||
|
x = bone.x;
|
||||||
|
y = bone.y;
|
||||||
|
rotation = bone.rotation;
|
||||||
|
scaleX = bone.scaleX;
|
||||||
|
scaleY = bone.scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Computes the world SRT using the parent bone and the local SRT. */
|
||||||
|
public void updateWorldTransform (boolean flipX, boolean flipY) {
|
||||||
|
Bone parent = this.parent;
|
||||||
|
if (parent != null) {
|
||||||
|
worldX = x * parent.m00 + y * parent.m01 + parent.worldX;
|
||||||
|
worldY = x * parent.m10 + y * parent.m11 + parent.worldY;
|
||||||
|
worldScaleX = parent.worldScaleX * scaleX;
|
||||||
|
worldScaleY = parent.worldScaleY * scaleY;
|
||||||
|
worldRotation = parent.worldRotation + rotation;
|
||||||
|
} else {
|
||||||
|
worldX = x;
|
||||||
|
worldY = y;
|
||||||
|
worldScaleX = scaleX;
|
||||||
|
worldScaleY = scaleY;
|
||||||
|
worldRotation = rotation;
|
||||||
|
}
|
||||||
|
float cos = MathUtils.cosDeg(worldRotation);
|
||||||
|
float sin = MathUtils.sinDeg(worldRotation);
|
||||||
|
m00 = cos * worldScaleX;
|
||||||
|
m10 = sin * worldScaleX;
|
||||||
|
m01 = -sin * worldScaleY;
|
||||||
|
m11 = cos * worldScaleY;
|
||||||
|
if (flipX) {
|
||||||
|
m00 = -m00;
|
||||||
|
m01 = -m01;
|
||||||
|
}
|
||||||
|
if (flipY) {
|
||||||
|
m10 = -m10;
|
||||||
|
m11 = -m11;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToBindPose () {
|
||||||
|
BoneData data = this.data;
|
||||||
|
x = data.x;
|
||||||
|
y = data.y;
|
||||||
|
rotation = data.rotation;
|
||||||
|
scaleX = data.scaleX;
|
||||||
|
scaleY = data.scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoneData getData () {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bone getParent () {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getX () {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX (float x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getY () {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY (float y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRotation () {
|
||||||
|
return rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotation (float rotation) {
|
||||||
|
this.rotation = rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getScaleX () {
|
||||||
|
return scaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScaleX (float scaleX) {
|
||||||
|
this.scaleX = scaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getScaleY () {
|
||||||
|
return scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScaleY (float scaleY) {
|
||||||
|
this.scaleY = scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getM00 () {
|
||||||
|
return m00;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getM01 () {
|
||||||
|
return m01;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getM10 () {
|
||||||
|
return m10;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getM11 () {
|
||||||
|
return m11;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getWorldX () {
|
||||||
|
return worldX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getWorldY () {
|
||||||
|
return worldY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getWorldRotation () {
|
||||||
|
return worldRotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getWorldScaleX () {
|
||||||
|
return worldScaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getWorldScaleY () {
|
||||||
|
return worldScaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Matrix3 getWorldTransform (Matrix3 worldTransform) {
|
||||||
|
if (worldTransform == null) throw new IllegalArgumentException("worldTransform cannot be null.");
|
||||||
|
float[] val = worldTransform.val;
|
||||||
|
val[M00] = m00;
|
||||||
|
val[M01] = m01;
|
||||||
|
val[M02] = worldX;
|
||||||
|
val[M10] = m10;
|
||||||
|
val[M11] = m11;
|
||||||
|
val[M12] = worldY;
|
||||||
|
val[M20] = 0;
|
||||||
|
val[M21] = 0;
|
||||||
|
val[M22] = 1;
|
||||||
|
return worldTransform;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString () {
|
||||||
|
return data.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
93
spine-libgdx/src/com/esotericsoftware/spine/BoneData.java
Normal file
93
spine-libgdx/src/com/esotericsoftware/spine/BoneData.java
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
public class BoneData {
|
||||||
|
final BoneData parent;
|
||||||
|
final String name;
|
||||||
|
float length;
|
||||||
|
float x, y;
|
||||||
|
float rotation;
|
||||||
|
float scaleX = 1, scaleY = 1;
|
||||||
|
|
||||||
|
/** @param parent May be null. */
|
||||||
|
public BoneData (String name, BoneData parent) {
|
||||||
|
if (name == null) throw new IllegalArgumentException("name cannot be null.");
|
||||||
|
this.name = name;
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
* @param parent May be null. */
|
||||||
|
public BoneData (BoneData bone, BoneData parent) {
|
||||||
|
if (bone == null) throw new IllegalArgumentException("bone cannot be null.");
|
||||||
|
this.parent = parent;
|
||||||
|
name = bone.name;
|
||||||
|
length = bone.length;
|
||||||
|
x = bone.x;
|
||||||
|
y = bone.y;
|
||||||
|
rotation = bone.rotation;
|
||||||
|
scaleX = bone.scaleX;
|
||||||
|
scaleY = bone.scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public BoneData getParent () {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName () {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getLength () {
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLength (float length) {
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getX () {
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setX (float x) {
|
||||||
|
this.x = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getY () {
|
||||||
|
return y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setY (float y) {
|
||||||
|
this.y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getRotation () {
|
||||||
|
return rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRotation (float rotation) {
|
||||||
|
this.rotation = rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getScaleX () {
|
||||||
|
return scaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScaleX (float scaleX) {
|
||||||
|
this.scaleX = scaleX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getScaleY () {
|
||||||
|
return scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScaleY (float scaleY) {
|
||||||
|
this.scaleY = scaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString () {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
279
spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java
Normal file
279
spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Skin.Key;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
|
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||||
|
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.ObjectMap.Entry;
|
||||||
|
|
||||||
|
public class Skeleton {
|
||||||
|
final SkeletonData data;
|
||||||
|
final Array<Bone> bones;
|
||||||
|
final Array<Slot> slots;
|
||||||
|
final Array<Slot> drawOrder;
|
||||||
|
Skin skin;
|
||||||
|
final Color color;
|
||||||
|
float time;
|
||||||
|
boolean flipX, flipY;
|
||||||
|
|
||||||
|
public Skeleton (SkeletonData data) {
|
||||||
|
if (data == null) throw new IllegalArgumentException("data cannot be null.");
|
||||||
|
this.data = data;
|
||||||
|
|
||||||
|
bones = new Array(data.bones.size);
|
||||||
|
for (BoneData boneData : data.bones) {
|
||||||
|
Bone parent = boneData.parent == null ? null : bones.get(data.bones.indexOf(boneData.parent, true));
|
||||||
|
bones.add(new Bone(boneData, parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
slots = new Array(data.slots.size);
|
||||||
|
drawOrder = new Array(data.slots.size);
|
||||||
|
for (SlotData slotData : data.slots) {
|
||||||
|
Bone bone = bones.get(data.bones.indexOf(slotData.boneData, true));
|
||||||
|
Slot slot = new Slot(slotData, this, bone);
|
||||||
|
slots.add(slot);
|
||||||
|
drawOrder.add(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
color = new Color(1, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
public Skeleton (Skeleton skeleton) {
|
||||||
|
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
||||||
|
data = skeleton.data;
|
||||||
|
|
||||||
|
bones = new Array(skeleton.bones.size);
|
||||||
|
for (Bone bone : skeleton.bones) {
|
||||||
|
Bone parent = bones.get(skeleton.bones.indexOf(bone.parent, true));
|
||||||
|
bones.add(new Bone(bone, parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
slots = new Array(skeleton.slots.size);
|
||||||
|
for (Slot slot : skeleton.slots) {
|
||||||
|
Bone bone = bones.get(skeleton.bones.indexOf(slot.bone, true));
|
||||||
|
Slot newSlot = new Slot(slot, this, bone);
|
||||||
|
slots.add(newSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
drawOrder = new Array(slots.size);
|
||||||
|
for (Slot slot : skeleton.drawOrder)
|
||||||
|
drawOrder.add(slots.get(skeleton.slots.indexOf(slot, true)));
|
||||||
|
|
||||||
|
skin = skeleton.skin;
|
||||||
|
color = new Color(skeleton.color);
|
||||||
|
time = skeleton.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Updates the world transform for each bone. */
|
||||||
|
public void updateWorldTransform () {
|
||||||
|
boolean flipX = this.flipX;
|
||||||
|
boolean flipY = this.flipY;
|
||||||
|
Array<Bone> bones = this.bones;
|
||||||
|
for (int i = 0, n = bones.size; i < n; i++)
|
||||||
|
bones.get(i).updateWorldTransform(flipX, flipY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the bones and slots to their bind pose values. */
|
||||||
|
public void setToBindPose () {
|
||||||
|
setBonesToBindPose();
|
||||||
|
setSlotsToBindPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBonesToBindPose () {
|
||||||
|
Array<Bone> bones = this.bones;
|
||||||
|
for (int i = 0, n = bones.size; i < n; i++)
|
||||||
|
bones.get(i).setToBindPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlotsToBindPose () {
|
||||||
|
Array<Slot> slots = this.slots;
|
||||||
|
for (int i = 0, n = slots.size; i < n; i++)
|
||||||
|
slots.get(i).setToBindPose(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw (SpriteBatch batch) {
|
||||||
|
Array<Slot> drawOrder = this.drawOrder;
|
||||||
|
for (int i = 0, n = drawOrder.size; i < n; i++) {
|
||||||
|
Slot slot = drawOrder.get(i);
|
||||||
|
Attachment attachment = slot.attachment;
|
||||||
|
if (attachment != null) {
|
||||||
|
if (!attachment.resolved) data.attachmentResolver.resolve(attachment);
|
||||||
|
attachment.updateOffset();
|
||||||
|
attachment.draw(batch, slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void drawDebug (ShapeRenderer renderer) {
|
||||||
|
renderer.setColor(Color.RED);
|
||||||
|
renderer.begin(ShapeType.Line);
|
||||||
|
for (int i = 0, n = bones.size; i < n; i++) {
|
||||||
|
Bone bone = bones.get(i);
|
||||||
|
if (bone.parent == null) continue;
|
||||||
|
float x = bone.data.length * bone.m00 + bone.worldX;
|
||||||
|
float y = bone.data.length * bone.m10 + bone.worldY;
|
||||||
|
renderer.line(bone.worldX, bone.worldY, x, y);
|
||||||
|
}
|
||||||
|
renderer.end();
|
||||||
|
|
||||||
|
renderer.setColor(Color.GREEN);
|
||||||
|
renderer.begin(ShapeType.Filled);
|
||||||
|
for (int i = 0, n = bones.size; i < n; i++) {
|
||||||
|
Bone bone = bones.get(i);
|
||||||
|
renderer.setColor(Color.GREEN);
|
||||||
|
renderer.circle(bone.worldX, bone.worldY, 3);
|
||||||
|
}
|
||||||
|
renderer.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkeletonData getData () {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Bone> getBones () {
|
||||||
|
return bones;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May return null. */
|
||||||
|
public Bone getRootBone () {
|
||||||
|
if (bones.size == 0) return null;
|
||||||
|
return bones.first();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Bone findBone (String boneName) {
|
||||||
|
if (boneName == null) throw new IllegalArgumentException("boneName cannot be null.");
|
||||||
|
Array<Bone> bones = this.bones;
|
||||||
|
for (int i = 0, n = bones.size; i < n; i++) {
|
||||||
|
Bone bone = bones.get(i);
|
||||||
|
if (bone.data.name.equals(boneName)) return bone;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return -1 if the bone was not found. */
|
||||||
|
public int findBoneIndex (String boneName) {
|
||||||
|
if (boneName == null) throw new IllegalArgumentException("boneName cannot be null.");
|
||||||
|
Array<Bone> bones = this.bones;
|
||||||
|
for (int i = 0, n = bones.size; i < n; i++)
|
||||||
|
if (bones.get(i).data.name.equals(boneName)) return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<Slot> getSlots () {
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Slot findSlot (String slotName) {
|
||||||
|
if (slotName == null) throw new IllegalArgumentException("slotName cannot be null.");
|
||||||
|
Array<Slot> slots = this.slots;
|
||||||
|
for (int i = 0, n = slots.size; i < n; i++) {
|
||||||
|
Slot slot = slots.get(i);
|
||||||
|
if (slot.data.name.equals(slotName)) return slot;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return -1 if the bone was not found. */
|
||||||
|
public int findSlotIndex (String slotName) {
|
||||||
|
if (slotName == null) throw new IllegalArgumentException("slotName cannot be null.");
|
||||||
|
Array<Slot> slots = this.slots;
|
||||||
|
for (int i = 0, n = slots.size; i < n; i++)
|
||||||
|
if (slots.get(i).data.name.equals(slotName)) return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the slots in the order they will be drawn. The returned array may be modified to change the draw order. */
|
||||||
|
public Array<Slot> getDrawOrder () {
|
||||||
|
return drawOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Skin getSkin () {
|
||||||
|
return skin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets a skin by name.
|
||||||
|
* @see #setSkin(Skin) */
|
||||||
|
public void setSkin (String skinName) {
|
||||||
|
Skin skin = data.findSkin(skinName);
|
||||||
|
if (skin == null) throw new IllegalArgumentException("Skin not found: " + skinName);
|
||||||
|
setSkin(skin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the skin used to look up attachments not found in the {@link SkeletonData#getDefaultSkin() default skin}. Attachments
|
||||||
|
* from the new skin are attached if the corresponding attachment from the old skin is currently attached.
|
||||||
|
* @param newSkin May be null. */
|
||||||
|
public void setSkin (Skin newSkin) {
|
||||||
|
if (skin != null && newSkin != null) newSkin.attachAll(this, skin);
|
||||||
|
skin = newSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Attachment getAttachment (String slotName, String attachmentName) {
|
||||||
|
return getAttachment(data.findSlotIndex(slotName), attachmentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Attachment getAttachment (int slotIndex, String attachmentName) {
|
||||||
|
if (attachmentName == null) throw new IllegalArgumentException("attachmentName cannot be null.");
|
||||||
|
if (data.defaultSkin != null) {
|
||||||
|
Attachment attachment = data.defaultSkin.getAttachment(slotIndex, attachmentName);
|
||||||
|
if (attachment != null) return attachment;
|
||||||
|
}
|
||||||
|
if (skin != null) return skin.getAttachment(slotIndex, attachmentName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param attachmentName May be null. */
|
||||||
|
public void setAttachment (String slotName, String attachmentName) {
|
||||||
|
if (slotName == null) throw new IllegalArgumentException("slotName cannot be null.");
|
||||||
|
if (attachmentName == null) throw new IllegalArgumentException("attachmentName cannot be null.");
|
||||||
|
for (int i = 0, n = slots.size; i < n; i++) {
|
||||||
|
Slot slot = slots.get(i);
|
||||||
|
if (slot.data.name.equals(slotName)) {
|
||||||
|
slot.setAttachment(getAttachment(i, attachmentName));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new IllegalArgumentException("Slot not found: " + slotName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor () {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getFlipX () {
|
||||||
|
return flipX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlipX (boolean flipX) {
|
||||||
|
this.flipX = flipX;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getFlipY () {
|
||||||
|
return flipY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFlipY (boolean flipY) {
|
||||||
|
this.flipY = flipY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getTime () {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTime (float time) {
|
||||||
|
this.time = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update (float delta) {
|
||||||
|
time += delta;
|
||||||
|
}
|
||||||
|
}
|
||||||
270
spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java
Normal file
270
spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Animation.AttachmentTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.ColorTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.CurveTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.RotateTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.Timeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.TranslateTimeline;
|
||||||
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
|
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment;
|
||||||
|
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment.Mode;
|
||||||
|
import com.esotericsoftware.spine.attachments.TextureAtlasAttachmentResolver;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.DataInput;
|
||||||
|
import com.badlogic.gdx.utils.SerializationException;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class SkeletonBinary {
|
||||||
|
static public final int TIMELINE_SCALE = 0;
|
||||||
|
static public final int TIMELINE_ROTATE = 1;
|
||||||
|
static public final int TIMELINE_TRANSLATE = 2;
|
||||||
|
static public final int TIMELINE_ATTACHMENT = 3;
|
||||||
|
static public final int TIMELINE_COLOR = 4;
|
||||||
|
|
||||||
|
static public final int ATTACHMENT_REGION = 0;
|
||||||
|
static public final int ATTACHMENT_REGION_SEQUENCE = 1;
|
||||||
|
|
||||||
|
static public final int CURVE_LINEAR = 0;
|
||||||
|
static public final int CURVE_STEPPED = 1;
|
||||||
|
static public final int CURVE_BEZIER = 2;
|
||||||
|
|
||||||
|
private final AttachmentResolver attachmentResolver;
|
||||||
|
private float scale = 1;
|
||||||
|
|
||||||
|
public SkeletonBinary (TextureAtlas atlas) {
|
||||||
|
attachmentResolver = new TextureAtlasAttachmentResolver(atlas);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkeletonBinary (AttachmentResolver attachmentResolver) {
|
||||||
|
this.attachmentResolver = attachmentResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getScale () {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Scales the bones, images, and animations as they are loaded. */
|
||||||
|
public void setScale (float scale) {
|
||||||
|
this.scale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkeletonData readSkeletonData (FileHandle file) {
|
||||||
|
if (file == null) throw new IllegalArgumentException("file cannot be null.");
|
||||||
|
|
||||||
|
SkeletonData skeletonData = new SkeletonData(attachmentResolver);
|
||||||
|
DataInput input = new DataInput(file.read(512));
|
||||||
|
try {
|
||||||
|
// Bones.
|
||||||
|
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
||||||
|
String name = input.readString();
|
||||||
|
BoneData parent = null;
|
||||||
|
String parentName = input.readString();
|
||||||
|
if (parentName != null) {
|
||||||
|
parent = skeletonData.findBone(parentName);
|
||||||
|
if (parent == null) throw new SerializationException("Bone not found: " + parentName);
|
||||||
|
}
|
||||||
|
BoneData boneData = new BoneData(name, parent);
|
||||||
|
boneData.x = input.readFloat() * scale;
|
||||||
|
boneData.y = input.readFloat() * scale;
|
||||||
|
boneData.scaleX = input.readFloat();
|
||||||
|
boneData.scaleY = input.readFloat();
|
||||||
|
boneData.rotation = input.readFloat();
|
||||||
|
boneData.length = input.readFloat() * scale;
|
||||||
|
skeletonData.addBone(boneData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slots.
|
||||||
|
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
||||||
|
String slotName = input.readString();
|
||||||
|
String boneName = input.readString();
|
||||||
|
BoneData boneData = skeletonData.findBone(boneName);
|
||||||
|
if (boneData == null) throw new SerializationException("Bone not found: " + boneName);
|
||||||
|
SlotData slotData = new SlotData(slotName, boneData);
|
||||||
|
Color.rgba8888ToColor(slotData.getColor(), input.readInt());
|
||||||
|
slotData.setAttachmentName(input.readString());
|
||||||
|
skeletonData.addSlot(slotData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default skin.
|
||||||
|
Skin defaultSkin = readSkin(input, "default");
|
||||||
|
if (defaultSkin != null) {
|
||||||
|
skeletonData.setDefaultSkin(defaultSkin);
|
||||||
|
skeletonData.addSkin(defaultSkin);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skins.
|
||||||
|
for (int i = 0, n = input.readInt(true); i < n; i++)
|
||||||
|
skeletonData.addSkin(readSkin(input, input.readString()));
|
||||||
|
|
||||||
|
input.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new SerializationException("Error reading skeleton file.", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
skeletonData.bones.shrink();
|
||||||
|
skeletonData.slots.shrink();
|
||||||
|
skeletonData.skins.shrink();
|
||||||
|
return skeletonData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Skin readSkin (DataInput input, String skinName) throws IOException {
|
||||||
|
int slotCount = input.readInt(true);
|
||||||
|
if (slotCount == 0) return null;
|
||||||
|
Skin skin = new Skin(skinName);
|
||||||
|
for (int i = 0; i < slotCount; i++) {
|
||||||
|
int slotIndex = input.readInt(true);
|
||||||
|
int attachmentCount = input.readInt(true);
|
||||||
|
for (int ii = 0; ii < attachmentCount; ii++) {
|
||||||
|
String name = input.readString();
|
||||||
|
skin.addAttachment(slotIndex, name, readAttachment(input, name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return skin;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Attachment readAttachment (DataInput input, String attachmentName) throws IOException {
|
||||||
|
String name = input.readString();
|
||||||
|
if (name == null) name = attachmentName;
|
||||||
|
|
||||||
|
Attachment attachment;
|
||||||
|
int type = input.readByte();
|
||||||
|
switch (type) {
|
||||||
|
case ATTACHMENT_REGION:
|
||||||
|
attachment = new RegionAttachment(name);
|
||||||
|
break;
|
||||||
|
case ATTACHMENT_REGION_SEQUENCE:
|
||||||
|
float fps = input.readFloat();
|
||||||
|
Mode mode = Mode.values()[input.readInt(true)];
|
||||||
|
attachment = new RegionSequenceAttachment(name, 1 / fps, mode);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new SerializationException("Unknown attachment type: " + type + " (" + name + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment.setX(input.readFloat() * scale);
|
||||||
|
attachment.setY(input.readFloat() * scale);
|
||||||
|
attachment.setScaleX(input.readFloat());
|
||||||
|
attachment.setScaleY(input.readFloat());
|
||||||
|
attachment.setRotation(input.readFloat());
|
||||||
|
attachment.setWidth(input.readFloat() * scale);
|
||||||
|
attachment.setHeight(input.readFloat() * scale);
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Animation readAnimation (FileHandle file, SkeletonData skeleton) {
|
||||||
|
if (file == null) throw new IllegalArgumentException("file cannot be null.");
|
||||||
|
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
||||||
|
|
||||||
|
Array<Timeline> timelines = new Array();
|
||||||
|
float duration = 0;
|
||||||
|
|
||||||
|
DataInput input = new DataInput(file.read(512));
|
||||||
|
try {
|
||||||
|
int boneCount = input.readInt(true);
|
||||||
|
for (int i = 0; i < boneCount; i++) {
|
||||||
|
String boneName = input.readString();
|
||||||
|
int boneIndex = skeleton.findBoneIndex(boneName);
|
||||||
|
if (boneIndex == -1) throw new SerializationException("Bone not found: " + boneName);
|
||||||
|
int itemCount = input.readInt(true);
|
||||||
|
for (int ii = 0; ii < itemCount; ii++) {
|
||||||
|
int timelineType = input.readByte();
|
||||||
|
int keyCount = input.readInt(true);
|
||||||
|
switch (timelineType) {
|
||||||
|
case TIMELINE_ROTATE: {
|
||||||
|
RotateTimeline timeline = new RotateTimeline(keyCount);
|
||||||
|
timeline.setBoneIndex(boneIndex);
|
||||||
|
for (int keyframeIndex = 0; keyframeIndex < keyCount; keyframeIndex++) {
|
||||||
|
timeline.setKeyframe(keyframeIndex, input.readFloat(), input.readFloat());
|
||||||
|
if (keyframeIndex < keyCount - 1) readCurve(input, keyframeIndex, timeline);
|
||||||
|
}
|
||||||
|
timelines.add(timeline);
|
||||||
|
duration = Math.max(duration, timeline.getDuration());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TIMELINE_TRANSLATE:
|
||||||
|
case TIMELINE_SCALE:
|
||||||
|
TranslateTimeline timeline;
|
||||||
|
float timelineScale = 1;
|
||||||
|
if (timelineType == TIMELINE_SCALE)
|
||||||
|
timeline = new ScaleTimeline(keyCount);
|
||||||
|
else {
|
||||||
|
timeline = new TranslateTimeline(keyCount);
|
||||||
|
timelineScale = scale;
|
||||||
|
}
|
||||||
|
timeline.setBoneIndex(boneIndex);
|
||||||
|
for (int keyframeIndex = 0; keyframeIndex < keyCount; keyframeIndex++) {
|
||||||
|
timeline.setKeyframe(keyframeIndex, input.readFloat(), input.readFloat() * timelineScale, input.readFloat()
|
||||||
|
* timelineScale);
|
||||||
|
if (keyframeIndex < keyCount - 1) readCurve(input, keyframeIndex, timeline);
|
||||||
|
}
|
||||||
|
timelines.add(timeline);
|
||||||
|
duration = Math.max(duration, timeline.getDuration());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Invalid timeline type for a bone: " + timelineType + " (" + boneName + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int slotCount = input.readInt(true);
|
||||||
|
for (int i = 0; i < slotCount; i++) {
|
||||||
|
String slotName = input.readString();
|
||||||
|
int slotIndex = skeleton.findSlotIndex(slotName);
|
||||||
|
int itemCount = input.readInt(true);
|
||||||
|
for (int ii = 0; ii < itemCount; ii++) {
|
||||||
|
int timelineType = input.readByte();
|
||||||
|
int keyCount = input.readInt(true);
|
||||||
|
switch (timelineType) {
|
||||||
|
case TIMELINE_COLOR: {
|
||||||
|
ColorTimeline timeline = new ColorTimeline(keyCount);
|
||||||
|
timeline.setSlotIndex(slotIndex);
|
||||||
|
for (int keyframeIndex = 0; keyframeIndex < keyCount; keyframeIndex++) {
|
||||||
|
float time = input.readFloat();
|
||||||
|
Color.rgba8888ToColor(Color.tmp, input.readInt());
|
||||||
|
timeline.setKeyframe(keyframeIndex, time, Color.tmp.r, Color.tmp.g, Color.tmp.b, Color.tmp.a);
|
||||||
|
if (keyframeIndex < keyCount - 1) readCurve(input, keyframeIndex, timeline);
|
||||||
|
}
|
||||||
|
timelines.add(timeline);
|
||||||
|
duration = Math.max(duration, timeline.getDuration());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TIMELINE_ATTACHMENT:
|
||||||
|
AttachmentTimeline timeline = new AttachmentTimeline(keyCount);
|
||||||
|
timeline.setSlotIndex(slotIndex);
|
||||||
|
for (int keyframeIndex = 0; keyframeIndex < keyCount; keyframeIndex++)
|
||||||
|
timeline.setKeyframe(keyframeIndex, input.readFloat(), input.readString());
|
||||||
|
timelines.add(timeline);
|
||||||
|
duration = Math.max(duration, timeline.getDuration());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new RuntimeException("Invalid timeline type for a slot: " + timelineType + " (" + slotName + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new SerializationException("Error reading skeleton file.", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
timelines.shrink();
|
||||||
|
return new Animation(timelines, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readCurve (DataInput input, int keyframeIndex, CurveTimeline timeline) throws IOException {
|
||||||
|
switch (input.readByte()) {
|
||||||
|
case CURVE_STEPPED:
|
||||||
|
timeline.setStepped(keyframeIndex);
|
||||||
|
break;
|
||||||
|
case CURVE_BEZIER:
|
||||||
|
timeline.setCurve(keyframeIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
120
spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java
Normal file
120
spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
|
||||||
|
public class SkeletonData {
|
||||||
|
final Array<BoneData> bones = new Array(); // Ordered parents first.
|
||||||
|
final Array<SlotData> slots = new Array(); // Bind pose draw order.
|
||||||
|
final Array<Skin> skins = new Array();
|
||||||
|
Skin defaultSkin;
|
||||||
|
final AttachmentResolver attachmentResolver;
|
||||||
|
|
||||||
|
public SkeletonData (AttachmentResolver attachmentResolver) {
|
||||||
|
if (attachmentResolver == null) throw new IllegalArgumentException("attachmentResolver cannot be null.");
|
||||||
|
this.attachmentResolver = attachmentResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear () {
|
||||||
|
bones.clear();
|
||||||
|
slots.clear();
|
||||||
|
skins.clear();
|
||||||
|
defaultSkin = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttachmentResolver getAttachmentResolver () {
|
||||||
|
return attachmentResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Bones.
|
||||||
|
|
||||||
|
public void addBone (BoneData bone) {
|
||||||
|
if (bone == null) throw new IllegalArgumentException("bone cannot be null.");
|
||||||
|
bones.add(bone);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<BoneData> getBones () {
|
||||||
|
return bones;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public BoneData findBone (String boneName) {
|
||||||
|
if (boneName == null) throw new IllegalArgumentException("boneName cannot be null.");
|
||||||
|
Array<BoneData> bones = this.bones;
|
||||||
|
for (int i = 0, n = bones.size; i < n; i++) {
|
||||||
|
BoneData bone = bones.get(i);
|
||||||
|
if (bone.name.equals(boneName)) return bone;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return -1 if the bone was not found. */
|
||||||
|
public int findBoneIndex (String boneName) {
|
||||||
|
if (boneName == null) throw new IllegalArgumentException("boneName cannot be null.");
|
||||||
|
Array<BoneData> bones = this.bones;
|
||||||
|
for (int i = 0, n = bones.size; i < n; i++)
|
||||||
|
if (bones.get(i).name.equals(boneName)) return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Slots.
|
||||||
|
|
||||||
|
public void addSlot (SlotData slot) {
|
||||||
|
if (slot == null) throw new IllegalArgumentException("slot cannot be null.");
|
||||||
|
slots.add(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Array<SlotData> getSlots () {
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public SlotData findSlot (String slotName) {
|
||||||
|
if (slotName == null) throw new IllegalArgumentException("slotName cannot be null.");
|
||||||
|
Array<SlotData> slots = this.slots;
|
||||||
|
for (int i = 0, n = slots.size; i < n; i++) {
|
||||||
|
SlotData slot = slots.get(i);
|
||||||
|
if (slot.name.equals(slotName)) return slot;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return -1 if the bone was not found. */
|
||||||
|
public int findSlotIndex (String slotName) {
|
||||||
|
if (slotName == null) throw new IllegalArgumentException("slotName cannot be null.");
|
||||||
|
Array<SlotData> slots = this.slots;
|
||||||
|
for (int i = 0, n = slots.size; i < n; i++)
|
||||||
|
if (slots.get(i).name.equals(slotName)) return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Skins.
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Skin getDefaultSkin () {
|
||||||
|
return defaultSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param defaultSkin May be null. */
|
||||||
|
public void setDefaultSkin (Skin defaultSkin) {
|
||||||
|
this.defaultSkin = defaultSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSkin (Skin skin) {
|
||||||
|
if (skin == null) throw new IllegalArgumentException("skin cannot be null.");
|
||||||
|
skins.add(skin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Skin findSkin (String skinName) {
|
||||||
|
if (skinName == null) throw new IllegalArgumentException("skinName cannot be null.");
|
||||||
|
for (Skin skin : skins)
|
||||||
|
if (skin.name.equals(skinName)) return skin;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns all skins, including the default skin. */
|
||||||
|
public Array<Skin> getSkins () {
|
||||||
|
return skins;
|
||||||
|
}
|
||||||
|
}
|
||||||
277
spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java
Normal file
277
spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java
Normal file
@ -0,0 +1,277 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Animation.AttachmentTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.ColorTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.CurveTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.RotateTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.ScaleTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.Timeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.TranslateTimeline;
|
||||||
|
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment;
|
||||||
|
import com.esotericsoftware.spine.attachments.RegionSequenceAttachment.Mode;
|
||||||
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
|
import com.esotericsoftware.spine.attachments.TextureAtlasAttachmentResolver;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.Json;
|
||||||
|
import com.badlogic.gdx.utils.ObjectMap.Entry;
|
||||||
|
import com.badlogic.gdx.utils.OrderedMap;
|
||||||
|
import com.badlogic.gdx.utils.SerializationException;
|
||||||
|
|
||||||
|
public class SkeletonJson {
|
||||||
|
static public final String TIMELINE_SCALE = "scale";
|
||||||
|
static public final String TIMELINE_ROTATE = "rotate";
|
||||||
|
static public final String TIMELINE_TRANSLATE = "translate";
|
||||||
|
static public final String TIMELINE_ATTACHMENT = "attachment";
|
||||||
|
static public final String TIMELINE_COLOR = "color";
|
||||||
|
|
||||||
|
static public final String ATTACHMENT_REGION = "region";
|
||||||
|
static public final String ATTACHMENT_REGION_SEQUENCE = "regionSequence";
|
||||||
|
|
||||||
|
private final Json json = new Json();
|
||||||
|
private final AttachmentResolver attachmentResolver;
|
||||||
|
private float scale = 1;
|
||||||
|
|
||||||
|
public SkeletonJson (TextureAtlas atlas) {
|
||||||
|
attachmentResolver = new TextureAtlasAttachmentResolver(atlas);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkeletonJson (AttachmentResolver attachmentResolver) {
|
||||||
|
this.attachmentResolver = attachmentResolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float getScale () {
|
||||||
|
return scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Scales the bones, images, and animations as they are loaded. */
|
||||||
|
public void setScale (float scale) {
|
||||||
|
this.scale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkeletonData readSkeletonData (FileHandle file) {
|
||||||
|
if (file == null) throw new IllegalArgumentException("file cannot be null.");
|
||||||
|
|
||||||
|
SkeletonData skeletonData = new SkeletonData(attachmentResolver);
|
||||||
|
|
||||||
|
OrderedMap<String, ?> root = json.fromJson(OrderedMap.class, file);
|
||||||
|
|
||||||
|
// Bones.
|
||||||
|
for (OrderedMap boneMap : (Array<OrderedMap>)root.get("bones")) {
|
||||||
|
BoneData parent = null;
|
||||||
|
String parentName = (String)boneMap.get("parent");
|
||||||
|
if (parentName != null) {
|
||||||
|
parent = skeletonData.findBone(parentName);
|
||||||
|
if (parent == null) throw new SerializationException("Parent bone not found: " + parentName);
|
||||||
|
}
|
||||||
|
BoneData boneData = new BoneData((String)boneMap.get("name"), parent);
|
||||||
|
boneData.length = getFloat(boneMap, "length", 0) * scale;
|
||||||
|
boneData.x = getFloat(boneMap, "x", 0) * scale;
|
||||||
|
boneData.y = getFloat(boneMap, "y", 0) * scale;
|
||||||
|
boneData.rotation = getFloat(boneMap, "rotation", 0);
|
||||||
|
boneData.scaleX = getFloat(boneMap, "scaleX", 1);
|
||||||
|
boneData.scaleY = getFloat(boneMap, "scaleY", 1);
|
||||||
|
skeletonData.addBone(boneData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slots.
|
||||||
|
Array<OrderedMap> slots = (Array<OrderedMap>)root.get("slots");
|
||||||
|
if (slots != null) {
|
||||||
|
for (OrderedMap slotMap : slots) {
|
||||||
|
String slotName = (String)slotMap.get("name");
|
||||||
|
String boneName = (String)slotMap.get("bone");
|
||||||
|
BoneData boneData = skeletonData.findBone(boneName);
|
||||||
|
if (boneData == null) throw new SerializationException("Slot bone not found: " + boneName);
|
||||||
|
SlotData slotData = new SlotData(slotName, boneData);
|
||||||
|
|
||||||
|
String color = (String)slotMap.get("color");
|
||||||
|
if (color != null) slotData.getColor().set(Color.valueOf(color));
|
||||||
|
|
||||||
|
slotData.setAttachmentName((String)slotMap.get("attachment"));
|
||||||
|
|
||||||
|
skeletonData.addSlot(slotData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skins.
|
||||||
|
OrderedMap<String, OrderedMap> slotMap = (OrderedMap)root.get("skins");
|
||||||
|
if (slotMap != null) {
|
||||||
|
for (Entry<String, OrderedMap> entry : slotMap.entries()) {
|
||||||
|
Skin skin = new Skin(entry.key);
|
||||||
|
for (Entry<String, OrderedMap> slotEntry : ((OrderedMap<String, OrderedMap>)entry.value).entries()) {
|
||||||
|
int slotIndex = skeletonData.findSlotIndex(slotEntry.key);
|
||||||
|
for (Entry<String, OrderedMap> attachmentEntry : ((OrderedMap<String, OrderedMap>)slotEntry.value).entries()) {
|
||||||
|
Attachment attachment = readAttachment(attachmentEntry.key, attachmentEntry.value);
|
||||||
|
skin.addAttachment(slotIndex, attachmentEntry.key, attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
skeletonData.addSkin(skin);
|
||||||
|
if (skin.name.equals("default")) skeletonData.setDefaultSkin(skin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
skeletonData.bones.shrink();
|
||||||
|
skeletonData.slots.shrink();
|
||||||
|
skeletonData.skins.shrink();
|
||||||
|
return skeletonData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Attachment readAttachment (String name, OrderedMap map) {
|
||||||
|
name = (String)map.get("name", name);
|
||||||
|
Attachment attachment;
|
||||||
|
String type = (String)map.get("type");
|
||||||
|
if (type == null) type = ATTACHMENT_REGION;
|
||||||
|
if (type.equals(ATTACHMENT_REGION)) {
|
||||||
|
attachment = new RegionAttachment(name);
|
||||||
|
|
||||||
|
} else if (type.equals(ATTACHMENT_REGION_SEQUENCE)) {
|
||||||
|
Float fps = (Float)map.get("fps");
|
||||||
|
if (fps == null) throw new SerializationException("Region sequence attachment missing fps: " + name);
|
||||||
|
|
||||||
|
String modeString = (String)map.get("mode");
|
||||||
|
Mode mode = modeString == null ? Mode.forward : Mode.valueOf(modeString);
|
||||||
|
|
||||||
|
attachment = new RegionSequenceAttachment(name, 1 / fps, mode);
|
||||||
|
|
||||||
|
} else
|
||||||
|
throw new SerializationException("Unknown attachment type: " + type + " (" + name + ")");
|
||||||
|
|
||||||
|
attachment.setX(getFloat(map, "x", 0) * scale);
|
||||||
|
attachment.setY(getFloat(map, "y", 0) * scale);
|
||||||
|
attachment.setScaleX(getFloat(map, "scaleX", 1));
|
||||||
|
attachment.setScaleY(getFloat(map, "scaleY", 1));
|
||||||
|
attachment.setRotation(getFloat(map, "rotation", 0));
|
||||||
|
attachment.setWidth(getFloat(map, "width", 32) * scale);
|
||||||
|
attachment.setHeight(getFloat(map, "height", 32) * scale);
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float getFloat (OrderedMap map, String name, float defaultValue) {
|
||||||
|
Object value = map.get(name);
|
||||||
|
if (value == null) return defaultValue;
|
||||||
|
return (Float)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Animation readAnimation (FileHandle file, SkeletonData skeletonData) {
|
||||||
|
if (file == null) throw new IllegalArgumentException("file cannot be null.");
|
||||||
|
if (skeletonData == null) throw new IllegalArgumentException("skeletonData cannot be null.");
|
||||||
|
|
||||||
|
OrderedMap<String, ?> map = json.fromJson(OrderedMap.class, file);
|
||||||
|
|
||||||
|
Array<Timeline> timelines = new Array();
|
||||||
|
float duration = 0;
|
||||||
|
|
||||||
|
OrderedMap<String, ?> bonesMap = (OrderedMap)map.get("bones");
|
||||||
|
for (Entry<String, ?> entry : bonesMap.entries()) {
|
||||||
|
String boneName = entry.key;
|
||||||
|
int boneIndex = skeletonData.findBoneIndex(boneName);
|
||||||
|
if (boneIndex == -1) throw new SerializationException("Bone not found: " + boneName);
|
||||||
|
OrderedMap<?, ?> propertyMap = (OrderedMap)entry.value;
|
||||||
|
|
||||||
|
for (Entry propertyEntry : propertyMap.entries()) {
|
||||||
|
Array<OrderedMap> values = (Array)propertyEntry.value;
|
||||||
|
String timelineType = (String)propertyEntry.key;
|
||||||
|
if (timelineType.equals(TIMELINE_ROTATE)) {
|
||||||
|
RotateTimeline timeline = new RotateTimeline(values.size);
|
||||||
|
timeline.setBoneIndex(boneIndex);
|
||||||
|
|
||||||
|
int keyframeIndex = 0;
|
||||||
|
for (OrderedMap valueMap : values) {
|
||||||
|
float time = (Float)valueMap.get("time");
|
||||||
|
timeline.setKeyframe(keyframeIndex, time, (Float)valueMap.get("angle"));
|
||||||
|
readCurve(timeline, keyframeIndex, valueMap);
|
||||||
|
keyframeIndex++;
|
||||||
|
}
|
||||||
|
timelines.add(timeline);
|
||||||
|
duration = Math.max(duration, timeline.getDuration());
|
||||||
|
|
||||||
|
} else if (timelineType.equals(TIMELINE_TRANSLATE) || timelineType.equals(TIMELINE_SCALE)) {
|
||||||
|
TranslateTimeline timeline;
|
||||||
|
float timelineScale = 1;
|
||||||
|
if (timelineType.equals(TIMELINE_SCALE))
|
||||||
|
timeline = new ScaleTimeline(values.size);
|
||||||
|
else {
|
||||||
|
timeline = new TranslateTimeline(values.size);
|
||||||
|
timelineScale = scale;
|
||||||
|
}
|
||||||
|
timeline.setBoneIndex(boneIndex);
|
||||||
|
|
||||||
|
int keyframeIndex = 0;
|
||||||
|
for (OrderedMap valueMap : values) {
|
||||||
|
float time = (Float)valueMap.get("time");
|
||||||
|
Float x = (Float)valueMap.get("x"), y = (Float)valueMap.get("y");
|
||||||
|
timeline.setKeyframe(keyframeIndex, time, x == null ? 0 : (x * timelineScale), y == null ? 0
|
||||||
|
: (y * timelineScale));
|
||||||
|
readCurve(timeline, keyframeIndex, valueMap);
|
||||||
|
keyframeIndex++;
|
||||||
|
}
|
||||||
|
timelines.add(timeline);
|
||||||
|
duration = Math.max(duration, timeline.getDuration());
|
||||||
|
|
||||||
|
} else
|
||||||
|
throw new RuntimeException("Invalid timeline type for a bone: " + timelineType + " (" + boneName + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OrderedMap<String, ?> slotsMap = (OrderedMap)map.get("slots");
|
||||||
|
if (slotsMap != null) {
|
||||||
|
for (Entry<String, ?> entry : slotsMap.entries()) {
|
||||||
|
String slotName = entry.key;
|
||||||
|
int slotIndex = skeletonData.findSlotIndex(slotName);
|
||||||
|
OrderedMap<?, ?> propertyMap = (OrderedMap)entry.value;
|
||||||
|
|
||||||
|
for (Entry propertyEntry : propertyMap.entries()) {
|
||||||
|
Array<OrderedMap> values = (Array)propertyEntry.value;
|
||||||
|
String timelineType = (String)propertyEntry.key;
|
||||||
|
if (timelineType.equals(TIMELINE_COLOR)) {
|
||||||
|
ColorTimeline timeline = new ColorTimeline(values.size);
|
||||||
|
timeline.setSlotIndex(slotIndex);
|
||||||
|
|
||||||
|
int keyframeIndex = 0;
|
||||||
|
for (OrderedMap valueMap : values) {
|
||||||
|
float time = (Float)valueMap.get("time");
|
||||||
|
Color color = Color.valueOf((String)valueMap.get("color"));
|
||||||
|
timeline.setKeyframe(keyframeIndex, time, color.r, color.g, color.b, color.a);
|
||||||
|
readCurve(timeline, keyframeIndex, valueMap);
|
||||||
|
keyframeIndex++;
|
||||||
|
}
|
||||||
|
timelines.add(timeline);
|
||||||
|
duration = Math.max(duration, timeline.getDuration());
|
||||||
|
|
||||||
|
} else if (timelineType.equals(TIMELINE_ATTACHMENT)) {
|
||||||
|
AttachmentTimeline timeline = new AttachmentTimeline(values.size);
|
||||||
|
timeline.setSlotIndex(slotIndex);
|
||||||
|
|
||||||
|
int keyframeIndex = 0;
|
||||||
|
for (OrderedMap valueMap : values) {
|
||||||
|
float time = (Float)valueMap.get("time");
|
||||||
|
timeline.setKeyframe(keyframeIndex++, time, (String)valueMap.get("name"));
|
||||||
|
}
|
||||||
|
timelines.add(timeline);
|
||||||
|
duration = Math.max(duration, timeline.getDuration());
|
||||||
|
|
||||||
|
} else
|
||||||
|
throw new RuntimeException("Invalid timeline type for a slot: " + timelineType + " (" + slotName + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timelines.shrink();
|
||||||
|
return new Animation(timelines, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readCurve (CurveTimeline timeline, int keyframeIndex, OrderedMap valueMap) {
|
||||||
|
Object curveObject = valueMap.get("curve");
|
||||||
|
if (curveObject == null) return;
|
||||||
|
if (curveObject.equals("stepped"))
|
||||||
|
timeline.setStepped(keyframeIndex);
|
||||||
|
else if (curveObject instanceof Array) {
|
||||||
|
Array curve = (Array)curveObject;
|
||||||
|
timeline.setCurve(keyframeIndex, (Float)curve.get(0), (Float)curve.get(1), (Float)curve.get(2), (Float)curve.get(3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
97
spine-libgdx/src/com/esotericsoftware/spine/Skin.java
Normal file
97
spine-libgdx/src/com/esotericsoftware/spine/Skin.java
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.badlogic.gdx.utils.ObjectMap;
|
||||||
|
import com.badlogic.gdx.utils.ObjectMap.Entry;
|
||||||
|
|
||||||
|
/** Stores attachments by slot index and attachment name. */
|
||||||
|
public class Skin {
|
||||||
|
static private final Key lookup = new Key();
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
final ObjectMap<Key, Attachment> attachments = new ObjectMap();
|
||||||
|
|
||||||
|
public Skin (String name) {
|
||||||
|
if (name == null) throw new IllegalArgumentException("name cannot be null.");
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addAttachment (int slotIndex, String name, Attachment attachment) {
|
||||||
|
if (attachment == null) throw new IllegalArgumentException("attachment cannot be null.");
|
||||||
|
Key key = new Key();
|
||||||
|
key.set(slotIndex, name);
|
||||||
|
attachments.put(key, attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Attachment getAttachment (int slotIndex, String name) {
|
||||||
|
lookup.set(slotIndex, name);
|
||||||
|
return attachments.get(lookup);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void findNamesForSlot (int slotIndex, Array<String> names) {
|
||||||
|
if (names == null) throw new IllegalArgumentException("names cannot be null.");
|
||||||
|
for (Key key : attachments.keys())
|
||||||
|
if (key.slotIndex == slotIndex) names.add(key.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void findAttachmentsForSlot (int slotIndex, Array<Attachment> attachments) {
|
||||||
|
if (attachments == null) throw new IllegalArgumentException("attachments cannot be null.");
|
||||||
|
for (Entry<Key, Attachment> entry : this.attachments.entries())
|
||||||
|
if (entry.key.slotIndex == slotIndex) attachments.add(entry.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear () {
|
||||||
|
attachments.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName () {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString () {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Key {
|
||||||
|
int slotIndex;
|
||||||
|
String name;
|
||||||
|
int hashCode;
|
||||||
|
|
||||||
|
public void set (int slotName, String name) {
|
||||||
|
if (name == null) throw new IllegalArgumentException("attachmentName cannot be null.");
|
||||||
|
this.slotIndex = slotName;
|
||||||
|
this.name = name;
|
||||||
|
hashCode = 31 * (31 + name.hashCode()) + slotIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode () {
|
||||||
|
return hashCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals (Object object) {
|
||||||
|
if (object == null) return false;
|
||||||
|
Key other = (Key)object;
|
||||||
|
if (slotIndex != other.slotIndex) return false;
|
||||||
|
if (!name.equals(other.name)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString () {
|
||||||
|
return slotIndex + ":" + name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached. */
|
||||||
|
void attachAll (Skeleton skeleton, Skin oldSkin) {
|
||||||
|
for (Entry<Key, Attachment> entry : oldSkin.attachments.entries()) {
|
||||||
|
int slotIndex = entry.key.slotIndex;
|
||||||
|
Slot slot = skeleton.slots.get(slotIndex);
|
||||||
|
if (slot.attachment == entry.value) {
|
||||||
|
Attachment attachment = getAttachment(slotIndex, entry.key.name);
|
||||||
|
if (attachment != null) slot.setAttachment(attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
93
spine-libgdx/src/com/esotericsoftware/spine/Slot.java
Normal file
93
spine-libgdx/src/com/esotericsoftware/spine/Slot.java
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
|
||||||
|
public class Slot {
|
||||||
|
final SlotData data;
|
||||||
|
final Bone bone;
|
||||||
|
private final Skeleton skeleton;
|
||||||
|
final Color color;
|
||||||
|
Attachment attachment;
|
||||||
|
private float attachmentTime;
|
||||||
|
|
||||||
|
Slot () {
|
||||||
|
data = null;
|
||||||
|
bone = null;
|
||||||
|
skeleton = null;
|
||||||
|
color = new Color(1, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot (SlotData data, Skeleton skeleton, Bone bone) {
|
||||||
|
if (data == null) throw new IllegalArgumentException("data cannot be null.");
|
||||||
|
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
||||||
|
if (bone == null) throw new IllegalArgumentException("bone cannot be null.");
|
||||||
|
this.data = data;
|
||||||
|
this.skeleton = skeleton;
|
||||||
|
this.bone = bone;
|
||||||
|
color = new Color(1, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
public Slot (Slot slot, Skeleton skeleton, Bone bone) {
|
||||||
|
if (slot == null) throw new IllegalArgumentException("slot cannot be null.");
|
||||||
|
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
||||||
|
if (bone == null) throw new IllegalArgumentException("bone cannot be null.");
|
||||||
|
data = slot.data;
|
||||||
|
this.skeleton = skeleton;
|
||||||
|
this.bone = bone;
|
||||||
|
color = new Color(slot.color);
|
||||||
|
attachment = slot.attachment;
|
||||||
|
attachmentTime = slot.attachmentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotData getData () {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Skeleton getSkeleton () {
|
||||||
|
return skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Bone getBone () {
|
||||||
|
return bone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor () {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Attachment getAttachment () {
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the attachment and resets {@link #getAttachmentTime()}.
|
||||||
|
* @param attachment May be null. */
|
||||||
|
public void setAttachment (Attachment attachment) {
|
||||||
|
this.attachment = attachment;
|
||||||
|
attachmentTime = skeleton.time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAttachmentTime (float time) {
|
||||||
|
attachmentTime = skeleton.time - time;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the time since the attachment was set. */
|
||||||
|
public float getAttachmentTime () {
|
||||||
|
return skeleton.time - attachmentTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setToBindPose (int slotIndex) {
|
||||||
|
color.set(data.color);
|
||||||
|
setAttachment(data.attachmentName == null ? null : skeleton.getAttachment(slotIndex, data.attachmentName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setToBindPose () {
|
||||||
|
setToBindPose(skeleton.slots.indexOf(this, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString () {
|
||||||
|
return data.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
49
spine-libgdx/src/com/esotericsoftware/spine/SlotData.java
Normal file
49
spine-libgdx/src/com/esotericsoftware/spine/SlotData.java
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
|
||||||
|
public class SlotData {
|
||||||
|
final String name;
|
||||||
|
final BoneData boneData;
|
||||||
|
final Color color = new Color(1, 1, 1, 1);
|
||||||
|
String attachmentName;
|
||||||
|
|
||||||
|
SlotData () {
|
||||||
|
name = null;
|
||||||
|
boneData = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotData (String name, BoneData boneData) {
|
||||||
|
if (name == null) throw new IllegalArgumentException("name cannot be null.");
|
||||||
|
if (boneData == null) throw new IllegalArgumentException("boneData cannot be null.");
|
||||||
|
this.name = name;
|
||||||
|
this.boneData = boneData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName () {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoneData getBoneData () {
|
||||||
|
return boneData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Color getColor () {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param attachmentName May be null. */
|
||||||
|
public void setAttachmentName (String attachmentName) {
|
||||||
|
this.attachmentName = attachmentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public String getAttachmentName () {
|
||||||
|
return attachmentName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString () {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,153 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine.attachments;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Attachment;
|
||||||
|
import com.esotericsoftware.spine.Bone;
|
||||||
|
import com.esotericsoftware.spine.Slot;
|
||||||
|
|
||||||
|
import static com.badlogic.gdx.graphics.g2d.SpriteBatch.*;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
|
import com.badlogic.gdx.utils.NumberUtils;
|
||||||
|
|
||||||
|
/** Attachment that displays a texture region. */
|
||||||
|
public class RegionAttachment extends Attachment {
|
||||||
|
private TextureRegion region;
|
||||||
|
private final float[] vertices = new float[20];
|
||||||
|
private final float[] offset = new float[8];
|
||||||
|
|
||||||
|
public RegionAttachment (String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateOffset () {
|
||||||
|
float width = getWidth();
|
||||||
|
float height = getHeight();
|
||||||
|
float localX2 = width / 2;
|
||||||
|
float localY2 = height / 2;
|
||||||
|
float localX = -localX2;
|
||||||
|
float localY = -localY2;
|
||||||
|
if (region instanceof AtlasRegion) {
|
||||||
|
AtlasRegion region = (AtlasRegion)this.region;
|
||||||
|
if (region.rotate) {
|
||||||
|
localX += region.offsetX / region.originalWidth * height;
|
||||||
|
localY += region.offsetY / region.originalHeight * width;
|
||||||
|
localX2 -= (region.originalWidth - region.offsetX - region.packedHeight) / region.originalWidth * width;
|
||||||
|
localY2 -= (region.originalHeight - region.offsetY - region.packedWidth) / region.originalHeight * height;
|
||||||
|
} else {
|
||||||
|
localX += region.offsetX / region.originalWidth * width;
|
||||||
|
localY += region.offsetY / region.originalHeight * height;
|
||||||
|
localX2 -= (region.originalWidth - region.offsetX - region.packedWidth) / region.originalWidth * width;
|
||||||
|
localY2 -= (region.originalHeight - region.offsetY - region.packedHeight) / region.originalHeight * height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float scaleX = getScaleX();
|
||||||
|
float scaleY = getScaleY();
|
||||||
|
localX *= scaleX;
|
||||||
|
localY *= scaleY;
|
||||||
|
localX2 *= scaleX;
|
||||||
|
localY2 *= scaleY;
|
||||||
|
float rotation = getRotation();
|
||||||
|
float cos = MathUtils.cosDeg(rotation);
|
||||||
|
float sin = MathUtils.sinDeg(rotation);
|
||||||
|
float x = getX();
|
||||||
|
float y = getY();
|
||||||
|
float localXCos = localX * cos + x;
|
||||||
|
float localXSin = localX * sin;
|
||||||
|
float localYCos = localY * cos + y;
|
||||||
|
float localYSin = localY * sin;
|
||||||
|
float localX2Cos = localX2 * cos + x;
|
||||||
|
float localX2Sin = localX2 * sin;
|
||||||
|
float localY2Cos = localY2 * cos + y;
|
||||||
|
float localY2Sin = localY2 * sin;
|
||||||
|
float[] offset = this.offset;
|
||||||
|
offset[0] = localXCos - localYSin;
|
||||||
|
offset[1] = localYCos + localXSin;
|
||||||
|
offset[2] = localXCos - localY2Sin;
|
||||||
|
offset[3] = localY2Cos + localXSin;
|
||||||
|
offset[4] = localX2Cos - localY2Sin;
|
||||||
|
offset[5] = localY2Cos + localX2Sin;
|
||||||
|
offset[6] = localX2Cos - localYSin;
|
||||||
|
offset[7] = localYCos + localX2Sin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegion (TextureRegion region) {
|
||||||
|
if (region == null) throw new IllegalArgumentException("region cannot be null.");
|
||||||
|
TextureRegion oldRegion = this.region;
|
||||||
|
this.region = region;
|
||||||
|
float[] vertices = this.vertices;
|
||||||
|
if (region instanceof AtlasRegion && ((AtlasRegion)region).rotate) {
|
||||||
|
vertices[U2] = region.getU();
|
||||||
|
vertices[V2] = region.getV2();
|
||||||
|
vertices[U3] = region.getU();
|
||||||
|
vertices[V3] = region.getV();
|
||||||
|
vertices[U4] = region.getU2();
|
||||||
|
vertices[V4] = region.getV();
|
||||||
|
vertices[U1] = region.getU2();
|
||||||
|
vertices[V1] = region.getV2();
|
||||||
|
} else {
|
||||||
|
vertices[U1] = region.getU();
|
||||||
|
vertices[V1] = region.getV2();
|
||||||
|
vertices[U2] = region.getU();
|
||||||
|
vertices[V2] = region.getV();
|
||||||
|
vertices[U3] = region.getU2();
|
||||||
|
vertices[V3] = region.getV();
|
||||||
|
vertices[U4] = region.getU2();
|
||||||
|
vertices[V4] = region.getV2();
|
||||||
|
}
|
||||||
|
updateOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextureRegion getRegion () {
|
||||||
|
if (region == null) throw new IllegalStateException("RegionAttachment is not resolved: " + this);
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw (SpriteBatch batch, Slot slot) {
|
||||||
|
if (region == null) throw new IllegalStateException("RegionAttachment is not resolved: " + this);
|
||||||
|
|
||||||
|
Color skeletonColor = slot.getSkeleton().getColor();
|
||||||
|
Color slotColor = slot.getColor();
|
||||||
|
float color = NumberUtils.intToFloatColor( //
|
||||||
|
((int)(255 * skeletonColor.a * slotColor.a) << 24) //
|
||||||
|
| ((int)(255 * skeletonColor.b * slotColor.b) << 16) //
|
||||||
|
| ((int)(255 * skeletonColor.g * slotColor.g) << 8) //
|
||||||
|
| ((int)(255 * skeletonColor.r * slotColor.r)));
|
||||||
|
float[] vertices = this.vertices;
|
||||||
|
vertices[C1] = color;
|
||||||
|
vertices[C2] = color;
|
||||||
|
vertices[C3] = color;
|
||||||
|
vertices[C4] = color;
|
||||||
|
|
||||||
|
updateWorldVertices(slot.getBone());
|
||||||
|
|
||||||
|
batch.draw(region.getTexture(), vertices, 0, vertices.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateWorldVertices (Bone bone) {
|
||||||
|
float[] vertices = this.vertices;
|
||||||
|
float[] offset = this.offset;
|
||||||
|
float x = bone.getWorldX();
|
||||||
|
float y = bone.getWorldY();
|
||||||
|
float m00 = bone.getM00();
|
||||||
|
float m01 = bone.getM01();
|
||||||
|
float m10 = bone.getM10();
|
||||||
|
float m11 = bone.getM11();
|
||||||
|
vertices[X1] = offset[0] * m00 + offset[1] * m01 + x;
|
||||||
|
vertices[Y1] = offset[0] * m10 + offset[1] * m11 + y;
|
||||||
|
vertices[X2] = offset[2] * m00 + offset[3] * m01 + x;
|
||||||
|
vertices[Y2] = offset[2] * m10 + offset[3] * m11 + y;
|
||||||
|
vertices[X3] = offset[4] * m00 + offset[5] * m01 + x;
|
||||||
|
vertices[Y3] = offset[4] * m10 + offset[5] * m11 + y;
|
||||||
|
vertices[X4] = offset[6] * m00 + offset[7] * m01 + x;
|
||||||
|
vertices[Y4] = offset[6] * m10 + offset[7] * m11 + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float[] getWorldVertices () {
|
||||||
|
return vertices;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine.attachments;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Slot;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureRegion;
|
||||||
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
|
|
||||||
|
/** Attachment that displays various texture regions over time. */
|
||||||
|
public class RegionSequenceAttachment extends RegionAttachment {
|
||||||
|
private final Mode mode;
|
||||||
|
private float frameTime;
|
||||||
|
private TextureRegion[] regions;
|
||||||
|
|
||||||
|
/** @param frameTime Time in seconds each frame is shown. */
|
||||||
|
public RegionSequenceAttachment (String name, float frameTime, Mode mode) {
|
||||||
|
super(name);
|
||||||
|
if (mode == null) throw new IllegalArgumentException("mode cannot be null.");
|
||||||
|
|
||||||
|
this.frameTime = frameTime;
|
||||||
|
this.mode = mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void draw (SpriteBatch batch, Slot slot) {
|
||||||
|
if (regions == null) throw new IllegalStateException("RegionSequenceAttachment is not resolved: " + this);
|
||||||
|
|
||||||
|
int frameIndex = (int)(slot.getAttachmentTime() / frameTime);
|
||||||
|
switch (mode) {
|
||||||
|
case forward:
|
||||||
|
frameIndex = Math.min(regions.length - 1, frameIndex);
|
||||||
|
break;
|
||||||
|
case forwardLoop:
|
||||||
|
frameIndex = frameIndex % regions.length;
|
||||||
|
break;
|
||||||
|
case pingPong:
|
||||||
|
frameIndex = frameIndex % (regions.length * 2);
|
||||||
|
if (frameIndex >= regions.length) frameIndex = regions.length - 1 - (frameIndex - regions.length);
|
||||||
|
break;
|
||||||
|
case random:
|
||||||
|
frameIndex = MathUtils.random(regions.length - 1);
|
||||||
|
break;
|
||||||
|
case backward:
|
||||||
|
frameIndex = Math.max(regions.length - frameIndex - 1, 0);
|
||||||
|
break;
|
||||||
|
case backwardLoop:
|
||||||
|
frameIndex = frameIndex % regions.length;
|
||||||
|
frameIndex = regions.length - frameIndex - 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
setRegion(regions[frameIndex]);
|
||||||
|
super.draw(batch, slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** May be null if the attachment is not resolved. */
|
||||||
|
public TextureRegion[] getRegions () {
|
||||||
|
if (regions == null) throw new IllegalStateException("RegionSequenceAttachment is not resolved: " + this);
|
||||||
|
return regions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRegions (TextureRegion[] regions) {
|
||||||
|
this.regions = regions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static public enum Mode {
|
||||||
|
forward, backward, forwardLoop, backwardLoop, pingPong, random
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine.attachments;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Attachment;
|
||||||
|
import com.esotericsoftware.spine.AttachmentResolver;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
||||||
|
|
||||||
|
public class TextureAtlasAttachmentResolver implements AttachmentResolver {
|
||||||
|
private TextureAtlas atlas;
|
||||||
|
|
||||||
|
public TextureAtlasAttachmentResolver (TextureAtlas atlas) {
|
||||||
|
if (atlas == null) throw new IllegalArgumentException("atlas cannot be null.");
|
||||||
|
this.atlas = atlas;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resolve (Attachment attachment) {
|
||||||
|
if (attachment instanceof RegionAttachment) {
|
||||||
|
AtlasRegion region = atlas.findRegion(attachment.getName());
|
||||||
|
if (region == null) throw new RuntimeException("Region not found in atlas: " + attachment);
|
||||||
|
((RegionAttachment)attachment).setRegion(region);
|
||||||
|
attachment.setResolved(true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException("Unable to resolve attachment of type: " + attachment.getClass().getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
124
spine-libgdx/test/com/esotericsoftware/spine/MixTest.java
Normal file
124
spine-libgdx/test/com/esotericsoftware/spine/MixTest.java
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.ApplicationAdapter;
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.Input.Keys;
|
||||||
|
import com.badlogic.gdx.InputAdapter;
|
||||||
|
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
||||||
|
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.GL10;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
|
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||||
|
|
||||||
|
public class MixTest extends ApplicationAdapter {
|
||||||
|
SpriteBatch batch;
|
||||||
|
float time;
|
||||||
|
ShapeRenderer renderer;
|
||||||
|
|
||||||
|
SkeletonData skeletonData;
|
||||||
|
Skeleton skeleton;
|
||||||
|
Animation walkAnimation;
|
||||||
|
Animation jumpAnimation;
|
||||||
|
|
||||||
|
public void create () {
|
||||||
|
batch = new SpriteBatch();
|
||||||
|
renderer = new ShapeRenderer();
|
||||||
|
|
||||||
|
final String name = "spineboy";
|
||||||
|
|
||||||
|
TextureAtlas atlas = new TextureAtlas(Gdx.files.internal(name + ".atlas"));
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SkeletonJson json = new SkeletonJson(atlas);
|
||||||
|
// json.setScale(2);
|
||||||
|
skeletonData = json.readSkeletonData(Gdx.files.internal(name + "-skeleton.json"));
|
||||||
|
walkAnimation = json.readAnimation(Gdx.files.internal(name + "-walk.json"), skeletonData);
|
||||||
|
jumpAnimation = json.readAnimation(Gdx.files.internal(name + "-jump.json"), skeletonData);
|
||||||
|
} else {
|
||||||
|
SkeletonBinary binary = new SkeletonBinary(atlas);
|
||||||
|
// binary.setScale(2);
|
||||||
|
skeletonData = binary.readSkeletonData(Gdx.files.internal(name + ".skel"));
|
||||||
|
walkAnimation = binary.readAnimation(Gdx.files.internal(name + "-walk.anim"), skeletonData);
|
||||||
|
jumpAnimation = binary.readAnimation(Gdx.files.internal(name + "-jump.anim"), skeletonData);
|
||||||
|
}
|
||||||
|
|
||||||
|
skeleton = new Skeleton(skeletonData);
|
||||||
|
skeleton.setToBindPose();
|
||||||
|
|
||||||
|
final Bone root = skeleton.getRootBone();
|
||||||
|
root.x = -50;
|
||||||
|
root.y = 20;
|
||||||
|
root.scaleX = 1f;
|
||||||
|
root.scaleY = 1f;
|
||||||
|
skeleton.updateWorldTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void render () {
|
||||||
|
float delta = Gdx.graphics.getDeltaTime() * 0.25f; // Reduced to make mixing easier to see.
|
||||||
|
|
||||||
|
float jump = jumpAnimation.getDuration();
|
||||||
|
float beforeJump = 1f;
|
||||||
|
float blendIn = 0.4f;
|
||||||
|
float blendOut = 0.4f;
|
||||||
|
float blendOutStart = beforeJump + jump - blendOut;
|
||||||
|
float total = 3.75f;
|
||||||
|
|
||||||
|
time += delta;
|
||||||
|
|
||||||
|
Bone root = skeleton.getRootBone();
|
||||||
|
float speed = 180;
|
||||||
|
if (time > beforeJump + blendIn && time < blendOutStart) speed = 360;
|
||||||
|
root.setX(root.getX() + speed * delta);
|
||||||
|
|
||||||
|
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
|
||||||
|
batch.begin();
|
||||||
|
batch.setColor(Color.GRAY);
|
||||||
|
|
||||||
|
if (time > total) {
|
||||||
|
// restart
|
||||||
|
time = 0;
|
||||||
|
root.setX(-50);
|
||||||
|
} else if (time > beforeJump + jump) {
|
||||||
|
// just walk after jump
|
||||||
|
walkAnimation.apply(skeleton, time, true);
|
||||||
|
} else if (time > blendOutStart) {
|
||||||
|
// blend out jump
|
||||||
|
walkAnimation.apply(skeleton, time, true);
|
||||||
|
jumpAnimation.mix(skeleton, time - beforeJump, false, 1 - (time - blendOutStart) / blendOut);
|
||||||
|
} else if (time > beforeJump + blendIn) {
|
||||||
|
// just jump
|
||||||
|
jumpAnimation.apply(skeleton, time - beforeJump, false);
|
||||||
|
} else if (time > beforeJump) {
|
||||||
|
// blend in jump
|
||||||
|
walkAnimation.apply(skeleton, time, true);
|
||||||
|
jumpAnimation.mix(skeleton, time - beforeJump, false, (time - beforeJump) / blendIn);
|
||||||
|
} else {
|
||||||
|
// just walk before jump
|
||||||
|
walkAnimation.apply(skeleton, time, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
skeleton.updateWorldTransform();
|
||||||
|
skeleton.update(Gdx.graphics.getDeltaTime());
|
||||||
|
skeleton.draw(batch);
|
||||||
|
|
||||||
|
batch.end();
|
||||||
|
|
||||||
|
// skeleton.drawDebug(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resize (int width, int height) {
|
||||||
|
batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
|
||||||
|
renderer.setProjectionMatrix(batch.getProjectionMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main (String[] args) throws Exception {
|
||||||
|
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
|
||||||
|
config.title = "Mix Test";
|
||||||
|
config.width = 640;
|
||||||
|
config.height = 480;
|
||||||
|
new LwjglApplication(new MixTest(), config);
|
||||||
|
}
|
||||||
|
}
|
||||||
123
spine-libgdx/test/com/esotericsoftware/spine/SkeletonTest.java
Normal file
123
spine-libgdx/test/com/esotericsoftware/spine/SkeletonTest.java
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
|
||||||
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.ApplicationAdapter;
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.Input.Keys;
|
||||||
|
import com.badlogic.gdx.InputAdapter;
|
||||||
|
import com.badlogic.gdx.backends.lwjgl.LwjglApplication;
|
||||||
|
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration;
|
||||||
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
|
import com.badlogic.gdx.graphics.Color;
|
||||||
|
import com.badlogic.gdx.graphics.GL10;
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap;
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap.Format;
|
||||||
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas.TextureAtlasData;
|
||||||
|
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
|
||||||
|
|
||||||
|
public class SkeletonTest extends ApplicationAdapter {
|
||||||
|
SpriteBatch batch;
|
||||||
|
float time;
|
||||||
|
ShapeRenderer renderer;
|
||||||
|
|
||||||
|
SkeletonData skeletonData;
|
||||||
|
Skeleton skeleton;
|
||||||
|
Animation animation;
|
||||||
|
|
||||||
|
public void create () {
|
||||||
|
batch = new SpriteBatch();
|
||||||
|
renderer = new ShapeRenderer();
|
||||||
|
|
||||||
|
final String name = "goblins";
|
||||||
|
|
||||||
|
// A regular texture atlas would normally usually be used. This returns a white image for images not found in the atlas.
|
||||||
|
Pixmap pixmap = new Pixmap(32, 32, Format.RGBA8888);
|
||||||
|
pixmap.setColor(Color.WHITE);
|
||||||
|
pixmap.fill();
|
||||||
|
final AtlasRegion fake = new AtlasRegion(new Texture(pixmap), 0, 0, 32, 32);
|
||||||
|
pixmap.dispose();
|
||||||
|
FileHandle atlasFile = Gdx.files.internal(name + ".atlas");
|
||||||
|
TextureAtlasData data = !atlasFile.exists() ? null : new TextureAtlasData(atlasFile, atlasFile.parent(), false);
|
||||||
|
TextureAtlas atlas = new TextureAtlas(data) {
|
||||||
|
public AtlasRegion findRegion (String name) {
|
||||||
|
AtlasRegion region = super.findRegion(name);
|
||||||
|
return region != null ? region : fake;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (true) {
|
||||||
|
SkeletonJson json = new SkeletonJson(atlas);
|
||||||
|
// json.setScale(2);
|
||||||
|
skeletonData = json.readSkeletonData(Gdx.files.internal(name + "-skeleton.json"));
|
||||||
|
animation = json.readAnimation(Gdx.files.internal(name + "-walk.json"), skeletonData);
|
||||||
|
} else {
|
||||||
|
SkeletonBinary binary = new SkeletonBinary(atlas);
|
||||||
|
// binary.setScale(2);
|
||||||
|
skeletonData = binary.readSkeletonData(Gdx.files.internal(name + ".skel"));
|
||||||
|
animation = binary.readAnimation(Gdx.files.internal(name + "-walk.anim"), skeletonData);
|
||||||
|
}
|
||||||
|
|
||||||
|
skeleton = new Skeleton(skeletonData);
|
||||||
|
if (name.equals("goblins")) skeleton.setSkin("goblin");
|
||||||
|
skeleton.setToBindPose();
|
||||||
|
|
||||||
|
Bone root = skeleton.getRootBone();
|
||||||
|
root.x = 50;
|
||||||
|
root.y = 20;
|
||||||
|
root.scaleX = 1f;
|
||||||
|
root.scaleY = 1f;
|
||||||
|
skeleton.updateWorldTransform();
|
||||||
|
|
||||||
|
Gdx.input.setInputProcessor(new InputAdapter() {
|
||||||
|
public boolean keyDown (int keycode) {
|
||||||
|
if (keycode == Keys.SPACE) {
|
||||||
|
if (name.equals("goblins")) {
|
||||||
|
skeleton.setSkin(skeleton.getSkin().getName().equals("goblin") ? "goblingirl" : "goblin");
|
||||||
|
skeleton.setSlotsToBindPose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void render () {
|
||||||
|
time += Gdx.graphics.getDeltaTime();
|
||||||
|
|
||||||
|
Bone root = skeleton.getRootBone();
|
||||||
|
float x = root.getX() + 160 * Gdx.graphics.getDeltaTime() * (skeleton.getFlipX() ? -1 : 1);
|
||||||
|
if (x > Gdx.graphics.getWidth()) skeleton.setFlipX(true);
|
||||||
|
if (x < 0) skeleton.setFlipX(false);
|
||||||
|
root.setX(x);
|
||||||
|
|
||||||
|
Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
|
||||||
|
batch.begin();
|
||||||
|
batch.setColor(Color.GRAY);
|
||||||
|
|
||||||
|
animation.apply(skeleton, time, true);
|
||||||
|
skeleton.updateWorldTransform();
|
||||||
|
skeleton.update(Gdx.graphics.getDeltaTime());
|
||||||
|
skeleton.draw(batch);
|
||||||
|
|
||||||
|
batch.end();
|
||||||
|
|
||||||
|
skeleton.drawDebug(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resize (int width, int height) {
|
||||||
|
batch.getProjectionMatrix().setToOrtho2D(0, 0, width, height);
|
||||||
|
renderer.setProjectionMatrix(batch.getProjectionMatrix());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main (String[] args) throws Exception {
|
||||||
|
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
|
||||||
|
config.title = "Skeleton Test";
|
||||||
|
config.width = 640;
|
||||||
|
config.height = 480;
|
||||||
|
new LwjglApplication(new SkeletonTest(), config);
|
||||||
|
}
|
||||||
|
}
|
||||||
202
spine-libgdx/test/goblins-skeleton.json
Normal file
202
spine-libgdx/test/goblins-skeleton.json
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
{
|
||||||
|
"bones": [
|
||||||
|
{ "name": "root", "length": 0 },
|
||||||
|
{ "name": "hip", "parent": "root", "length": 0, "x": 0.64, "y": 114.41 },
|
||||||
|
{ "name": "left upper leg", "parent": "hip", "length": 50.39, "x": 14.45, "y": 2.81, "rotation": -89.09 },
|
||||||
|
{ "name": "left lower leg", "parent": "left upper leg", "length": 49.89, "x": 56.34, "y": 0.98, "rotation": -16.65 },
|
||||||
|
{ "name": "left foot", "parent": "left lower leg", "length": 46.5, "x": 58.94, "y": -7.61, "rotation": 102.43 },
|
||||||
|
{ "name": "right upper leg", "parent": "hip", "length": 42.45, "x": -20.07, "y": -6.83, "rotation": -97.49 },
|
||||||
|
{ "name": "right lower leg", "parent": "right upper leg", "length": 58.52, "x": 42.99, "y": -0.61, "rotation": -14.34 },
|
||||||
|
{ "name": "right foot", "parent": "right lower leg", "length": 45.45, "x": 64.88, "y": 0.04, "rotation": 110.3 },
|
||||||
|
{ "name": "torso", "parent": "hip", "length": 85.82, "x": -6.42, "y": 1.97, "rotation": 93.92 },
|
||||||
|
{ "name": "neck", "parent": "torso", "length": 18.38, "x": 81.67, "y": -6.34, "rotation": -1.51 },
|
||||||
|
{ "name": "head", "parent": "neck", "length": 68.28, "x": 20.93, "y": 11.59, "rotation": -13.92 },
|
||||||
|
{ "name": "right shoulder", "parent": "torso", "length": 37.24, "x": 76.02, "y": 18.14, "rotation": 133.88 },
|
||||||
|
{ "name": "right arm", "parent": "right shoulder", "length": 36.74, "x": 37.6, "y": 0.31, "rotation": 36.32 },
|
||||||
|
{ "name": "right hand", "parent": "right arm", "length": 15.32, "x": 36.9, "y": 0.34, "rotation": 2.35 },
|
||||||
|
{ "name": "left shoulder", "parent": "torso", "length": 35.43, "x": 74.04, "y": -20.38, "rotation": -156.96 },
|
||||||
|
{ "name": "left arm", "parent": "left shoulder", "length": 35.62, "x": 37.85, "y": -2.34, "rotation": 28.16 },
|
||||||
|
{ "name": "left hand", "parent": "left arm", "length": 11.52, "x": 35.62, "y": 0.07, "rotation": 2.7 },
|
||||||
|
{ "name": "pelvis", "parent": "hip", "length": 0, "x": 1.41, "y": -6.57 }
|
||||||
|
],
|
||||||
|
"slots": [
|
||||||
|
{ "name": "left shoulder", "bone": "left shoulder", "attachment": "left shoulder" },
|
||||||
|
{ "name": "left arm", "bone": "left arm", "attachment": "left arm" },
|
||||||
|
{ "name": "left hand item", "bone": "left hand", "attachment": "left hand item" },
|
||||||
|
{ "name": "left hand", "bone": "left hand", "attachment": "left hand" },
|
||||||
|
{ "name": "left foot", "bone": "left foot", "attachment": "left foot" },
|
||||||
|
{ "name": "left lower leg", "bone": "left lower leg", "attachment": "left lower leg" },
|
||||||
|
{ "name": "left upper leg", "bone": "left upper leg", "attachment": "left upper leg" },
|
||||||
|
{ "name": "neck", "bone": "neck", "attachment": "neck" },
|
||||||
|
{ "name": "torso", "bone": "torso", "attachment": "torso" },
|
||||||
|
{ "name": "pelvis", "bone": "pelvis", "attachment": "pelvis" },
|
||||||
|
{ "name": "right foot", "bone": "right foot", "attachment": "right foot" },
|
||||||
|
{ "name": "right lower leg", "bone": "right lower leg", "attachment": "right lower leg" },
|
||||||
|
{ "name": "undie straps", "bone": "pelvis", "attachment": "undie straps" },
|
||||||
|
{ "name": "undies", "bone": "pelvis", "attachment": "undies" },
|
||||||
|
{ "name": "right upper leg", "bone": "right upper leg", "attachment": "right upper leg" },
|
||||||
|
{ "name": "head", "bone": "head", "attachment": "head" },
|
||||||
|
{ "name": "eyes", "bone": "head", "attachment": "eyes open" },
|
||||||
|
{ "name": "right shoulder", "bone": "right shoulder", "attachment": "right shoulder" },
|
||||||
|
{ "name": "right arm", "bone": "right arm", "attachment": "right arm" },
|
||||||
|
{ "name": "right hand item 2", "bone": "right hand", "attachment": "right hand item 2" },
|
||||||
|
{ "name": "right hand", "bone": "right hand", "attachment": "right hand" },
|
||||||
|
{ "name": "right hand item", "bone": "right hand", "attachment": "right hand item" }
|
||||||
|
],
|
||||||
|
"skins": {
|
||||||
|
"goblin": {
|
||||||
|
"neck": {
|
||||||
|
"neck": { "name": "goblin/neck", "x": 10.1, "y": 0.42, "rotation": -93.69, "width": 36, "height": 41 }
|
||||||
|
},
|
||||||
|
"undies": {
|
||||||
|
"undies": { "name": "goblin/undies", "x": 6.3, "y": 0.12, "rotation": 0.91, "width": 36, "height": 29 }
|
||||||
|
},
|
||||||
|
"right hand": {
|
||||||
|
"right hand": { "name": "goblin/right-hand", "x": 7.88, "y": 2.78, "rotation": 91.96, "width": 36, "height": 37 }
|
||||||
|
},
|
||||||
|
"right arm": {
|
||||||
|
"right arm": { "name": "goblin/right-arm", "x": 16.44, "y": -1.04, "rotation": 94.32, "width": 23, "height": 50 }
|
||||||
|
},
|
||||||
|
"head": {
|
||||||
|
"head": { "name": "goblin/head", "x": 25.73, "y": 2.33, "rotation": -92.29, "width": 103, "height": 66 }
|
||||||
|
},
|
||||||
|
"left shoulder": {
|
||||||
|
"left shoulder": { "name": "goblin/left-shoulder", "x": 15.56, "y": -2.26, "rotation": 62.01, "width": 29, "height": 44 }
|
||||||
|
},
|
||||||
|
"left arm": {
|
||||||
|
"left arm": {
|
||||||
|
"name": "goblin/left-arm",
|
||||||
|
"x": 16.7,
|
||||||
|
"y": -1.69,
|
||||||
|
"scaleX": 1.057,
|
||||||
|
"scaleY": 1.057,
|
||||||
|
"rotation": 33.84,
|
||||||
|
"width": 37,
|
||||||
|
"height": 35
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"left hand": {
|
||||||
|
"left hand": {
|
||||||
|
"name": "goblin/left-hand",
|
||||||
|
"x": 3.47,
|
||||||
|
"y": 3.41,
|
||||||
|
"scaleX": 0.892,
|
||||||
|
"scaleY": 0.892,
|
||||||
|
"rotation": 31.14,
|
||||||
|
"width": 36,
|
||||||
|
"height": 41
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"right lower leg": {
|
||||||
|
"right lower leg": { "name": "goblin/right-lower-leg", "x": 25.68, "y": -3.15, "rotation": 111.83, "width": 36, "height": 76 }
|
||||||
|
},
|
||||||
|
"right upper leg": {
|
||||||
|
"right upper leg": { "name": "goblin/right-upper-leg", "x": 20.35, "y": 1.47, "rotation": 97.49, "width": 34, "height": 63 }
|
||||||
|
},
|
||||||
|
"pelvis": {
|
||||||
|
"pelvis": { "name": "goblin/pelvis", "x": -5.61, "y": 0.76, "width": 62, "height": 43 }
|
||||||
|
},
|
||||||
|
"left lower leg": {
|
||||||
|
"left lower leg": { "name": "goblin/left-lower-leg", "x": 23.58, "y": -2.06, "rotation": 105.75, "width": 33, "height": 70 }
|
||||||
|
},
|
||||||
|
"left upper leg": {
|
||||||
|
"left upper leg": { "name": "goblin/left-upper-leg", "x": 29.68, "y": -3.87, "rotation": 89.09, "width": 33, "height": 73 }
|
||||||
|
},
|
||||||
|
"torso": {
|
||||||
|
"torso": { "name": "goblin/torso", "x": 38.09, "y": -3.87, "rotation": -94.95, "width": 68, "height": 96 }
|
||||||
|
},
|
||||||
|
"right shoulder": {
|
||||||
|
"right shoulder": { "name": "goblin/right-shoulder", "x": 15.68, "y": -1.03, "rotation": 130.65, "width": 39, "height": 45 }
|
||||||
|
},
|
||||||
|
"right foot": {
|
||||||
|
"right foot": { "name": "goblin/right-foot", "x": 23.56, "y": 9.8, "rotation": 1.52, "width": 63, "height": 33 }
|
||||||
|
},
|
||||||
|
"left foot": {
|
||||||
|
"left foot": { "name": "goblin/left-foot", "x": 24.85, "y": 8.74, "rotation": 3.32, "width": 65, "height": 31 }
|
||||||
|
},
|
||||||
|
"right hand item": {
|
||||||
|
"right hand item": { "name": "goblin/shield", "x": -0.47, "y": 1.1, "rotation": 91.16, "width": 70, "height": 72 }
|
||||||
|
},
|
||||||
|
"left hand item": {
|
||||||
|
"left hand item": { "name": "goblin/spear", "x": -4.55, "y": 39.2, "rotation": 13.04, "width": 22, "height": 368 }
|
||||||
|
},
|
||||||
|
"undie straps": {
|
||||||
|
"undie straps": { "name": "goblin/undie-straps", "x": -3.87, "y": 13.1, "scaleX": 1.089, "width": 55, "height": 19 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"goblingirl": {
|
||||||
|
"left upper leg": {
|
||||||
|
"left upper leg": { "name": "goblingirl/left-upper-leg", "x": 30.21, "y": -2.95, "rotation": 89.09, "width": 33, "height": 70 }
|
||||||
|
},
|
||||||
|
"left lower leg": {
|
||||||
|
"left lower leg": { "name": "goblingirl/left-lower-leg", "x": 25.02, "y": -0.6, "rotation": 105.75, "width": 33, "height": 70 }
|
||||||
|
},
|
||||||
|
"left foot": {
|
||||||
|
"left foot": { "name": "goblingirl/left-foot", "x": 25.17, "y": 7.92, "rotation": 3.32, "width": 65, "height": 31 }
|
||||||
|
},
|
||||||
|
"right upper leg": {
|
||||||
|
"right upper leg": { "name": "goblingirl/right-upper-leg", "x": 19.69, "y": 2.13, "rotation": 97.49, "width": 34, "height": 63 }
|
||||||
|
},
|
||||||
|
"right lower leg": {
|
||||||
|
"right lower leg": { "name": "goblingirl/right-lower-leg", "x": 26.15, "y": -3.27, "rotation": 111.83, "width": 36, "height": 76 }
|
||||||
|
},
|
||||||
|
"right foot": {
|
||||||
|
"right foot": { "name": "goblingirl/right-foot", "x": 23.46, "y": 9.66, "rotation": 1.52, "width": 63, "height": 33 }
|
||||||
|
},
|
||||||
|
"torso": {
|
||||||
|
"torso": { "name": "goblingirl/torso", "x": 36.28, "y": -5.14, "rotation": -95.74, "width": 68, "height": 96 }
|
||||||
|
},
|
||||||
|
"left shoulder": {
|
||||||
|
"left shoulder": { "name": "goblingirl/left-shoulder", "x": 19.8, "y": -0.42, "rotation": 61.21, "width": 28, "height": 46 }
|
||||||
|
},
|
||||||
|
"left arm": {
|
||||||
|
"left arm": { "name": "goblingirl/left-arm", "x": 19.64, "y": -2.42, "rotation": 33.05, "width": 37, "height": 35 }
|
||||||
|
},
|
||||||
|
"left hand": {
|
||||||
|
"left hand": {
|
||||||
|
"name": "goblingirl/left-hand",
|
||||||
|
"x": 4.34,
|
||||||
|
"y": 2.39,
|
||||||
|
"scaleX": 0.896,
|
||||||
|
"scaleY": 0.896,
|
||||||
|
"rotation": 30.34,
|
||||||
|
"width": 35,
|
||||||
|
"height": 40
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"neck": {
|
||||||
|
"neck": { "name": "goblingirl/neck", "x": 6.16, "y": -3.14, "rotation": -98.86, "width": 35, "height": 41 }
|
||||||
|
},
|
||||||
|
"head": {
|
||||||
|
"head": { "name": "goblingirl/head", "x": 27.71, "y": -4.32, "rotation": -85.58, "width": 103, "height": 81 }
|
||||||
|
},
|
||||||
|
"right shoulder": {
|
||||||
|
"right shoulder": { "name": "goblingirl/right-shoulder", "x": 14.46, "y": 0.45, "rotation": 129.85, "width": 39, "height": 45 }
|
||||||
|
},
|
||||||
|
"right arm": {
|
||||||
|
"right arm": { "name": "goblingirl/right-arm", "x": 16.85, "y": -0.66, "rotation": 93.52, "width": 28, "height": 50 }
|
||||||
|
},
|
||||||
|
"right hand": {
|
||||||
|
"right hand": { "name": "goblingirl/right-hand", "x": 7.21, "y": 3.43, "rotation": 91.16, "width": 36, "height": 37 }
|
||||||
|
},
|
||||||
|
"pelvis": {
|
||||||
|
"pelvis": { "name": "goblingirl/pelvis", "x": -3.87, "y": 3.18, "width": 62, "height": 43 }
|
||||||
|
},
|
||||||
|
"undie straps": {
|
||||||
|
"undie straps": { "name": "goblingirl/undie-straps", "x": -1.51, "y": 14.18, "width": 55, "height": 19 }
|
||||||
|
},
|
||||||
|
"undies": {
|
||||||
|
"undies": { "name": "goblingirl/undies", "x": 5.4, "y": 1.7, "width": 36, "height": 29 }
|
||||||
|
},
|
||||||
|
"left hand item": {
|
||||||
|
"left hand item": { "name": "goblingirl/dagger", "x": 7.88, "y": -23.45, "rotation": 10.47, "width": 26, "height": 108 }
|
||||||
|
},
|
||||||
|
"right hand item 2": {
|
||||||
|
"right hand item 2": { "name": "goblingirl/dagger", "x": 7.17, "y": -22.38, "rotation": -5.27, "width": 26, "height": 108 }
|
||||||
|
},
|
||||||
|
"right hand item": {
|
||||||
|
"right hand item": { "name": "goblingirl/dagger-tip", "x": 13.45, "y": 22.07, "rotation": -3.23, "width": 17, "height": 17 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
spine-libgdx/test/goblins-walk.anim
Normal file
BIN
spine-libgdx/test/goblins-walk.anim
Normal file
Binary file not shown.
288
spine-libgdx/test/goblins-walk.json
Normal file
288
spine-libgdx/test/goblins-walk.json
Normal file
@ -0,0 +1,288 @@
|
|||||||
|
{
|
||||||
|
"bones": {
|
||||||
|
"left upper leg": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -26.55 },
|
||||||
|
{ "time": 0.1333, "angle": -8.78 },
|
||||||
|
{ "time": 0.2666, "angle": 9.51 },
|
||||||
|
{ "time": 0.4, "angle": 30.74 },
|
||||||
|
{ "time": 0.5333, "angle": 25.33 },
|
||||||
|
{ "time": 0.6666, "angle": 26.11 },
|
||||||
|
{ "time": 0.8, "angle": -7.7 },
|
||||||
|
{ "time": 0.9333, "angle": -21.19 },
|
||||||
|
{ "time": 1.0666, "angle": -26.55 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": -1.32, "y": 1.7 },
|
||||||
|
{ "time": 0.4, "x": -0.06, "y": 2.42 },
|
||||||
|
{ "time": 1.0666, "x": -1.32, "y": 1.7 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right upper leg": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 42.45 },
|
||||||
|
{ "time": 0.1333, "angle": 52.1 },
|
||||||
|
{ "time": 0.2666, "angle": 8.53 },
|
||||||
|
{ "time": 0.5333, "angle": -16.93 },
|
||||||
|
{ "time": 0.6666, "angle": 1.89 },
|
||||||
|
{
|
||||||
|
"time": 0.8,
|
||||||
|
"angle": 28.06,
|
||||||
|
"curve": [ 0.462, 0.11, 1, 1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.9333,
|
||||||
|
"angle": 58.68,
|
||||||
|
"curve": [ 0.5, 0.02, 1, 1 ]
|
||||||
|
},
|
||||||
|
{ "time": 1.0666, "angle": 42.45 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 6.23, "y": 0 },
|
||||||
|
{ "time": 0.2666, "x": 2.14, "y": 2.4 },
|
||||||
|
{ "time": 0.5333, "x": 2.44, "y": 4.8 },
|
||||||
|
{ "time": 1.0666, "x": 6.23, "y": 0 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left lower leg": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -22.98 },
|
||||||
|
{ "time": 0.1333, "angle": -63.5 },
|
||||||
|
{ "time": 0.2666, "angle": -73.76 },
|
||||||
|
{ "time": 0.5333, "angle": 5.11 },
|
||||||
|
{ "time": 0.6666, "angle": -28.29 },
|
||||||
|
{ "time": 0.8, "angle": 4.08 },
|
||||||
|
{ "time": 0.9333, "angle": 3.53 },
|
||||||
|
{ "time": 1.0666, "angle": -22.98 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0 },
|
||||||
|
{ "time": 0.2666, "x": 2.55, "y": -0.47 },
|
||||||
|
{ "time": 0.5333, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.0666, "x": 0, "y": 0 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left foot": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -3.69 },
|
||||||
|
{ "time": 0.1333, "angle": -10.42 },
|
||||||
|
{ "time": 0.2666, "angle": -5.01 },
|
||||||
|
{ "time": 0.4, "angle": 3.87 },
|
||||||
|
{ "time": 0.5333, "angle": -3.87 },
|
||||||
|
{ "time": 0.6666, "angle": 2.78 },
|
||||||
|
{ "time": 0.8, "angle": 1.68 },
|
||||||
|
{ "time": 0.9333, "angle": -8.54 },
|
||||||
|
{ "time": 1.0666, "angle": -3.69 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right shoulder": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": 5.29,
|
||||||
|
"curve": [ 0.264, 0, 0.75, 1 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.6666, "angle": 6.65 },
|
||||||
|
{ "time": 1.0666, "angle": 5.29 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right arm": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": -4.02,
|
||||||
|
"curve": [ 0.267, 0, 0.804, 0.99 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.6666,
|
||||||
|
"angle": 19.78,
|
||||||
|
"curve": [ 0.307, 0, 0.787, 0.99 ]
|
||||||
|
},
|
||||||
|
{ "time": 1.0666, "angle": -4.02 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right hand": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 8.98 },
|
||||||
|
{ "time": 0.6666, "angle": 0.51 },
|
||||||
|
{ "time": 1.0666, "angle": 8.98 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left shoulder": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": 6.25,
|
||||||
|
"curve": [ 0.339, 0, 0.683, 1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.5333,
|
||||||
|
"angle": -11.78,
|
||||||
|
"curve": [ 0.281, 0, 0.686, 0.99 ]
|
||||||
|
},
|
||||||
|
{ "time": 1.0666, "angle": 6.25 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 1.15, "y": 0.23 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left hand": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": -21.23,
|
||||||
|
"curve": [ 0.295, 0, 0.755, 0.98 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.5333,
|
||||||
|
"angle": -27.28,
|
||||||
|
"curve": [ 0.241, 0, 0.75, 0.97 ]
|
||||||
|
},
|
||||||
|
{ "time": 1.0666, "angle": -21.23 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left arm": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": 28.37,
|
||||||
|
"curve": [ 0.339, 0, 0.683, 1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.5333,
|
||||||
|
"angle": 60.09,
|
||||||
|
"curve": [ 0.281, 0, 0.686, 0.99 ]
|
||||||
|
},
|
||||||
|
{ "time": 1.0666, "angle": 28.37 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"torso": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -10.28 },
|
||||||
|
{
|
||||||
|
"time": 0.1333,
|
||||||
|
"angle": -15.38,
|
||||||
|
"curve": [ 0.545, 0, 0.818, 1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.4,
|
||||||
|
"angle": -9.78,
|
||||||
|
"curve": [ 0.58, 0.17, 0.669, 0.99 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.6666,
|
||||||
|
"angle": -15.75,
|
||||||
|
"curve": [ 0.235, 0.01, 0.795, 1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.9333,
|
||||||
|
"angle": -7.06,
|
||||||
|
"curve": [ 0.209, 0, 0.816, 0.98 ]
|
||||||
|
},
|
||||||
|
{ "time": 1.0666, "angle": -10.28 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": -1.29, "y": 1.68 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right foot": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -5.25 },
|
||||||
|
{ "time": 0.2666, "angle": -1.91 },
|
||||||
|
{ "time": 0.4, "angle": -6.45 },
|
||||||
|
{ "time": 0.5333, "angle": -5.39 },
|
||||||
|
{ "time": 0.8, "angle": -11.68 },
|
||||||
|
{ "time": 0.9333, "angle": 0.46 },
|
||||||
|
{ "time": 1.0666, "angle": -5.25 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right lower leg": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": -3.39,
|
||||||
|
"curve": [ 0.316, 0.01, 0.741, 0.98 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.1333,
|
||||||
|
"angle": -45.53,
|
||||||
|
"curve": [ 0.229, 0, 0.738, 0.97 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.2666, "angle": -4.83 },
|
||||||
|
{ "time": 0.5333, "angle": -19.53 },
|
||||||
|
{ "time": 0.6666, "angle": -64.8 },
|
||||||
|
{
|
||||||
|
"time": 0.8,
|
||||||
|
"angle": -82.56,
|
||||||
|
"curve": [ 0.557, 0.18, 1, 1 ]
|
||||||
|
},
|
||||||
|
{ "time": 1.0666, "angle": -3.39 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.5333, "x": 0, "y": 0 },
|
||||||
|
{ "time": 0.6666, "x": 2.18, "y": 0.21 },
|
||||||
|
{ "time": 1.0666, "x": 0, "y": 0 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hip": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.0666, "angle": 0 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": -4.16 },
|
||||||
|
{
|
||||||
|
"time": 0.1333,
|
||||||
|
"x": 0,
|
||||||
|
"y": -7.05,
|
||||||
|
"curve": [ 0.359, 0.47, 0.646, 0.74 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.4, "x": 0, "y": 6.78 },
|
||||||
|
{ "time": 0.5333, "x": 0, "y": -6.13 },
|
||||||
|
{
|
||||||
|
"time": 0.6666,
|
||||||
|
"x": 0,
|
||||||
|
"y": -7.05,
|
||||||
|
"curve": [ 0.359, 0.47, 0.646, 0.74 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 6.78 },
|
||||||
|
{ "time": 1.0666, "x": 0, "y": -4.16 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"neck": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 3.6 },
|
||||||
|
{ "time": 0.1333, "angle": 17.49 },
|
||||||
|
{ "time": 0.2666, "angle": 6.1 },
|
||||||
|
{ "time": 0.4, "angle": 3.45 },
|
||||||
|
{ "time": 0.5333, "angle": 5.17 },
|
||||||
|
{ "time": 0.6666, "angle": 18.36 },
|
||||||
|
{ "time": 0.8, "angle": 6.09 },
|
||||||
|
{ "time": 0.9333, "angle": 2.28 },
|
||||||
|
{ "time": 1.0666, "angle": 3.6 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"head": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": 3.6,
|
||||||
|
"curve": [ 0, 0, 0.704, 1.17 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.1333, "angle": -0.2 },
|
||||||
|
{ "time": 0.2666, "angle": 6.1 },
|
||||||
|
{ "time": 0.4, "angle": 3.45 },
|
||||||
|
{
|
||||||
|
"time": 0.5333,
|
||||||
|
"angle": 5.17,
|
||||||
|
"curve": [ 0, 0, 0.704, 1.61 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.7, "angle": 1.1 },
|
||||||
|
{ "time": 0.8, "angle": 6.09 },
|
||||||
|
{ "time": 0.9333, "angle": 2.28 },
|
||||||
|
{ "time": 1.0666, "angle": 3.6 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
297
spine-libgdx/test/goblins.atlas
Normal file
297
spine-libgdx/test/goblins.atlas
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
|
||||||
|
goblins.png
|
||||||
|
format: RGBA8888
|
||||||
|
filter: Nearest,Nearest
|
||||||
|
repeat: none
|
||||||
|
goblin/spear
|
||||||
|
rotate: false
|
||||||
|
xy: 1, 123
|
||||||
|
size: 22, 368
|
||||||
|
orig: 22, 368
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/head
|
||||||
|
rotate: false
|
||||||
|
xy: 25, 425
|
||||||
|
size: 103, 66
|
||||||
|
orig: 103, 66
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/torso
|
||||||
|
rotate: false
|
||||||
|
xy: 25, 327
|
||||||
|
size: 68, 96
|
||||||
|
orig: 68, 96
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/shield
|
||||||
|
rotate: false
|
||||||
|
xy: 25, 253
|
||||||
|
size: 70, 72
|
||||||
|
orig: 70, 72
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/right-lower-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 25, 175
|
||||||
|
size: 36, 76
|
||||||
|
orig: 36, 76
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/left-upper-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 95, 350
|
||||||
|
size: 33, 73
|
||||||
|
orig: 33, 73
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/pelvis
|
||||||
|
rotate: false
|
||||||
|
xy: 130, 448
|
||||||
|
size: 62, 43
|
||||||
|
orig: 62, 43
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/left-lower-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 130, 376
|
||||||
|
size: 33, 70
|
||||||
|
orig: 33, 70
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/right-upper-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 63, 188
|
||||||
|
size: 34, 63
|
||||||
|
orig: 34, 63
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/right-shoulder
|
||||||
|
rotate: false
|
||||||
|
xy: 194, 446
|
||||||
|
size: 39, 45
|
||||||
|
orig: 39, 45
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/left-hand
|
||||||
|
rotate: false
|
||||||
|
xy: 25, 132
|
||||||
|
size: 36, 41
|
||||||
|
orig: 36, 41
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/neck
|
||||||
|
rotate: false
|
||||||
|
xy: 63, 145
|
||||||
|
size: 36, 41
|
||||||
|
orig: 36, 41
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/right-arm
|
||||||
|
rotate: false
|
||||||
|
xy: 165, 396
|
||||||
|
size: 23, 50
|
||||||
|
orig: 23, 50
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/left-foot
|
||||||
|
rotate: false
|
||||||
|
xy: 190, 413
|
||||||
|
size: 65, 31
|
||||||
|
orig: 65, 31
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/right-foot
|
||||||
|
rotate: false
|
||||||
|
xy: 190, 378
|
||||||
|
size: 63, 33
|
||||||
|
orig: 63, 33
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/left-shoulder
|
||||||
|
rotate: false
|
||||||
|
xy: 1, 77
|
||||||
|
size: 29, 44
|
||||||
|
orig: 29, 44
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/right-hand
|
||||||
|
rotate: false
|
||||||
|
xy: 1, 38
|
||||||
|
size: 36, 37
|
||||||
|
orig: 36, 37
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/left-arm
|
||||||
|
rotate: false
|
||||||
|
xy: 1, 1
|
||||||
|
size: 37, 35
|
||||||
|
orig: 37, 35
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/undies
|
||||||
|
rotate: false
|
||||||
|
xy: 130, 345
|
||||||
|
size: 36, 29
|
||||||
|
orig: 36, 29
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblin/undie-straps
|
||||||
|
rotate: false
|
||||||
|
xy: 168, 357
|
||||||
|
size: 55, 19
|
||||||
|
orig: 55, 19
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
|
||||||
|
goblins2.png
|
||||||
|
format: RGBA8888
|
||||||
|
filter: Nearest,Nearest
|
||||||
|
repeat: none
|
||||||
|
goblingirl/goblingirl
|
||||||
|
rotate: false
|
||||||
|
xy: 1, 217
|
||||||
|
size: 148, 294
|
||||||
|
orig: 148, 294
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/head
|
||||||
|
rotate: false
|
||||||
|
xy: 1, 134
|
||||||
|
size: 103, 81
|
||||||
|
orig: 103, 81
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/torso
|
||||||
|
rotate: false
|
||||||
|
xy: 151, 415
|
||||||
|
size: 68, 96
|
||||||
|
orig: 68, 96
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/right-upper-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 221, 448
|
||||||
|
size: 34, 63
|
||||||
|
orig: 34, 63
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/dagger
|
||||||
|
rotate: false
|
||||||
|
xy: 1, 24
|
||||||
|
size: 26, 108
|
||||||
|
orig: 26, 108
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/right-lower-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 106, 139
|
||||||
|
size: 36, 76
|
||||||
|
orig: 36, 76
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/pelvis
|
||||||
|
rotate: false
|
||||||
|
xy: 151, 370
|
||||||
|
size: 62, 43
|
||||||
|
orig: 62, 43
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/left-lower-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 29, 62
|
||||||
|
size: 33, 70
|
||||||
|
orig: 33, 70
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/left-upper-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 151, 298
|
||||||
|
size: 33, 70
|
||||||
|
orig: 33, 70
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/right-shoulder
|
||||||
|
rotate: false
|
||||||
|
xy: 64, 87
|
||||||
|
size: 39, 45
|
||||||
|
orig: 39, 45
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/right-arm
|
||||||
|
rotate: false
|
||||||
|
xy: 151, 246
|
||||||
|
size: 28, 50
|
||||||
|
orig: 28, 50
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/left-shoulder
|
||||||
|
rotate: false
|
||||||
|
xy: 186, 322
|
||||||
|
size: 28, 46
|
||||||
|
orig: 28, 46
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/left-hand
|
||||||
|
rotate: false
|
||||||
|
xy: 29, 20
|
||||||
|
size: 35, 40
|
||||||
|
orig: 35, 40
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/undie-straps
|
||||||
|
rotate: false
|
||||||
|
xy: 64, 66
|
||||||
|
size: 55, 19
|
||||||
|
orig: 55, 19
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/right-foot
|
||||||
|
rotate: false
|
||||||
|
xy: 66, 31
|
||||||
|
size: 63, 33
|
||||||
|
orig: 63, 33
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/left-arm
|
||||||
|
rotate: false
|
||||||
|
xy: 151, 209
|
||||||
|
size: 37, 35
|
||||||
|
orig: 37, 35
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/neck
|
||||||
|
rotate: false
|
||||||
|
xy: 144, 166
|
||||||
|
size: 35, 41
|
||||||
|
orig: 35, 41
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/left-foot
|
||||||
|
rotate: false
|
||||||
|
xy: 144, 133
|
||||||
|
size: 65, 31
|
||||||
|
orig: 65, 31
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/right-hand
|
||||||
|
rotate: false
|
||||||
|
xy: 186, 283
|
||||||
|
size: 36, 37
|
||||||
|
orig: 36, 37
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/undies
|
||||||
|
rotate: false
|
||||||
|
xy: 181, 252
|
||||||
|
size: 36, 29
|
||||||
|
orig: 36, 29
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
goblingirl/dagger-tip
|
||||||
|
rotate: false
|
||||||
|
xy: 1, 1
|
||||||
|
size: 17, 17
|
||||||
|
orig: 17, 17
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
BIN
spine-libgdx/test/goblins.png
Normal file
BIN
spine-libgdx/test/goblins.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 87 KiB |
BIN
spine-libgdx/test/goblins.skel
Normal file
BIN
spine-libgdx/test/goblins.skel
Normal file
Binary file not shown.
BIN
spine-libgdx/test/goblins2.png
Normal file
BIN
spine-libgdx/test/goblins2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
BIN
spine-libgdx/test/spineboy-jump.anim
Normal file
BIN
spine-libgdx/test/spineboy-jump.anim
Normal file
Binary file not shown.
410
spine-libgdx/test/spineboy-jump.json
Normal file
410
spine-libgdx/test/spineboy-jump.json
Normal file
@ -0,0 +1,410 @@
|
|||||||
|
{
|
||||||
|
"bones": {
|
||||||
|
"hip": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "angle": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "angle": 0 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": -11.57, "y": -3 },
|
||||||
|
{ "time": 0.2333, "x": -16.2, "y": -19.43 },
|
||||||
|
{
|
||||||
|
"time": 0.3333,
|
||||||
|
"x": 7.66,
|
||||||
|
"y": -8.48,
|
||||||
|
"curve": [ 0.057, 0.06, 0.712, 1 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.3666, "x": 15.38, "y": 5.01 },
|
||||||
|
{ "time": 0.4666, "x": -7.84, "y": 57.22 },
|
||||||
|
{
|
||||||
|
"time": 0.6,
|
||||||
|
"x": -10.81,
|
||||||
|
"y": 96.34,
|
||||||
|
"curve": [ 0.241, 0, 1, 1 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.7333, "x": -7.01, "y": 54.7 },
|
||||||
|
{ "time": 0.8, "x": -10.58, "y": 32.2 },
|
||||||
|
{ "time": 0.9333, "x": -31.99, "y": 0.45 },
|
||||||
|
{ "time": 1.0666, "x": -12.48, "y": -29.47 },
|
||||||
|
{ "time": 1.3666, "x": -11.57, "y": -3 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left upper leg": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 17.13 },
|
||||||
|
{ "time": 0.2333, "angle": 44.35 },
|
||||||
|
{ "time": 0.3333, "angle": 16.46 },
|
||||||
|
{ "time": 0.4, "angle": -9.88 },
|
||||||
|
{ "time": 0.4666, "angle": -11.42 },
|
||||||
|
{ "time": 0.5666, "angle": 23.46 },
|
||||||
|
{ "time": 0.7666, "angle": 71.82 },
|
||||||
|
{ "time": 0.9333, "angle": 65.53 },
|
||||||
|
{ "time": 1.0666, "angle": 51.01 },
|
||||||
|
{ "time": 1.3666, "angle": 17.13 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": -3, "y": -2.25, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": -3, "y": -2.25, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": -3, "y": -2.25 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left lower leg": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -16.25 },
|
||||||
|
{ "time": 0.2333, "angle": -52.21 },
|
||||||
|
{ "time": 0.4, "angle": 15.04 },
|
||||||
|
{ "time": 0.4666, "angle": -8.95 },
|
||||||
|
{ "time": 0.5666, "angle": -39.53 },
|
||||||
|
{ "time": 0.7666, "angle": -27.27 },
|
||||||
|
{ "time": 0.9333, "angle": -3.52 },
|
||||||
|
{ "time": 1.0666, "angle": -61.92 },
|
||||||
|
{ "time": 1.3666, "angle": -16.25 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 0, "y": 0 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left foot": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 0.33 },
|
||||||
|
{ "time": 0.2333, "angle": 6.2 },
|
||||||
|
{ "time": 0.3333, "angle": 14.73 },
|
||||||
|
{ "time": 0.4, "angle": -15.54 },
|
||||||
|
{ "time": 0.4333, "angle": -21.2 },
|
||||||
|
{ "time": 0.5666, "angle": -7.55 },
|
||||||
|
{ "time": 0.7666, "angle": -0.67 },
|
||||||
|
{ "time": 0.9333, "angle": -0.58 },
|
||||||
|
{ "time": 1.0666, "angle": 14.64 },
|
||||||
|
{ "time": 1.3666, "angle": 0.33 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 0, "y": 0 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right upper leg": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 25.97 },
|
||||||
|
{ "time": 0.2333, "angle": 46.43 },
|
||||||
|
{ "time": 0.3333, "angle": 22.61 },
|
||||||
|
{ "time": 0.4, "angle": 2.13 },
|
||||||
|
{
|
||||||
|
"time": 0.4666,
|
||||||
|
"angle": 0.04,
|
||||||
|
"curve": [ 0, 0, 0.637, 0.98 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.6, "angle": 65.55 },
|
||||||
|
{ "time": 0.7666, "angle": 64.93 },
|
||||||
|
{ "time": 0.9333, "angle": 41.08 },
|
||||||
|
{ "time": 1.0666, "angle": 66.25 },
|
||||||
|
{ "time": 1.3666, "angle": 25.97 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 5.74, "y": 0.61 },
|
||||||
|
{ "time": 0.2333, "x": 4.79, "y": 1.79 },
|
||||||
|
{ "time": 0.3333, "x": 6.05, "y": -4.55 },
|
||||||
|
{ "time": 0.9333, "x": 4.79, "y": 1.79, "curve": "stepped" },
|
||||||
|
{ "time": 1.0666, "x": 4.79, "y": 1.79 },
|
||||||
|
{ "time": 1.3666, "x": 5.74, "y": 0.61 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right lower leg": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -27.46 },
|
||||||
|
{ "time": 0.2333, "angle": -64.03 },
|
||||||
|
{ "time": 0.4, "angle": -48.36 },
|
||||||
|
{ "time": 0.5666, "angle": -76.86 },
|
||||||
|
{ "time": 0.7666, "angle": -26.89 },
|
||||||
|
{ "time": 0.9, "angle": -18.97 },
|
||||||
|
{ "time": 0.9333, "angle": -14.18 },
|
||||||
|
{ "time": 1.0666, "angle": -80.45 },
|
||||||
|
{ "time": 1.3666, "angle": -27.46 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 0, "y": 0 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right foot": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 1.08 },
|
||||||
|
{ "time": 0.2333, "angle": 16.02 },
|
||||||
|
{ "time": 0.3, "angle": 12.94 },
|
||||||
|
{ "time": 0.3333, "angle": 15.16 },
|
||||||
|
{ "time": 0.4, "angle": -14.7 },
|
||||||
|
{ "time": 0.4333, "angle": -12.85 },
|
||||||
|
{ "time": 0.4666, "angle": -19.18 },
|
||||||
|
{ "time": 0.5666, "angle": -15.82 },
|
||||||
|
{ "time": 0.6, "angle": -3.59 },
|
||||||
|
{ "time": 0.7666, "angle": -3.56 },
|
||||||
|
{ "time": 0.9333, "angle": 1.86 },
|
||||||
|
{ "time": 1.0666, "angle": 16.02 },
|
||||||
|
{ "time": 1.3666, "angle": 1.08 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 0, "y": 0 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"torso": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -13.35 },
|
||||||
|
{ "time": 0.2333, "angle": -48.95 },
|
||||||
|
{ "time": 0.4333, "angle": -35.77 },
|
||||||
|
{ "time": 0.6, "angle": -4.59 },
|
||||||
|
{ "time": 0.7666, "angle": 14.61 },
|
||||||
|
{ "time": 0.9333, "angle": 15.74 },
|
||||||
|
{ "time": 1.0666, "angle": -32.44 },
|
||||||
|
{ "time": 1.3666, "angle": -13.35 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": -3.67, "y": 1.68, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": -3.67, "y": 1.68, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": -3.67, "y": 1.68 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"neck": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 12.78 },
|
||||||
|
{ "time": 0.2333, "angle": 16.46 },
|
||||||
|
{ "time": 0.4, "angle": 26.49 },
|
||||||
|
{ "time": 0.6, "angle": 15.51 },
|
||||||
|
{ "time": 0.7666, "angle": 1.34 },
|
||||||
|
{ "time": 0.9333, "angle": 2.35 },
|
||||||
|
{ "time": 1.0666, "angle": 6.08 },
|
||||||
|
{ "time": 1.3, "angle": 21.23 },
|
||||||
|
{ "time": 1.3666, "angle": 12.78 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 0, "y": 0 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"head": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 5.19 },
|
||||||
|
{ "time": 0.2333, "angle": 20.27 },
|
||||||
|
{ "time": 0.4, "angle": 15.27 },
|
||||||
|
{ "time": 0.6, "angle": -24.69 },
|
||||||
|
{ "time": 0.7666, "angle": -11.02 },
|
||||||
|
{ "time": 0.9333, "angle": -24.38 },
|
||||||
|
{ "time": 1.0666, "angle": 11.99 },
|
||||||
|
{ "time": 1.3, "angle": 4.86 },
|
||||||
|
{ "time": 1.3666, "angle": 5.19 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 0, "y": 0 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left shoulder": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": 0.05,
|
||||||
|
"curve": [ 0, 0, 0.62, 1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.2333,
|
||||||
|
"angle": 279.66,
|
||||||
|
"curve": [ 0.218, 0.67, 0.66, 0.99 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.5,
|
||||||
|
"angle": 62.27,
|
||||||
|
"curve": [ 0.462, 0, 0.764, 0.58 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.9333, "angle": 28.91 },
|
||||||
|
{ "time": 1.0666, "angle": -8.62 },
|
||||||
|
{ "time": 1.1666, "angle": -18.43 },
|
||||||
|
{ "time": 1.3666, "angle": 0.05 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": -1.76, "y": 0.56, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": -1.76, "y": 0.56, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": -1.76, "y": 0.56 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left hand": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 11.58, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "angle": 11.58, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "angle": 11.58 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 0, "y": 0 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left arm": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 0.51 },
|
||||||
|
{ "time": 0.4333, "angle": 12.82 },
|
||||||
|
{ "time": 0.6, "angle": 47.55 },
|
||||||
|
{ "time": 0.9333, "angle": 12.82 },
|
||||||
|
{ "time": 1.1666, "angle": -6.5 },
|
||||||
|
{ "time": 1.3666, "angle": 0.51 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 0, "y": 0 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right shoulder": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": 43.82,
|
||||||
|
"curve": [ 0, 0, 0.62, 1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.2333,
|
||||||
|
"angle": -8.74,
|
||||||
|
"curve": [ 0.304, 0.58, 0.709, 0.97 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.5333,
|
||||||
|
"angle": -208.02,
|
||||||
|
"curve": [ 0.462, 0, 0.764, 0.58 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.9333, "angle": -246.72 },
|
||||||
|
{ "time": 1.0666, "angle": -307.13 },
|
||||||
|
{ "time": 1.1666, "angle": 37.15 },
|
||||||
|
{ "time": 1.3666, "angle": 43.82 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": -7.84, "y": 7.19, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": -7.84, "y": 7.19, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": -7.84, "y": 7.19 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right arm": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -4.02 },
|
||||||
|
{ "time": 0.6, "angle": 17.5 },
|
||||||
|
{ "time": 0.9333, "angle": -4.02 },
|
||||||
|
{ "time": 1.1666, "angle": -16.72 },
|
||||||
|
{ "time": 1.3666, "angle": -4.02 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 0, "y": 0 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right hand": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 22.92, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "angle": 22.92, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "angle": 22.92 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 0, "y": 0 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 0.9333, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 0 },
|
||||||
|
{ "time": 0.4333, "angle": -14.52 },
|
||||||
|
{ "time": 0.8, "angle": 9.86 },
|
||||||
|
{ "time": 1.3666, "angle": 0 }
|
||||||
|
],
|
||||||
|
"scale": [
|
||||||
|
{ "time": 0, "x": 1, "y": 1, "curve": "stepped" },
|
||||||
|
{ "time": 1.3666, "x": 1, "y": 1 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
101
spine-libgdx/test/spineboy-skeleton.json
Normal file
101
spine-libgdx/test/spineboy-skeleton.json
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
{
|
||||||
|
"bones": [
|
||||||
|
{ "name": "root", "length": 0 },
|
||||||
|
{ "name": "hip", "parent": "root", "length": 0, "x": 0.64, "y": 114.41 },
|
||||||
|
{ "name": "left upper leg", "parent": "hip", "length": 50.39, "x": 14.45, "y": 2.81, "rotation": -89.09 },
|
||||||
|
{ "name": "left lower leg", "parent": "left upper leg", "length": 56.45, "x": 51.78, "y": 3.46, "rotation": -16.65 },
|
||||||
|
{ "name": "left foot", "parent": "left lower leg", "length": 46.5, "x": 64.02, "y": -8.67, "rotation": 102.43 },
|
||||||
|
{ "name": "right upper leg", "parent": "hip", "length": 45.76, "x": -18.27, "rotation": -101.13 },
|
||||||
|
{ "name": "right lower leg", "parent": "right upper leg", "length": 58.52, "x": 50.21, "y": 0.6, "rotation": -10.7 },
|
||||||
|
{ "name": "right foot", "parent": "right lower leg", "length": 45.45, "x": 64.88, "y": 0.04, "rotation": 110.3 },
|
||||||
|
{ "name": "torso", "parent": "hip", "length": 85.82, "x": -6.42, "y": 1.97, "rotation": 94.95 },
|
||||||
|
{ "name": "neck", "parent": "torso", "length": 18.38, "x": 83.64, "y": -1.78, "rotation": 0.9 },
|
||||||
|
{ "name": "head", "parent": "neck", "length": 68.28, "x": 19.09, "y": 6.97, "rotation": -8.94 },
|
||||||
|
{ "name": "right shoulder", "parent": "torso", "length": 49.95, "x": 81.9, "y": 6.79, "rotation": 130.6 },
|
||||||
|
{ "name": "right arm", "parent": "right shoulder", "length": 36.74, "x": 49.95, "y": -0.12, "rotation": 40.12 },
|
||||||
|
{ "name": "right hand", "parent": "right arm", "length": 15.32, "x": 36.9, "y": 0.34, "rotation": 2.35 },
|
||||||
|
{ "name": "left shoulder", "parent": "torso", "length": 44.19, "x": 78.96, "y": -15.75, "rotation": -156.96 },
|
||||||
|
{ "name": "left arm", "parent": "left shoulder", "length": 35.62, "x": 44.19, "y": -0.01, "rotation": 28.16 },
|
||||||
|
{ "name": "left hand", "parent": "left arm", "length": 11.52, "x": 35.62, "y": 0.07, "rotation": 2.7 },
|
||||||
|
{ "name": "pelvis", "parent": "hip", "length": 0, "x": 1.41, "y": -6.57 }
|
||||||
|
],
|
||||||
|
"slots": [
|
||||||
|
{ "name": "template", "bone": "root", "color": "ff898c86" },
|
||||||
|
{ "name": "left shoulder", "bone": "left shoulder", "attachment": "left-shoulder" },
|
||||||
|
{ "name": "left arm", "bone": "left arm", "attachment": "left-arm" },
|
||||||
|
{ "name": "left hand", "bone": "left hand", "attachment": "left-hand" },
|
||||||
|
{ "name": "left foot", "bone": "left foot", "attachment": "left-foot" },
|
||||||
|
{ "name": "left lower leg", "bone": "left lower leg", "attachment": "left-lower-leg" },
|
||||||
|
{ "name": "left upper leg", "bone": "left upper leg", "attachment": "left-upper-leg" },
|
||||||
|
{ "name": "pelvis", "bone": "pelvis", "attachment": "pelvis" },
|
||||||
|
{ "name": "right foot", "bone": "right foot", "attachment": "right-foot" },
|
||||||
|
{ "name": "right lower leg", "bone": "right lower leg", "attachment": "right-lower-leg" },
|
||||||
|
{ "name": "right upper leg", "bone": "right upper leg", "attachment": "right-upper-leg" },
|
||||||
|
{ "name": "torso", "bone": "torso", "attachment": "torso" },
|
||||||
|
{ "name": "neck", "bone": "neck", "attachment": "neck" },
|
||||||
|
{ "name": "head", "bone": "head", "attachment": "head" },
|
||||||
|
{ "name": "eyes", "bone": "head", "attachment": "eyes" },
|
||||||
|
{ "name": "right shoulder", "bone": "right shoulder", "attachment": "right-shoulder" },
|
||||||
|
{ "name": "right arm", "bone": "right arm", "attachment": "right-arm" },
|
||||||
|
{ "name": "right hand", "bone": "right hand", "attachment": "right-hand" }
|
||||||
|
],
|
||||||
|
"skins": {
|
||||||
|
"default": {
|
||||||
|
"template": {
|
||||||
|
"spineboy": { "y": 167.82, "width": 145, "height": 341 }
|
||||||
|
},
|
||||||
|
"left shoulder": {
|
||||||
|
"left-shoulder": { "x": 23.74, "y": 0.11, "rotation": 62.01, "width": 34, "height": 53 }
|
||||||
|
},
|
||||||
|
"left arm": {
|
||||||
|
"left-arm": { "x": 15.11, "y": -0.44, "rotation": 33.84, "width": 35, "height": 29 }
|
||||||
|
},
|
||||||
|
"left hand": {
|
||||||
|
"left-hand": { "x": 0.75, "y": 1.86, "rotation": 31.14, "width": 35, "height": 38 }
|
||||||
|
},
|
||||||
|
"left foot": {
|
||||||
|
"left-foot": { "x": 24.35, "y": 8.88, "rotation": 3.32, "width": 65, "height": 30 }
|
||||||
|
},
|
||||||
|
"left lower leg": {
|
||||||
|
"left-lower-leg": { "x": 24.55, "y": -1.92, "rotation": 105.75, "width": 49, "height": 64 }
|
||||||
|
},
|
||||||
|
"left upper leg": {
|
||||||
|
"left-upper-leg": { "x": 26.12, "y": -1.85, "rotation": 89.09, "width": 33, "height": 67 }
|
||||||
|
},
|
||||||
|
"pelvis": {
|
||||||
|
"pelvis": { "x": -4.83, "y": 10.62, "width": 63, "height": 47 }
|
||||||
|
},
|
||||||
|
"right foot": {
|
||||||
|
"right-foot": { "x": 19.02, "y": 8.47, "rotation": 1.52, "width": 67, "height": 30 }
|
||||||
|
},
|
||||||
|
"right lower leg": {
|
||||||
|
"right-lower-leg": { "x": 23.28, "y": -2.59, "rotation": 111.83, "width": 51, "height": 64 }
|
||||||
|
},
|
||||||
|
"right upper leg": {
|
||||||
|
"right-upper-leg": { "x": 23.03, "y": 0.25, "rotation": 101.13, "width": 44, "height": 70 }
|
||||||
|
},
|
||||||
|
"torso": {
|
||||||
|
"torso": { "x": 44.57, "y": -7.08, "rotation": -94.95, "width": 68, "height": 92 }
|
||||||
|
},
|
||||||
|
"neck": {
|
||||||
|
"neck": { "x": 9.42, "y": -3.66, "rotation": -100.15, "width": 34, "height": 28 }
|
||||||
|
},
|
||||||
|
"head": {
|
||||||
|
"head": { "x": 53.94, "y": -5.75, "rotation": -86.9, "width": 121, "height": 132 }
|
||||||
|
},
|
||||||
|
"eyes": {
|
||||||
|
"eyes": { "x": 28.94, "y": -32.92, "rotation": -86.9, "width": 34, "height": 27 },
|
||||||
|
"eyes-closed": { "x": 28.77, "y": -32.86, "rotation": -86.9, "width": 34, "height": 27 }
|
||||||
|
},
|
||||||
|
"right shoulder": {
|
||||||
|
"right-shoulder": { "x": 25.86, "y": 0.03, "rotation": 134.44, "width": 52, "height": 51 }
|
||||||
|
},
|
||||||
|
"right arm": {
|
||||||
|
"right-arm": { "x": 18.34, "y": -2.64, "rotation": 94.32, "width": 21, "height": 45 }
|
||||||
|
},
|
||||||
|
"right hand": {
|
||||||
|
"right-hand": { "x": 6.82, "y": 1.25, "rotation": 91.96, "width": 32, "height": 32 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
spine-libgdx/test/spineboy-walk.anim
Normal file
BIN
spine-libgdx/test/spineboy-walk.anim
Normal file
Binary file not shown.
278
spine-libgdx/test/spineboy-walk.json
Normal file
278
spine-libgdx/test/spineboy-walk.json
Normal file
@ -0,0 +1,278 @@
|
|||||||
|
{
|
||||||
|
"bones": {
|
||||||
|
"left upper leg": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -26.55 },
|
||||||
|
{ "time": 0.1333, "angle": -8.78 },
|
||||||
|
{ "time": 0.2666, "angle": 9.51 },
|
||||||
|
{ "time": 0.4, "angle": 30.74 },
|
||||||
|
{ "time": 0.5333, "angle": 25.33 },
|
||||||
|
{ "time": 0.6666, "angle": 26.11 },
|
||||||
|
{ "time": 0.8, "angle": -7.7 },
|
||||||
|
{ "time": 0.9333, "angle": -21.19 },
|
||||||
|
{ "time": 1.0666, "angle": -26.55 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": -3, "y": -2.25 },
|
||||||
|
{ "time": 0.4, "x": -2.18, "y": -2.25 },
|
||||||
|
{ "time": 1.0666, "x": -3, "y": -2.25 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right upper leg": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 42.45 },
|
||||||
|
{ "time": 0.1333, "angle": 52.1 },
|
||||||
|
{ "time": 0.2666, "angle": 5.96 },
|
||||||
|
{ "time": 0.5333, "angle": -16.93 },
|
||||||
|
{ "time": 0.6666, "angle": 1.89 },
|
||||||
|
{
|
||||||
|
"time": 0.8,
|
||||||
|
"angle": 28.06,
|
||||||
|
"curve": [ 0.462, 0.11, 1, 1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.9333,
|
||||||
|
"angle": 58.68,
|
||||||
|
"curve": [ 0.5, 0.02, 1, 1 ]
|
||||||
|
},
|
||||||
|
{ "time": 1.0666, "angle": 42.45 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 8.11, "y": -2.36 },
|
||||||
|
{ "time": 0.1333, "x": 10.03, "y": -2.56 },
|
||||||
|
{ "time": 0.4, "x": 2.76, "y": -2.97 },
|
||||||
|
{ "time": 0.5333, "x": 2.76, "y": -2.81 },
|
||||||
|
{ "time": 0.9333, "x": 8.67, "y": -2.54 },
|
||||||
|
{ "time": 1.0666, "x": 8.11, "y": -2.36 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left lower leg": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -10.21 },
|
||||||
|
{ "time": 0.1333, "angle": -55.64 },
|
||||||
|
{ "time": 0.2666, "angle": -68.12 },
|
||||||
|
{ "time": 0.5333, "angle": 5.11 },
|
||||||
|
{ "time": 0.6666, "angle": -28.29 },
|
||||||
|
{ "time": 0.8, "angle": 4.08 },
|
||||||
|
{ "time": 0.9333, "angle": 3.53 },
|
||||||
|
{ "time": 1.0666, "angle": -10.21 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left foot": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -3.69 },
|
||||||
|
{ "time": 0.1333, "angle": -10.42 },
|
||||||
|
{ "time": 0.2666, "angle": -17.14 },
|
||||||
|
{ "time": 0.4, "angle": -2.83 },
|
||||||
|
{ "time": 0.5333, "angle": -3.87 },
|
||||||
|
{ "time": 0.6666, "angle": 2.78 },
|
||||||
|
{ "time": 0.8, "angle": 1.68 },
|
||||||
|
{ "time": 0.9333, "angle": -8.54 },
|
||||||
|
{ "time": 1.0666, "angle": -3.69 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right shoulder": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": 20.89,
|
||||||
|
"curve": [ 0.264, 0, 0.75, 1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.1333,
|
||||||
|
"angle": 3.72,
|
||||||
|
"curve": [ 0.272, 0, 0.841, 1 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.6666, "angle": -278.28 },
|
||||||
|
{ "time": 1.0666, "angle": 20.89 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": -7.84, "y": 7.19 },
|
||||||
|
{ "time": 0.1333, "x": -6.36, "y": 6.42 },
|
||||||
|
{ "time": 0.6666, "x": -11.07, "y": 5.25 },
|
||||||
|
{ "time": 1.0666, "x": -7.84, "y": 7.19 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right arm": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": -4.02,
|
||||||
|
"curve": [ 0.267, 0, 0.804, 0.99 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.1333,
|
||||||
|
"angle": -13.99,
|
||||||
|
"curve": [ 0.341, 0, 1, 1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.6666,
|
||||||
|
"angle": 36.54,
|
||||||
|
"curve": [ 0.307, 0, 0.787, 0.99 ]
|
||||||
|
},
|
||||||
|
{ "time": 1.0666, "angle": -4.02 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right hand": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 22.92 },
|
||||||
|
{ "time": 0.4, "angle": -8.97 },
|
||||||
|
{ "time": 0.6666, "angle": 0.51 },
|
||||||
|
{ "time": 1.0666, "angle": 22.92 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left shoulder": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -1.47 },
|
||||||
|
{ "time": 0.1333, "angle": 13.6 },
|
||||||
|
{ "time": 0.6666, "angle": 280.74 },
|
||||||
|
{ "time": 1.0666, "angle": -1.47 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": -1.76, "y": 0.56 },
|
||||||
|
{ "time": 0.6666, "x": -2.47, "y": 8.14 },
|
||||||
|
{ "time": 1.0666, "x": -1.76, "y": 0.56 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left hand": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": 11.58,
|
||||||
|
"curve": [ 0.169, 0.37, 0.632, 1.55 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.1333,
|
||||||
|
"angle": 28.13,
|
||||||
|
"curve": [ 0.692, 0, 0.692, 0.99 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.6666,
|
||||||
|
"angle": -27.42,
|
||||||
|
"curve": [ 0.117, 0.41, 0.738, 1.76 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.8, "angle": -36.32 },
|
||||||
|
{ "time": 1.0666, "angle": 11.58 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"left arm": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -8.27 },
|
||||||
|
{ "time": 0.1333, "angle": 18.43 },
|
||||||
|
{ "time": 0.6666, "angle": 0.88 },
|
||||||
|
{ "time": 1.0666, "angle": -8.27 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"torso": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -10.28 },
|
||||||
|
{
|
||||||
|
"time": 0.1333,
|
||||||
|
"angle": -15.38,
|
||||||
|
"curve": [ 0.545, 0, 1, 1 ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"time": 0.4,
|
||||||
|
"angle": -9.78,
|
||||||
|
"curve": [ 0.58, 0.17, 1, 1 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.6666, "angle": -15.75 },
|
||||||
|
{ "time": 0.9333, "angle": -7.06 },
|
||||||
|
{ "time": 1.0666, "angle": -10.28 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": -3.67, "y": 1.68 },
|
||||||
|
{ "time": 0.1333, "x": -3.67, "y": 0.68 },
|
||||||
|
{ "time": 0.4, "x": -3.67, "y": 1.97 },
|
||||||
|
{ "time": 0.6666, "x": -3.67, "y": -0.14 },
|
||||||
|
{ "time": 1.0666, "x": -3.67, "y": 1.68 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right foot": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -5.25 },
|
||||||
|
{ "time": 0.2666, "angle": -4.08 },
|
||||||
|
{ "time": 0.4, "angle": -6.45 },
|
||||||
|
{ "time": 0.5333, "angle": -5.39 },
|
||||||
|
{ "time": 0.8, "angle": -11.68 },
|
||||||
|
{ "time": 0.9333, "angle": 0.46 },
|
||||||
|
{ "time": 1.0666, "angle": -5.25 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"right lower leg": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": -3.39 },
|
||||||
|
{ "time": 0.1333, "angle": -45.53 },
|
||||||
|
{ "time": 0.2666, "angle": -2.59 },
|
||||||
|
{ "time": 0.5333, "angle": -19.53 },
|
||||||
|
{ "time": 0.6666, "angle": -64.8 },
|
||||||
|
{
|
||||||
|
"time": 0.8,
|
||||||
|
"angle": -82.56,
|
||||||
|
"curve": [ 0.557, 0.18, 1, 1 ]
|
||||||
|
},
|
||||||
|
{ "time": 1.0666, "angle": -3.39 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"hip": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 0, "curve": "stepped" },
|
||||||
|
{ "time": 1.0666, "angle": 0 }
|
||||||
|
],
|
||||||
|
"translate": [
|
||||||
|
{ "time": 0, "x": 0, "y": 0 },
|
||||||
|
{
|
||||||
|
"time": 0.1333,
|
||||||
|
"x": 0,
|
||||||
|
"y": -7.61,
|
||||||
|
"curve": [ 0.272, 0.86, 1, 1 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.4, "x": 0, "y": 8.7 },
|
||||||
|
{ "time": 0.5333, "x": 0, "y": -0.41 },
|
||||||
|
{
|
||||||
|
"time": 0.6666,
|
||||||
|
"x": 0,
|
||||||
|
"y": -7.05,
|
||||||
|
"curve": [ 0.235, 0.89, 1, 1 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.8, "x": 0, "y": 2.92 },
|
||||||
|
{ "time": 0.9333, "x": 0, "y": 6.78 },
|
||||||
|
{ "time": 1.0666, "x": 0, "y": 0 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"neck": {
|
||||||
|
"rotate": [
|
||||||
|
{ "time": 0, "angle": 3.6 },
|
||||||
|
{ "time": 0.1333, "angle": 17.49 },
|
||||||
|
{ "time": 0.2666, "angle": 6.1 },
|
||||||
|
{ "time": 0.4, "angle": 3.45 },
|
||||||
|
{ "time": 0.5333, "angle": 5.17 },
|
||||||
|
{ "time": 0.6666, "angle": 18.36 },
|
||||||
|
{ "time": 0.8, "angle": 6.09 },
|
||||||
|
{ "time": 0.9333, "angle": 2.28 },
|
||||||
|
{ "time": 1.0666, "angle": 3.6 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"head": {
|
||||||
|
"rotate": [
|
||||||
|
{
|
||||||
|
"time": 0,
|
||||||
|
"angle": 3.6,
|
||||||
|
"curve": [ 0, 0, 0.704, 1.61 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.1666, "angle": -0.2 },
|
||||||
|
{ "time": 0.2666, "angle": 6.1 },
|
||||||
|
{ "time": 0.4, "angle": 3.45 },
|
||||||
|
{
|
||||||
|
"time": 0.5333,
|
||||||
|
"angle": 5.17,
|
||||||
|
"curve": [ 0, 0, 0.704, 1.61 ]
|
||||||
|
},
|
||||||
|
{ "time": 0.7, "angle": 1.1 },
|
||||||
|
{ "time": 0.8, "angle": 6.09 },
|
||||||
|
{ "time": 0.9333, "angle": 2.28 },
|
||||||
|
{ "time": 1.0666, "angle": 3.6 }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
166
spine-libgdx/test/spineboy.atlas
Normal file
166
spine-libgdx/test/spineboy.atlas
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
|
||||||
|
spineboy.png
|
||||||
|
format: RGBA8888
|
||||||
|
filter: Nearest,Nearest
|
||||||
|
repeat: none
|
||||||
|
head
|
||||||
|
rotate: false
|
||||||
|
xy: 1, 122
|
||||||
|
size: 121, 132
|
||||||
|
orig: 121, 132
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
torso
|
||||||
|
rotate: false
|
||||||
|
xy: 1, 28
|
||||||
|
size: 68, 92
|
||||||
|
orig: 68, 92
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
left-pant-bottom
|
||||||
|
rotate: false
|
||||||
|
xy: 1, 4
|
||||||
|
size: 44, 22
|
||||||
|
orig: 44, 22
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
right-pant-bottom
|
||||||
|
rotate: false
|
||||||
|
xy: 47, 8
|
||||||
|
size: 46, 18
|
||||||
|
orig: 46, 18
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
right-upper-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 71, 50
|
||||||
|
size: 44, 70
|
||||||
|
orig: 44, 70
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
pelvis
|
||||||
|
rotate: false
|
||||||
|
xy: 95, 1
|
||||||
|
size: 63, 47
|
||||||
|
orig: 63, 47
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
left-upper-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 117, 53
|
||||||
|
size: 33, 67
|
||||||
|
orig: 33, 67
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
right-foot
|
||||||
|
rotate: false
|
||||||
|
xy: 160, 224
|
||||||
|
size: 67, 30
|
||||||
|
orig: 67, 30
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
left-shoulder
|
||||||
|
rotate: false
|
||||||
|
xy: 124, 201
|
||||||
|
size: 34, 53
|
||||||
|
orig: 34, 53
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
left-ankle
|
||||||
|
rotate: false
|
||||||
|
xy: 229, 222
|
||||||
|
size: 25, 32
|
||||||
|
orig: 25, 32
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
left-foot
|
||||||
|
rotate: false
|
||||||
|
xy: 160, 192
|
||||||
|
size: 65, 30
|
||||||
|
orig: 65, 30
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
neck
|
||||||
|
rotate: false
|
||||||
|
xy: 124, 171
|
||||||
|
size: 34, 28
|
||||||
|
orig: 34, 28
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
right-arm
|
||||||
|
rotate: false
|
||||||
|
xy: 124, 124
|
||||||
|
size: 21, 45
|
||||||
|
orig: 21, 45
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
right-ankle
|
||||||
|
rotate: false
|
||||||
|
xy: 227, 190
|
||||||
|
size: 25, 30
|
||||||
|
orig: 25, 30
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
left-hand
|
||||||
|
rotate: false
|
||||||
|
xy: 147, 131
|
||||||
|
size: 35, 38
|
||||||
|
orig: 35, 38
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
left-arm
|
||||||
|
rotate: false
|
||||||
|
xy: 184, 161
|
||||||
|
size: 35, 29
|
||||||
|
orig: 35, 29
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
eyes-closed
|
||||||
|
rotate: false
|
||||||
|
xy: 221, 161
|
||||||
|
size: 34, 27
|
||||||
|
orig: 34, 27
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
right-lower-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 152, 65
|
||||||
|
size: 51, 64
|
||||||
|
orig: 51, 64
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
right-foot-idle
|
||||||
|
rotate: false
|
||||||
|
xy: 184, 131
|
||||||
|
size: 53, 28
|
||||||
|
orig: 53, 28
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
left-lower-leg
|
||||||
|
rotate: false
|
||||||
|
xy: 205, 65
|
||||||
|
size: 49, 64
|
||||||
|
orig: 49, 64
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
right-shoulder
|
||||||
|
rotate: false
|
||||||
|
xy: 160, 12
|
||||||
|
size: 52, 51
|
||||||
|
orig: 52, 51
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
eyes
|
||||||
|
rotate: false
|
||||||
|
xy: 214, 36
|
||||||
|
size: 34, 27
|
||||||
|
orig: 34, 27
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
|
right-hand
|
||||||
|
rotate: false
|
||||||
|
xy: 214, 2
|
||||||
|
size: 32, 32
|
||||||
|
orig: 32, 32
|
||||||
|
offset: 0, 0
|
||||||
|
index: -1
|
||||||
BIN
spine-libgdx/test/spineboy.png
Normal file
BIN
spine-libgdx/test/spineboy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 65 KiB |
BIN
spine-libgdx/test/spineboy.skel
Normal file
BIN
spine-libgdx/test/spineboy.skel
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user