mirror of
https://github.com/nacabaro/vbhelper.git
synced 2026-06-05 13:52:54 +00:00
Started setting up sprite animations.
This commit is contained in:
parent
c5cebd8213
commit
37e5efa874
@ -0,0 +1,62 @@
|
||||
package com.github.nacabaro.vbhelper.battle
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.asImageBitmap
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
fun AnimatedSpriteImage(
|
||||
characterId: String,
|
||||
animationType: DigimonAnimationType = DigimonAnimationType.IDLE,
|
||||
modifier: Modifier = Modifier,
|
||||
contentScale: ContentScale = ContentScale.Fit
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val spriteManager = remember { BattleSpriteManager(context) }
|
||||
val animationStateMachine = remember { DigimonAnimationStateMachine(characterId) }
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
|
||||
var bitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }
|
||||
|
||||
// Start the animation when the component is first created
|
||||
LaunchedEffect(characterId) {
|
||||
coroutineScope.launch {
|
||||
animationStateMachine.playAnimation(DigimonAnimationType.IDLE)
|
||||
}
|
||||
}
|
||||
|
||||
// Change animation when animationType changes
|
||||
LaunchedEffect(animationType) {
|
||||
coroutineScope.launch {
|
||||
animationStateMachine.playAnimation(animationType)
|
||||
}
|
||||
}
|
||||
|
||||
// Update sprite when animation state changes
|
||||
LaunchedEffect(animationStateMachine.currentSpriteIndex) {
|
||||
val spriteName = animationStateMachine.getCurrentSpriteName()
|
||||
val atlasName = animationStateMachine.getCurrentAtlasName()
|
||||
|
||||
println("Loading animated sprite: $spriteName from atlas: $atlasName")
|
||||
bitmap = spriteManager.loadSprite(spriteName, atlasName)
|
||||
|
||||
if (bitmap == null) {
|
||||
println("Failed to load animated sprite: $spriteName from atlas: $atlasName")
|
||||
} else {
|
||||
println("Successfully loaded animated sprite: $spriteName from atlas: $atlasName")
|
||||
}
|
||||
}
|
||||
|
||||
bitmap?.let { bmp ->
|
||||
Image(
|
||||
bitmap = bmp.asImageBitmap(),
|
||||
contentDescription = "Animated Sprite: $characterId - ${animationStateMachine.currentAnimation}",
|
||||
modifier = modifier,
|
||||
contentScale = contentScale
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -73,7 +73,7 @@ class BattleSpriteManager(private val context: Context) {
|
||||
}
|
||||
|
||||
// Load the specific sprite data file
|
||||
val spriteDataFile = File(spriteBaseDir, "sprites/${spriteName}_sprite_00.json")
|
||||
val spriteDataFile = File(spriteBaseDir, "sprites/${spriteName}.json")
|
||||
if (!spriteDataFile.exists()) {
|
||||
println("Sprite data file not found: ${spriteDataFile.absolutePath}")
|
||||
return null
|
||||
|
||||
@ -0,0 +1,113 @@
|
||||
package com.github.nacabaro.vbhelper.battle
|
||||
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.setValue
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
enum class DigimonAnimationType {
|
||||
IDLE,
|
||||
IDLE2,
|
||||
WALK,
|
||||
WALK2,
|
||||
RUN,
|
||||
RUN2,
|
||||
WORKOUT,
|
||||
WORKOUT2,
|
||||
HAPPY,
|
||||
SLEEP,
|
||||
ATTACK,
|
||||
FLEE
|
||||
}
|
||||
|
||||
data class AnimationState(
|
||||
val type: DigimonAnimationType,
|
||||
val spriteIndex: Int, // 00, 01, 02, etc.
|
||||
val duration: Long = 100L, // Duration in milliseconds
|
||||
val loop: Boolean = true
|
||||
)
|
||||
|
||||
class DigimonAnimationStateMachine(
|
||||
private val characterId: String
|
||||
) {
|
||||
var currentAnimation by mutableStateOf<DigimonAnimationType>(DigimonAnimationType.IDLE)
|
||||
private set
|
||||
|
||||
var currentSpriteIndex by mutableStateOf(0)
|
||||
private set
|
||||
|
||||
var isPlaying by mutableStateOf(false)
|
||||
private set
|
||||
|
||||
// Animation mapping - maps animation types to sprite indices
|
||||
// For now, we'll assume the sprite indices 0-11 correspond to the 12 animation types
|
||||
private val animationMapping = mapOf(
|
||||
DigimonAnimationType.IDLE to 0,
|
||||
DigimonAnimationType.IDLE2 to 1,
|
||||
DigimonAnimationType.WALK to 2,
|
||||
DigimonAnimationType.WALK2 to 3,
|
||||
DigimonAnimationType.RUN to 4,
|
||||
DigimonAnimationType.RUN2 to 5,
|
||||
DigimonAnimationType.WORKOUT to 6,
|
||||
DigimonAnimationType.WORKOUT2 to 7,
|
||||
DigimonAnimationType.HAPPY to 8,
|
||||
DigimonAnimationType.SLEEP to 9,
|
||||
DigimonAnimationType.ATTACK to 10,
|
||||
DigimonAnimationType.FLEE to 11
|
||||
)
|
||||
|
||||
// Animation durations for each type
|
||||
private val animationDurations = mapOf(
|
||||
DigimonAnimationType.IDLE to 500L,
|
||||
DigimonAnimationType.IDLE2 to 500L,
|
||||
DigimonAnimationType.WALK to 200L,
|
||||
DigimonAnimationType.WALK2 to 200L,
|
||||
DigimonAnimationType.RUN to 150L,
|
||||
DigimonAnimationType.RUN2 to 150L,
|
||||
DigimonAnimationType.WORKOUT to 300L,
|
||||
DigimonAnimationType.WORKOUT2 to 300L,
|
||||
DigimonAnimationType.HAPPY to 400L,
|
||||
DigimonAnimationType.SLEEP to 1000L,
|
||||
DigimonAnimationType.ATTACK to 300L, // Longer for attack animation
|
||||
DigimonAnimationType.FLEE to 150L
|
||||
)
|
||||
|
||||
suspend fun playAnimation(animationType: DigimonAnimationType) {
|
||||
if (currentAnimation == animationType && isPlaying) {
|
||||
return // Already playing this animation
|
||||
}
|
||||
|
||||
currentAnimation = animationType
|
||||
isPlaying = true
|
||||
|
||||
val spriteIndex = animationMapping[animationType] ?: 0
|
||||
currentSpriteIndex = spriteIndex
|
||||
|
||||
val duration = animationDurations[animationType] ?: 100L
|
||||
|
||||
// For non-looping animations like ATTACK, play once and return to IDLE
|
||||
if (animationType == DigimonAnimationType.ATTACK) {
|
||||
delay(duration)
|
||||
playAnimation(DigimonAnimationType.IDLE)
|
||||
} else {
|
||||
// For looping animations, keep playing
|
||||
while (isPlaying && currentAnimation == animationType) {
|
||||
delay(duration)
|
||||
// For now, we'll just keep the same sprite
|
||||
// In the future, we could cycle through multiple sprites for each animation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun stopAnimation() {
|
||||
isPlaying = false
|
||||
}
|
||||
|
||||
fun getCurrentSpriteName(): String {
|
||||
return "${characterId}_sprite_${String.format("%02d", currentSpriteIndex)}"
|
||||
}
|
||||
|
||||
fun getCurrentAtlasName(): String {
|
||||
return characterId
|
||||
}
|
||||
}
|
||||
@ -49,6 +49,8 @@ import com.github.nacabaro.vbhelper.battle.SpriteImage
|
||||
import com.github.nacabaro.vbhelper.battle.AttackSpriteImage
|
||||
import com.github.nacabaro.vbhelper.battle.SpriteFileManager
|
||||
import com.github.nacabaro.vbhelper.battle.ArenaBattleSystem
|
||||
import com.github.nacabaro.vbhelper.battle.DigimonAnimationType
|
||||
import com.github.nacabaro.vbhelper.battle.AnimatedSpriteImage
|
||||
|
||||
@Composable
|
||||
fun BattleScreen(
|
||||
@ -266,9 +268,18 @@ fun PlayerBattleView(
|
||||
.size(80.dp),
|
||||
contentAlignment = Alignment.CenterStart
|
||||
) {
|
||||
SpriteImage(
|
||||
spriteName = activeCharacter?.charaId ?: "dim011_mon01",
|
||||
atlasName = activeCharacter?.charaId ?: "dim011_mon01",
|
||||
// Determine animation type based on battle state
|
||||
val animationType = when (battleSystem.attackPhase) {
|
||||
1 -> DigimonAnimationType.ATTACK // Player attack on player screen
|
||||
2 -> DigimonAnimationType.ATTACK // Player attack on opponent screen
|
||||
3 -> DigimonAnimationType.IDLE // Opponent attack on opponent screen
|
||||
4 -> DigimonAnimationType.IDLE // Opponent attack on player screen
|
||||
else -> DigimonAnimationType.IDLE
|
||||
}
|
||||
|
||||
AnimatedSpriteImage(
|
||||
characterId = activeCharacter?.charaId ?: "dim011_mon01",
|
||||
animationType = animationType,
|
||||
modifier = Modifier
|
||||
.size(80.dp)
|
||||
.scale(-1f, 1f), // Flip player Digimon horizontally
|
||||
@ -473,9 +484,18 @@ fun OpponentBattleView(
|
||||
.size(80.dp),
|
||||
contentAlignment = Alignment.CenterEnd
|
||||
) {
|
||||
SpriteImage(
|
||||
spriteName = activeCharacter?.charaId ?: "dim011_mon01",
|
||||
atlasName = activeCharacter?.charaId ?: "dim011_mon01",
|
||||
// Determine animation type based on battle state
|
||||
val animationType = when (battleSystem.attackPhase) {
|
||||
1 -> DigimonAnimationType.IDLE // Player attack on player screen
|
||||
2 -> DigimonAnimationType.IDLE // Player attack on opponent screen
|
||||
3 -> DigimonAnimationType.ATTACK // Opponent attack on opponent screen
|
||||
4 -> DigimonAnimationType.ATTACK // Opponent attack on player screen
|
||||
else -> DigimonAnimationType.IDLE
|
||||
}
|
||||
|
||||
AnimatedSpriteImage(
|
||||
characterId = activeCharacter?.charaId ?: "dim011_mon01",
|
||||
animationType = animationType,
|
||||
modifier = Modifier.size(80.dp),
|
||||
contentScale = ContentScale.Fit
|
||||
)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user