mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 15:24:55 +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 com.esotericsoftware.spine.android.SpineController
|
||||
import com.esotericsoftware.spine.android.SpineView
|
||||
import com.esotericsoftware.spine.android.bounds.SkinAndAnimationBounds
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@ -58,16 +59,18 @@ fun PlayPause(
|
||||
|
||||
AndroidView(
|
||||
factory = { ctx ->
|
||||
SpineView(ctx).apply {
|
||||
loadFromAsset(
|
||||
"dragon.atlas",
|
||||
"dragon-ess.skel",
|
||||
controller
|
||||
)
|
||||
}
|
||||
SpineView.Builder(ctx)
|
||||
.setBoundsProvider(SkinAndAnimationBounds("flying"))
|
||||
.build()
|
||||
.apply {
|
||||
loadFromAsset(
|
||||
"dragon.atlas",
|
||||
"dragon-ess.skel",
|
||||
controller
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(paddingValues)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +50,35 @@ import java.io.File;
|
||||
import java.net.URL;
|
||||
|
||||
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 float delta = 0;
|
||||
private float offsetX = 0;
|
||||
@ -59,12 +88,13 @@ public class SpineView extends View implements Choreographer.FrameCallback {
|
||||
private float x = 0;
|
||||
private float y = 0;
|
||||
|
||||
SkeletonRenderer renderer = new SkeletonRenderer();
|
||||
private final SkeletonRenderer renderer = new SkeletonRenderer();
|
||||
private Bounds computedBounds = new Bounds();
|
||||
|
||||
SpineController controller;
|
||||
|
||||
BoundsProvider boundsProvider = new SetupPoseBounds();
|
||||
|
||||
Bounds computedBounds = new Bounds();
|
||||
Alignment alignment = Alignment.CENTER;
|
||||
|
||||
public SpineView (Context context) {
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
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 {
|
||||
private double x;
|
||||
private double y;
|
||||
@ -20,6 +24,19 @@ public class Bounds {
|
||||
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() {
|
||||
return x;
|
||||
}
|
||||
|
||||
@ -8,13 +8,6 @@ public class SetupPoseBounds implements BoundsProvider {
|
||||
|
||||
@Override
|
||||
public Bounds computeBounds(AndroidSkeletonDrawable drawable) {
|
||||
|
||||
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);
|
||||
return new Bounds(drawable.getSkeleton());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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