Update SpineController and SpineController.Builder API

This commit is contained in:
Denis Andrasec 2024-07-10 11:53:08 +02:00
parent fc4716f749
commit 77778a0e3a
9 changed files with 138 additions and 148 deletions

View File

@ -29,86 +29,84 @@ fun AnimationState(nav: NavHostController) {
val TAG = "AnimationState" val TAG = "AnimationState"
val controller = remember { val controller = remember {
SpineController.Builder() SpineController { controller ->
.setOnInitialized { controller -> controller.skeleton.setScaleX(0.5f)
controller.skeleton.setScaleX(0.5f) controller.skeleton.setScaleY(0.5f)
controller.skeleton.setScaleY(0.5f)
controller.skeleton.findSlot("gun")?.color = Color(1f, 0f, 0f, 1f) controller.skeleton.findSlot("gun")?.color = Color(1f, 0f, 0f, 1f)
controller.animationStateData.setDefaultMix(0.2f) controller.animationStateData.setDefaultMix(0.2f)
controller.animationState.setAnimation(0, "walk", true).setListener(object : AnimationState.AnimationStateListener { controller.animationState.setAnimation(0, "walk", true).setListener(object : AnimationState.AnimationStateListener {
override fun start(entry: AnimationState.TrackEntry?) { override fun start(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Walk animation event start") Log.d(TAG, "Walk animation event start")
}
override fun interrupt(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Walk animation event interrupt")
}
override fun end(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Walk animation event end")
}
override fun dispose(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Walk animation event dispose")
}
override fun complete(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Walk animation event complete")
}
override fun event(entry: AnimationState.TrackEntry?, event: Event?) {
Log.d(TAG, "Walk animation event event")
}
})
controller.animationState.addAnimation(0, "jump", false, 2f)
controller.animationState.addAnimation(0, "run", true, 0f).setListener(object : AnimationState.AnimationStateListener {
override fun start(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Run animation event start")
}
override fun interrupt(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Run animation event interrupt")
}
override fun end(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Run animation event end")
}
override fun dispose(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Run animation event dispose")
}
override fun complete(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Run animation event complete")
}
override fun event(entry: AnimationState.TrackEntry?, event: Event?) {
Log.d(TAG, "Run animation event event")
}
})
controller.animationState.addListener(object : AnimationState.AnimationStateListener {
override fun start(entry: AnimationState.TrackEntry?) {}
override fun interrupt(entry: AnimationState.TrackEntry?) {}
override fun end(entry: AnimationState.TrackEntry?) {}
override fun dispose(entry: AnimationState.TrackEntry?) {}
override fun complete(entry: AnimationState.TrackEntry?) {}
override fun event(entry: AnimationState.TrackEntry?, event: Event?) {
if (event != null) {
Log.d(TAG, "User event: { name: ${event.data.name}, intValue: ${event.int}, floatValue: ${event.float}, stringValue: ${event.string} }")
} }
}
override fun interrupt(entry: AnimationState.TrackEntry?) { })
Log.d(TAG, "Walk animation event interrupt") Log.d(TAG, "Current: ${controller.animationState.getCurrent(0)?.getAnimation()?.getName()}");
} }
override fun end(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Walk animation event end")
}
override fun dispose(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Walk animation event dispose")
}
override fun complete(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Walk animation event complete")
}
override fun event(entry: AnimationState.TrackEntry?, event: Event?) {
Log.d(TAG, "Walk animation event event")
}
})
controller.animationState.addAnimation(0, "jump", false, 2f)
controller.animationState.addAnimation(0, "run", true, 0f).setListener(object : AnimationState.AnimationStateListener {
override fun start(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Run animation event start")
}
override fun interrupt(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Run animation event interrupt")
}
override fun end(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Run animation event end")
}
override fun dispose(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Run animation event dispose")
}
override fun complete(entry: AnimationState.TrackEntry?) {
Log.d(TAG, "Run animation event complete")
}
override fun event(entry: AnimationState.TrackEntry?, event: Event?) {
Log.d(TAG, "Run animation event event")
}
})
controller.animationState.addListener(object : AnimationState.AnimationStateListener {
override fun start(entry: AnimationState.TrackEntry?) {}
override fun interrupt(entry: AnimationState.TrackEntry?) {}
override fun end(entry: AnimationState.TrackEntry?) {}
override fun dispose(entry: AnimationState.TrackEntry?) {}
override fun complete(entry: AnimationState.TrackEntry?) {}
override fun event(entry: AnimationState.TrackEntry?, event: Event?) {
if (event != null) {
Log.d(TAG, "User event: { name: ${event.data.name}, intValue: ${event.int}, floatValue: ${event.float}, stringValue: ${event.string} }")
}
}
})
Log.d(TAG, "Current: ${controller.animationState.getCurrent(0)?.getAnimation()?.getName()}");
}
.build()
} }
Scaffold( Scaffold(

View File

@ -47,14 +47,13 @@ fun DebugRendering(nav: NavHostController) {
"spineboy.atlas", "spineboy.atlas",
"spineboy-pro.json", "spineboy-pro.json",
context, context,
SpineController.Builder() SpineController.Builder { controller ->
.setOnInitialized { controller.animationState.setAnimation(0, "walk", true)
it.animationState.setAnimation(0, "walk", true) }
} .setOnAfterPaint { controller, canvas, commands ->
.setOnAfterPaint { controller, canvas, commands -> debugRenderer.render(controller.drawable, canvas, commands)
debugRenderer.render(controller.drawable, canvas, commands) }
} .build()
.build()
) )
}, },
modifier = Modifier.padding(paddingValues) modifier = Modifier.padding(paddingValues)

