diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/AnimatedSpriteImage.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/AnimatedSpriteImage.kt index e8c2049..ae872bf 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/battle/AnimatedSpriteImage.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/AnimatedSpriteImage.kt @@ -7,6 +7,7 @@ import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalContext import kotlinx.coroutines.launch +import kotlinx.coroutines.delay @Composable fun AnimatedSpriteImage( @@ -14,11 +15,22 @@ fun AnimatedSpriteImage( animationType: DigimonAnimationType = DigimonAnimationType.IDLE, modifier: Modifier = Modifier, contentScale: ContentScale = ContentScale.Fit, - reloadMappings: Boolean = false + reloadMappings: Boolean = false, + animationOffset: Long = 0L // New parameter for offsetting animation timing ) { val context = LocalContext.current val spriteManager = remember { IndividualSpriteManager(context) } - val animationStateMachine = remember { DigimonAnimationStateMachine(characterId, context) } + + // Calculate frame offset based on animation offset + // 750ms is the idle animation duration, so we calculate how many frames to offset + val frameOffset = if (animationOffset > 0L) { + // Convert time offset to frame offset (2 frames per cycle, 750ms per frame) + ((animationOffset / 750L) * 2).toInt() + } else { + 0 + } + + val animationStateMachine = remember { DigimonAnimationStateMachine(characterId, context, frameOffset, animationOffset) } val coroutineScope = rememberCoroutineScope() var bitmap by remember { mutableStateOf(null) } diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/battle/DigimonAnimationState.kt b/app/src/main/java/com/github/nacabaro/vbhelper/battle/DigimonAnimationState.kt index 2ff49cd..d23ea11 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/battle/DigimonAnimationState.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/battle/DigimonAnimationState.kt @@ -31,7 +31,9 @@ data class AnimationState( class DigimonAnimationStateMachine( private val characterId: String, - private val context: Context + private val context: Context, + private val initialFrameOffset: Int = 0, // New parameter for offsetting the starting frame + private val timingOffset: Long = 0L // New parameter for offsetting the timing ) { var currentAnimation by mutableStateOf(DigimonAnimationType.IDLE) private set @@ -79,7 +81,7 @@ class DigimonAnimationStateMachine( ) init { - println("Initialized DigimonAnimationStateMachine for character: $characterId") + println("Initialized DigimonAnimationStateMachine for character: $characterId with frame offset: $initialFrameOffset, timing offset: $timingOffset") println("Available animation types: ${animationTypeToFrames.keys}") } @@ -128,12 +130,17 @@ class DigimonAnimationStateMachine( // Combine frames for cycling idle animation val combinedFrames = (idleFrames + idle2Frames).distinct() - println("Playing idle animation with frames: $combinedFrames") + println("Playing idle animation with frames: $combinedFrames, starting at offset: $initialFrameOffset, timing offset: $timingOffset") val duration = animationDurations[DigimonAnimationType.IDLE] ?: 500L - // Cycle through idle frames - var frameIndex = 0 + // Apply initial timing offset + if (timingOffset > 0L) { + delay(timingOffset) + } + + // Cycle through idle frames, starting from the offset + var frameIndex = initialFrameOffset while (isPlaying && currentAnimation == DigimonAnimationType.IDLE) { val frameNumber = combinedFrames[frameIndex % combinedFrames.size] currentFrameNumber = frameNumber diff --git a/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt b/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt index 065308a..4711ca5 100644 --- a/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt +++ b/app/src/main/java/com/github/nacabaro/vbhelper/screens/BattlesScreen.kt @@ -730,7 +730,8 @@ fun MiddleBattleView( y = enemyVerticalOffset + 40.dp ), contentScale = ContentScale.Fit, - reloadMappings = false + reloadMappings = false, + animationOffset = 375L // Offset enemy animation by half the idle duration ) // Enemy attack sprite (Phase 1 only) @@ -811,7 +812,8 @@ fun MiddleBattleView( y = playerVerticalOffset - 40.dp ), contentScale = ContentScale.Fit, - reloadMappings = false + reloadMappings = false, + animationOffset = 0L // Player animation starts immediately ) // Player attack sprite (Phase 1 only) @@ -1149,7 +1151,8 @@ fun PlayerBattleView( y = verticalOffset ), contentScale = ContentScale.Fit, - reloadMappings = false + reloadMappings = false, + animationOffset = 0L // Player animation starts immediately ) // Attack sprite visibility and positioning based on attack phase @@ -1456,7 +1459,8 @@ fun EnemyBattleView( y = verticalOffset ), contentScale = ContentScale.Fit, - reloadMappings = false + reloadMappings = false, + animationOffset = 375L // Offset enemy animation by half the idle duration ) // Attack sprite visibility and positioning based on attack phase @@ -1797,7 +1801,8 @@ fun BattlesScreen() { animationType = currentTestAnimation, modifier = Modifier.size(120.dp), contentScale = ContentScale.Fit, - reloadMappings = false + reloadMappings = false, + animationOffset = 0L // No offset for sprite tester ) Spacer(modifier = Modifier.height(16.dp))