mirror of
https://github.com/nacabaro/vbhelper.git
synced 2026-06-05 22:02: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
|
// 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()) {
|
if (!spriteDataFile.exists()) {
|
||||||
println("Sprite data file not found: ${spriteDataFile.absolutePath}")
|
println("Sprite data file not found: ${spriteDataFile.absolutePath}")
|
||||||
return null
|
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.AttackSpriteImage
|
||||||
import com.github.nacabaro.vbhelper.battle.SpriteFileManager
|
import com.github.nacabaro.vbhelper.battle.SpriteFileManager
|
||||||
import com.github.nacabaro.vbhelper.battle.ArenaBattleSystem
|
import com.github.nacabaro.vbhelper.battle.ArenaBattleSystem
|
||||||
|
import com.github.nacabaro.vbhelper.battle.DigimonAnimationType
|
||||||
|
import com.github.nacabaro.vbhelper.battle.AnimatedSpriteImage
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun BattleScreen(
|
fun BattleScreen(
|
||||||
@ -266,9 +268,18 @@ fun PlayerBattleView(
|
|||||||
.size(80.dp),
|
.size(80.dp),
|
||||||
contentAlignment = Alignment.CenterStart
|
contentAlignment = Alignment.CenterStart
|
||||||
) {
|
) {
|
||||||
SpriteImage(
|
// Determine animation type based on battle state
|
||||||
spriteName = activeCharacter?.charaId ?: "dim011_mon01",
|
val animationType = when (battleSystem.attackPhase) {
|
||||||
atlasName = activeCharacter?.charaId ?: "dim011_mon01",
|
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
|
modifier = Modifier
|
||||||
.size(80.dp)
|
.size(80.dp)
|
||||||
.scale(-1f, 1f), // Flip player Digimon horizontally
|
.scale(-1f, 1f), // Flip player Digimon horizontally
|
||||||
@ -473,9 +484,18 @@ fun OpponentBattleView(
|
|||||||
.size(80.dp),
|
.size(80.dp),
|
||||||
contentAlignment = Alignment.CenterEnd
|
contentAlignment = Alignment.CenterEnd
|
||||||
) {
|
) {
|
||||||
SpriteImage(
|
// Determine animation type based on battle state
|
||||||
spriteName = activeCharacter?.charaId ?: "dim011_mon01",
|
val animationType = when (battleSystem.attackPhase) {
|
||||||
atlasName = activeCharacter?.charaId ?: "dim011_mon01",
|
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),
|
modifier = Modifier.size(80.dp),
|
||||||
contentScale = ContentScale.Fit
|
contentScale = ContentScale.Fit
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user