View File

@ -75,11 +75,9 @@ fun DressUp(nav: NavHostController) {
} }
val controller = remember { val controller = remember {
SpineController.Builder() SpineController { controller ->
.setOnInitialized { controller.animationState.setAnimation(0, "dance", true)
it.animationState.setAnimation(0, "dance", true) }
}
.build()
} }
fun toggleSkin(skinName: String) { fun toggleSkin(skinName: String) {

View File

@ -35,21 +35,20 @@ fun IKFollowing(nav: NavHostController) {
val crossHairPosition = remember { mutableStateOf<Point?>(null) } val crossHairPosition = remember { mutableStateOf<Point?>(null) }
val controller = remember { val controller = remember {
SpineController.Builder() SpineController.Builder { controller ->
.setOnInitialized { controller.animationState.setAnimation(0, "walk", true)
it.animationState.setAnimation(0, "walk", true) controller.animationState.setAnimation(1, "aim", true)
it.animationState.setAnimation(1, "aim", true) }
} .setOnAfterUpdateWorldTransforms {
.setOnAfterUpdateWorldTransforms { val worldPosition = crossHairPosition.value ?: return@setOnAfterUpdateWorldTransforms
val worldPosition = crossHairPosition.value ?: return@setOnAfterUpdateWorldTransforms val skeleton = it.skeleton
val skeleton = it.skeleton val bone = skeleton.findBone("crosshair") ?: return@setOnAfterUpdateWorldTransforms
val bone = skeleton.findBone("crosshair") ?: return@setOnAfterUpdateWorldTransforms val parent = bone.parent ?: return@setOnAfterUpdateWorldTransforms
val parent = bone.parent ?: return@setOnAfterUpdateWorldTransforms val position = parent.worldToLocal(Vector2(worldPosition.x.toFloat(), worldPosition.y.toFloat()))
val position = parent.worldToLocal(Vector2(worldPosition.x.toFloat(), worldPosition.y.toFloat())) bone.x = position.x
bone.x = position.x bone.y = position.y
bone.y = position.y }
} .build()
.build()
} }
Scaffold( Scaffold(

View File

@ -36,31 +36,30 @@ fun Physics(nav: NavHostController) {
val lastMousePosition = remember { mutableStateOf<Point?>(null) } val lastMousePosition = remember { mutableStateOf<Point?>(null) }
val controller = remember { val controller = remember {
SpineController.Builder() SpineController.Builder { controller ->
.setOnInitialized { controller -> controller.animationState.setAnimation(0, "eyeblink-long", true)
controller.animationState.setAnimation(0, "eyeblink-long", true) controller.animationState.setAnimation(1, "wings-and-feet", true)
controller.animationState.setAnimation(1, "wings-and-feet", true) }
.setOnAfterUpdateWorldTransforms { controller ->
val lastMousePositionValue = lastMousePosition.value
if (lastMousePositionValue == null) {
lastMousePosition.value = mousePosition.value
return@setOnAfterUpdateWorldTransforms
} }
.setOnAfterUpdateWorldTransforms { controller -> val mousePositionValue = mousePosition.value ?: return@setOnAfterUpdateWorldTransforms
val lastMousePositionValue = lastMousePosition.value
if (lastMousePositionValue == null) {
lastMousePosition.value = mousePosition.value
return@setOnAfterUpdateWorldTransforms
}
val mousePositionValue = mousePosition.value ?: return@setOnAfterUpdateWorldTransforms
val dx = mousePositionValue.x - lastMousePositionValue.x val dx = mousePositionValue.x - lastMousePositionValue.x
val dy = mousePositionValue.y - lastMousePositionValue.y val dy = mousePositionValue.y - lastMousePositionValue.y
val position = Point( val position = Point(
controller.skeleton.x.toInt(), controller.skeleton.x.toInt(),
controller.skeleton.y.toInt() controller.skeleton.y.toInt()
) )
position.x += dx position.x += dx
position.y += dy position.y += dy
controller.skeleton.setPosition(position.x.toFloat(), position.y.toFloat()); controller.skeleton.setPosition(position.x.toFloat(), position.y.toFloat());
lastMousePosition.value = mousePositionValue lastMousePosition.value = mousePositionValue
} }
.build() .build()
} }
Scaffold( Scaffold(

View File

@ -26,12 +26,9 @@ fun PlayPause(
nav: NavHostController nav: NavHostController
) { ) {
val controller = remember { val controller = remember {
SpineController.Builder() SpineController { controller ->
.setOnInitialized { controller.animationState.setAnimation(0, "flying", true)
it.animationState.setAnimation(0, "flying", true) }
}
.build()
} }
val isPlaying = remember { mutableStateOf(controller.isPlaying) } val isPlaying = remember { mutableStateOf(controller.isPlaying) }

View File

@ -40,11 +40,9 @@ fun SimpleAnimation(nav: NavHostController) {
"spineboy.atlas", "spineboy.atlas",
"spineboy-pro.json", "spineboy-pro.json",
context, context,
SpineController.Builder() SpineController {
.setOnInitialized { it.animationState.setAnimation(0, "walk", true)
it.animationState.setAnimation(0, "walk", true) }
}
.build()
) )
}, },
modifier = Modifier.padding(paddingValues) modifier = Modifier.padding(paddingValues)

View File

@ -17,15 +17,14 @@ import com.esotericsoftware.spine.android.utils.SpineControllerCallback;
public class SpineController { public class SpineController {
public static class Builder { public static class Builder {
private SpineControllerCallback onInitialized; private final SpineControllerCallback onInitialized;
private SpineControllerCallback onBeforeUpdateWorldTransforms; private SpineControllerCallback onBeforeUpdateWorldTransforms;
private SpineControllerCallback onAfterUpdateWorldTransforms; private SpineControllerCallback onAfterUpdateWorldTransforms;
private SpineControllerBeforePaintCallback onBeforePaint; private SpineControllerBeforePaintCallback onBeforePaint;
private SpineControllerAfterPaintCallback onAfterPaint; private SpineControllerAfterPaintCallback onAfterPaint;
public Builder setOnInitialized(SpineControllerCallback onInitialized) { public Builder(SpineControllerCallback onInitialized) {
this.onInitialized = onInitialized; this.onInitialized = onInitialized;
return this;
} }
public Builder setOnBeforeUpdateWorldTransforms(SpineControllerCallback onBeforeUpdateWorldTransforms) { public Builder setOnBeforeUpdateWorldTransforms(SpineControllerCallback onBeforeUpdateWorldTransforms) {
@ -49,8 +48,7 @@ public class SpineController {
} }
public SpineController build() { public SpineController build() {
SpineController spineController = new SpineController(); SpineController spineController = new SpineController(onInitialized);
spineController.onInitialized = onInitialized;
spineController.onBeforeUpdateWorldTransforms = onBeforeUpdateWorldTransforms; spineController.onBeforeUpdateWorldTransforms = onBeforeUpdateWorldTransforms;
spineController.onAfterUpdateWorldTransforms = onAfterUpdateWorldTransforms; spineController.onAfterUpdateWorldTransforms = onAfterUpdateWorldTransforms;
spineController.onBeforePaint = onBeforePaint; spineController.onBeforePaint = onBeforePaint;
@ -59,7 +57,7 @@ public class SpineController {
} }
} }
private @Nullable SpineControllerCallback onInitialized; private final SpineControllerCallback onInitialized;
private @Nullable SpineControllerCallback onBeforeUpdateWorldTransforms; private @Nullable SpineControllerCallback onBeforeUpdateWorldTransforms;
private @Nullable SpineControllerCallback onAfterUpdateWorldTransforms; private @Nullable SpineControllerCallback onAfterUpdateWorldTransforms;
private @Nullable SpineControllerBeforePaintCallback onBeforePaint; private @Nullable SpineControllerBeforePaintCallback onBeforePaint;
@ -71,6 +69,10 @@ public class SpineController {
private double scaleX = 1; private double scaleX = 1;
private double scaleY = 1; private double scaleY = 1;
public SpineController(SpineControllerCallback onInitialized) {
this.onInitialized = onInitialized;
}
protected void init(AndroidSkeletonDrawable drawable) { protected void init(AndroidSkeletonDrawable drawable) {
this.drawable = drawable; this.drawable = drawable;
if (onInitialized != null) { if (onInitialized != null) {

View File

@ -120,12 +120,12 @@ public class SpineView extends View implements Choreographer.FrameCallback {
public SpineView (Context context, AttributeSet attrs) { public SpineView (Context context, AttributeSet attrs) {
super(context, attrs); super(context, attrs);
this.controller = new SpineController(); // TODO Load controller & assets fro attrs
} }
public SpineView (Context context, AttributeSet attrs, int defStyle) { public SpineView (Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle); super(context, attrs, defStyle);
this.controller = new SpineController(); // TODO Load controller & assets fro attrs
} }
public static SpineView loadFromAssets(String atlasFileName, String skeletonFileName, Context context, SpineController controller) { public static SpineView loadFromAssets(String atlasFileName, String skeletonFileName, Context context, SpineController controller) {