mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
Add Physics sample
This commit is contained in:
parent
2bae3023e4
commit
8df1b3ee27
174
spine-android/app/src/main/assets/celestial-circus-pma.atlas
Normal file
174
spine-android/app/src/main/assets/celestial-circus-pma.atlas
Normal file
@ -0,0 +1,174 @@
|
||||
celestial-circus-pma.png
|
||||
size: 1024, 1024
|
||||
filter: Linear, Linear
|
||||
pma: true
|
||||
scale: 0.4
|
||||
arm-back-down
|
||||
bounds: 324, 401, 38, 82
|
||||
rotate: 90
|
||||
arm-back-up
|
||||
bounds: 290, 44, 83, 116
|
||||
rotate: 90
|
||||
arm-front-down
|
||||
bounds: 706, 2, 36, 78
|
||||
rotate: 90
|
||||
arm-front-up
|
||||
bounds: 860, 138, 77, 116
|
||||
bench
|
||||
bounds: 725, 256, 189, 48
|
||||
body-bottom
|
||||
bounds: 879, 868, 154, 124
|
||||
rotate: 90
|
||||
body-top
|
||||
bounds: 725, 128, 126, 133
|
||||
rotate: 90
|
||||
chest
|
||||
bounds: 408, 26, 104, 93
|
||||
cloud-back
|
||||
bounds: 752, 378, 202, 165
|
||||
cloud-front
|
||||
bounds: 2, 2, 325, 196
|
||||
rotate: 90
|
||||
collar
|
||||
bounds: 786, 13, 47, 26
|
||||
ear
|
||||
bounds: 1002, 643, 20, 28
|
||||
eye-back-shadow
|
||||
bounds: 428, 395, 14, 10
|
||||
eye-front-shadow
|
||||
bounds: 704, 529, 24, 14
|
||||
eye-reflex-back
|
||||
bounds: 860, 128, 8, 7
|
||||
rotate: 90
|
||||
eye-reflex-front
|
||||
bounds: 726, 386, 10, 7
|
||||
eye-white-back
|
||||
bounds: 835, 23, 13, 16
|
||||
eye-white-front
|
||||
bounds: 1005, 1000, 22, 17
|
||||
rotate: 90
|
||||
eyelashes-down-back
|
||||
bounds: 232, 329, 11, 6
|
||||
rotate: 90
|
||||
eyelashes-down-front
|
||||
bounds: 913, 851, 15, 6
|
||||
rotate: 90
|
||||
eyelashes-top-back
|
||||
bounds: 408, 395, 18, 10
|
||||
eyelashes-top-front
|
||||
bounds: 702, 179, 30, 16
|
||||
rotate: 90
|
||||
face
|
||||
bounds: 514, 26, 93, 102
|
||||
rotate: 90
|
||||
feathers-back
|
||||
bounds: 954, 625, 46, 46
|
||||
feathers-front
|
||||
bounds: 706, 40, 72, 86
|
||||
fringe-middle-back
|
||||
bounds: 200, 6, 33, 52
|
||||
rotate: 90
|
||||
fringe-middle-front
|
||||
bounds: 878, 76, 60, 50
|
||||
rotate: 90
|
||||
fringe-side-back
|
||||
bounds: 780, 41, 27, 94
|
||||
rotate: 90
|
||||
fringe-side-front
|
||||
bounds: 939, 161, 26, 93
|
||||
glove-bottom-back
|
||||
bounds: 954, 572, 51, 41
|
||||
rotate: 90
|
||||
glove-bottom-front
|
||||
bounds: 916, 256, 47, 48
|
||||
hair-back-1
|
||||
bounds: 444, 395, 132, 306
|
||||
rotate: 90
|
||||
hair-back-2
|
||||
bounds: 438, 211, 80, 285
|
||||
rotate: 90
|
||||
hair-back-3
|
||||
bounds: 719, 306, 70, 268
|
||||
rotate: 90
|
||||
hair-back-4
|
||||
bounds: 438, 121, 88, 262
|
||||
rotate: 90
|
||||
hair-back-5
|
||||
bounds: 438, 293, 88, 279
|
||||
rotate: 90
|
||||
hair-back-6
|
||||
bounds: 200, 41, 88, 286
|
||||
hair-hat-shadow
|
||||
bounds: 232, 398, 90, 41
|
||||
hand-back
|
||||
bounds: 954, 673, 60, 47
|
||||
rotate: 90
|
||||
hand-front
|
||||
bounds: 967, 172, 53, 60
|
||||
hat-back
|
||||
bounds: 954, 802, 64, 45
|
||||
rotate: 90
|
||||
hat-front
|
||||
bounds: 780, 70, 96, 56
|
||||
head-back
|
||||
bounds: 618, 17, 102, 86
|
||||
rotate: 90
|
||||
jabot
|
||||
bounds: 967, 234, 70, 55
|
||||
rotate: 90
|
||||
leg-back
|
||||
bounds: 232, 441, 210, 333
|
||||
leg-front
|
||||
bounds: 444, 529, 258, 320
|
||||
logo-brooch
|
||||
bounds: 954, 545, 16, 25
|
||||
mouth
|
||||
bounds: 408, 121, 22, 6
|
||||
neck
|
||||
bounds: 232, 342, 39, 56
|
||||
rotate: 90
|
||||
nose
|
||||
bounds: 742, 529, 6, 7
|
||||
rotate: 90
|
||||
nose-highlight
|
||||
bounds: 719, 300, 4, 4
|
||||
nose-shadow
|
||||
bounds: 869, 128, 7, 8
|
||||
pupil-back
|
||||
bounds: 730, 529, 10, 14
|
||||
pupil-front
|
||||
bounds: 254, 21, 12, 18
|
||||
rope-back
|
||||
bounds: 232, 383, 10, 492
|
||||
rotate: 90
|
||||
rope-front
|
||||
bounds: 232, 383, 10, 492
|
||||
rotate: 90
|
||||
rope-front-bottom
|
||||
bounds: 954, 735, 42, 65
|
||||
skirt
|
||||
bounds: 2, 776, 440, 246
|
||||
sock-bow
|
||||
bounds: 408, 407, 33, 32
|
||||
spine-logo-body
|
||||
bounds: 879, 853, 13, 32
|
||||
rotate: 90
|
||||
star-big
|
||||
bounds: 939, 141, 18, 24
|
||||
rotate: 90
|
||||
star-medium
|
||||
bounds: 742, 537, 6, 8
|
||||
rotate: 90
|
||||
star-small
|
||||
bounds: 719, 378, 3, 4
|
||||
rotate: 90
|
||||
underskirt
|
||||
bounds: 2, 329, 445, 228
|
||||
rotate: 90
|
||||
underskirt-back
|
||||
bounds: 444, 851, 433, 171
|
||||
wing-back
|
||||
bounds: 290, 129, 146, 252
|
||||
wing-front
|
||||
bounds: 704, 545, 304, 248
|
||||
rotate: 90
|
||||
BIN
spine-android/app/src/main/assets/celestial-circus-pma.png
Normal file
BIN
spine-android/app/src/main/assets/celestial-circus-pma.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 799 KiB |
BIN
spine-android/app/src/main/assets/celestial-circus-pro.skel
Normal file
BIN
spine-android/app/src/main/assets/celestial-circus-pro.skel
Normal file
Binary file not shown.
@ -61,7 +61,8 @@ fun AppContent() {
|
||||
Destination.SimpleAnimation,
|
||||
Destination.PlayPause,
|
||||
Destination.AnimationStateEvents,
|
||||
Destination.IKFollowing
|
||||
Destination.IKFollowing,
|
||||
Destination.Physics
|
||||
),
|
||||
paddingValues
|
||||
)
|
||||
@ -91,6 +92,12 @@ fun AppContent() {
|
||||
) {
|
||||
IKFollowing(navController)
|
||||
}
|
||||
|
||||
composable(
|
||||
Destination.Physics.route
|
||||
) {
|
||||
Physics(navController)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,4 +136,5 @@ sealed class Destination(val route: String, val title: String) {
|
||||
data object PlayPause : Destination("playPause", "Play/Pause")
|
||||
data object AnimationStateEvents : Destination("animationStateEvents", "Animation State Listener")
|
||||
data object IKFollowing : Destination("ikFollowing", "IK Following")
|
||||
data object Physics: Destination("physics", "Physics (drag anywhere)")
|
||||
}
|
||||
|
||||
@ -0,0 +1,122 @@
|
||||
package com.esotericsoftware.spine
|
||||
|
||||
import android.graphics.Point
|
||||
import androidx.compose.foundation.gestures.detectDragGestures
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.pointer.pointerInput
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.navigation.NavHostController
|
||||
import com.esotericsoftware.spine.android.SpineController
|
||||
import com.esotericsoftware.spine.android.SpineView
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun Physics(nav: NavHostController) {
|
||||
|
||||
val containerHeight = remember { mutableIntStateOf(0) }
|
||||
val dragPosition = remember { mutableStateOf(Point(0, 0)) }
|
||||
|
||||
val mousePosition = remember { mutableStateOf<Point?>(null) }
|
||||
val lastMousePosition = remember { mutableStateOf<Point?>(null) }
|
||||
|
||||
val controller = remember {
|
||||
SpineController.Builder()
|
||||
.setOnInitialized { controller ->
|
||||
controller.animationState.setAnimation(0, "eyeblink-long", true)
|
||||
controller.animationState.setAnimation(1, "wings-and-feet", true)
|
||||
}
|
||||
.setOnAfterUpdateWorldTransforms { controller ->
|
||||
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 dy = mousePositionValue.y - lastMousePositionValue.y
|
||||
val position = Point(
|
||||
controller.skeleton.x.toInt(),
|
||||
controller.skeleton.y.toInt()
|
||||
)
|
||||
position.x += dx
|
||||
position.y += dy
|
||||
controller.skeleton.setPosition(position.x.toFloat(), position.y.toFloat());
|
||||
lastMousePosition.value = mousePositionValue
|
||||
}
|
||||
.build()
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topBar = {
|
||||
TopAppBar(
|
||||
title = { Text(text = Destination.SimpleAnimation.title) },
|
||||
navigationIcon = {
|
||||
IconButton({ nav.navigateUp() }) {
|
||||
Icon(
|
||||
Icons.Rounded.ArrowBack,
|
||||
null,
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
) { paddingValues ->
|
||||
Box(modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(paddingValues)
|
||||
.onGloballyPositioned { coordinates ->
|
||||
containerHeight.intValue = coordinates.size.height
|
||||
}
|
||||
.pointerInput(Unit) {
|
||||
detectDragGestures(
|
||||
onDragStart = { offset ->
|
||||
dragPosition.value = Point(offset.x.toInt(), offset.y.toInt())
|
||||
},
|
||||
onDrag = { _, dragAmount ->
|
||||
dragPosition.value = Point(
|
||||
(dragPosition.value.x + dragAmount.x).toInt(),
|
||||
(dragPosition.value.y + dragAmount.y).toInt()
|
||||
)
|
||||
val invertedYDragPosition = Point(
|
||||
dragPosition.value.x,
|
||||
containerHeight.intValue - dragPosition.value.y,
|
||||
)
|
||||
mousePosition.value = controller.toSkeletonCoordinates(
|
||||
invertedYDragPosition
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
) {
|
||||
AndroidView(
|
||||
factory = { ctx ->
|
||||
SpineView(ctx).apply {
|
||||
loadFromAsset(
|
||||
"celestial-circus-pma.atlas",
|
||||
"celestial-circus-pro.skel",
|
||||
controller
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(paddingValues)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user