mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Add SkinAndAnimationBounds and use in Play/Pause Sample
This commit is contained in:
parent
092d97ec13
commit
2c8dd49a85
@ -18,6 +18,7 @@ import androidx.compose.ui.viewinterop.AndroidView
|
|||||||
import androidx.navigation.NavHostController
|
import androidx.navigation.NavHostController
|
||||||
import com.esotericsoftware.spine.android.SpineController
|
import com.esotericsoftware.spine.android.SpineController
|
||||||
import com.esotericsoftware.spine.android.SpineView
|
import com.esotericsoftware.spine.android.SpineView
|
||||||
|
import com.esotericsoftware.spine.android.bounds.SkinAndAnimationBounds
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
@ -58,16 +59,18 @@ fun PlayPause(
|
|||||||
|
|
||||||
AndroidView(
|
AndroidView(
|
||||||
factory = { ctx ->
|
factory = { ctx ->
|
||||||
SpineView(ctx).apply {
|
SpineView.Builder(ctx)
|
||||||
loadFromAsset(
|
.setBoundsProvider(SkinAndAnimationBounds("flying"))
|
||||||
"dragon.atlas",
|
.build()
|
||||||
"dragon-ess.skel",
|
.apply {
|
||||||
controller
|
loadFromAsset(
|
||||||
)
|
"dragon.atlas",
|
||||||
}
|
"dragon-ess.skel",
|
||||||
|
controller
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
modifier = Modifier.padding(paddingValues)
|
modifier = Modifier.padding(paddingValues)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|||||||
@ -50,6 +50,35 @@ import java.io.File;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
|
||||||
public class SpineView extends View implements Choreographer.FrameCallback {
|
public class SpineView extends View implements Choreographer.FrameCallback {
|
||||||
|
|
||||||
|
public static class Builder {
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
private BoundsProvider boundsProvider = new SetupPoseBounds();
|
||||||
|
private Alignment alignment = Alignment.CENTER;
|
||||||
|
|
||||||
|
public Builder(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setBoundsProvider(BoundsProvider boundsProvider) {
|
||||||
|
this.boundsProvider = boundsProvider;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Builder setAlignment(Alignment alignment) {
|
||||||
|
this.alignment = alignment;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SpineView build() {
|
||||||
|
SpineView spineView = new SpineView(context);
|
||||||
|
spineView.boundsProvider = boundsProvider;
|
||||||
|
spineView.alignment = alignment;
|
||||||
|
return spineView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private long lastTime = 0;
|
private long lastTime = 0;
|
||||||
private float delta = 0;
|
private float delta = 0;
|
||||||
private float offsetX = 0;
|
private float offsetX = 0;
|
||||||
@ -59,12 +88,13 @@ public class SpineView extends View implements Choreographer.FrameCallback {
|
|||||||
private float x = 0;
|
private float x = 0;
|
||||||
private float y = 0;
|
private float y = 0;
|
||||||
|
|
||||||
SkeletonRenderer renderer = new SkeletonRenderer();
|
private final SkeletonRenderer renderer = new SkeletonRenderer();
|
||||||
|
private Bounds computedBounds = new Bounds();
|
||||||
|
|
||||||
SpineController controller;
|
SpineController controller;
|
||||||
|
|
||||||
BoundsProvider boundsProvider = new SetupPoseBounds();
|
BoundsProvider boundsProvider = new SetupPoseBounds();
|
||||||
|
|
||||||
Bounds computedBounds = new Bounds();
|
|
||||||
Alignment alignment = Alignment.CENTER;
|
Alignment alignment = Alignment.CENTER;
|
||||||
|
|
||||||
public SpineView (Context context) {
|
public SpineView (Context context) {
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
package com.esotericsoftware.spine.android.bounds;
|
package com.esotericsoftware.spine.android.bounds;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.math.Vector2;
|
||||||
|
import com.badlogic.gdx.utils.FloatArray;
|
||||||
|
import com.esotericsoftware.spine.Skeleton;
|
||||||
|
|
||||||
public class Bounds {
|
public class Bounds {
|
||||||
private double x;
|
private double x;
|
||||||
private double y;
|
private double y;
|
||||||
@ -20,6 +24,19 @@ public class Bounds {
|
|||||||
this.height = height;
|
this.height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Bounds(Skeleton skeleton) {
|
||||||
|
Vector2 offset = new Vector2(0, 0);
|
||||||
|
Vector2 size = new Vector2(0, 0);
|
||||||
|
FloatArray floatArray = new FloatArray();
|
||||||
|
|
||||||
|
skeleton.getBounds(offset, size, floatArray);
|
||||||
|
|
||||||
|
x = offset.x;
|
||||||
|
y = offset.y;
|
||||||
|
width = size.x;
|
||||||
|
height = size.y;
|
||||||
|
}
|
||||||
|
|
||||||
public double getX() {
|
public double getX() {
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,13 +8,6 @@ public class SetupPoseBounds implements BoundsProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Bounds computeBounds(AndroidSkeletonDrawable drawable) {
|
public Bounds computeBounds(AndroidSkeletonDrawable drawable) {
|
||||||
|
return new Bounds(drawable.getSkeleton());
|
||||||
Vector2 offset = new Vector2(0, 0);
|
|
||||||
Vector2 size = new Vector2(0, 0);
|
|
||||||
FloatArray floatArray = new FloatArray();
|
|
||||||
|
|
||||||
drawable.getSkeleton().getBounds(offset, size, floatArray);
|
|
||||||
|
|
||||||
return new Bounds(offset.x, offset.y, size.x, size.y);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,75 @@
|
|||||||
|
package com.esotericsoftware.spine.android.bounds;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Animation;
|
||||||
|
import com.esotericsoftware.spine.SkeletonData;
|
||||||
|
import com.esotericsoftware.spine.Skin;
|
||||||
|
import com.esotericsoftware.spine.android.AndroidSkeletonDrawable;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class SkinAndAnimationBounds implements BoundsProvider {
|
||||||
|
private final List<String> skins;
|
||||||
|
private final String animation;
|
||||||
|
private final double stepTime;
|
||||||
|
|
||||||
|
// Constructor
|
||||||
|
public SkinAndAnimationBounds(List<String> skins, String animation, double stepTime) {
|
||||||
|
this.skins = (skins == null || skins.isEmpty()) ? Collections.singletonList("default") : skins;
|
||||||
|
this.animation = animation;
|
||||||
|
this.stepTime = stepTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkinAndAnimationBounds(List<String> skins, String animation) {
|
||||||
|
this(skins, animation, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkinAndAnimationBounds(String animation) {
|
||||||
|
this(Collections.emptyList(), animation, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Bounds computeBounds(AndroidSkeletonDrawable drawable) {
|
||||||
|
SkeletonData data = drawable.getSkeletonData();
|
||||||
|
Skin oldSkin = drawable.getSkeleton().getSkin();
|
||||||
|
Skin customSkin = new Skin("custom-skin");
|
||||||
|
for (String skinName : skins) {
|
||||||
|
Skin skin = data.findSkin(skinName);
|
||||||
|
if (skin == null) continue;
|
||||||
|
customSkin.addSkin(skin);
|
||||||
|
}
|
||||||
|
drawable.getSkeleton().setSkin(customSkin);
|
||||||
|
drawable.getSkeleton().setToSetupPose();
|
||||||
|
|
||||||
|
Animation animation = (this.animation != null) ? data.findAnimation(this.animation) : null;
|
||||||
|
double minX = Double.POSITIVE_INFINITY;
|
||||||
|
double minY = Double.POSITIVE_INFINITY;
|
||||||
|
double maxX = Double.NEGATIVE_INFINITY;
|
||||||
|
double maxY = Double.NEGATIVE_INFINITY;
|
||||||
|
if (animation == null) {
|
||||||
|
Bounds bounds = new Bounds(drawable.getSkeleton());
|
||||||
|
minX = bounds.getX();
|
||||||
|
minY = bounds.getY();
|
||||||
|
maxX = minX + bounds.getWidth();
|
||||||
|
maxY = minY + bounds.getHeight();
|
||||||
|
} else {
|
||||||
|
drawable.getAnimationState().setAnimation(0, animation, false);
|
||||||
|
int steps = (int) Math.max( (animation.getDuration() / stepTime), 1.0);
|
||||||
|
for (int i = 0; i < steps; i++) {
|
||||||
|
drawable.update(i > 0 ? (float) stepTime : 0);
|
||||||
|
Bounds bounds = new Bounds(drawable.getSkeleton());
|
||||||
|
minX = Math.min(minX, bounds.getX());
|
||||||
|
minY = Math.min(minY, bounds.getY());
|
||||||
|
maxX = Math.max(maxX, minX + bounds.getWidth());
|
||||||
|
maxY = Math.max(maxY, minY + bounds.getHeight());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drawable.getSkeleton().setSkin("default");
|
||||||
|
drawable.getAnimationState().clearTracks();
|
||||||
|
if (oldSkin != null) drawable.getSkeleton().setSkin(oldSkin);
|
||||||
|
drawable.getSkeleton().setToSetupPose();
|
||||||
|
drawable.update(0);
|
||||||
|
return new Bounds(minX, minY, maxX - minX, maxY - minY);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user