Fixed atk sprite import bug. Readjusted sprites to load from individual files instead of full spritesheets.

This commit is contained in:
lightheel 2025-08-05 06:54:55 -04:00
parent fb09350825
commit 71ba5e0207
7 changed files with 356 additions and 163 deletions

View File

@ -13,15 +13,23 @@ fun AnimatedSpriteImage(
characterId: String,
animationType: DigimonAnimationType = DigimonAnimationType.IDLE,
modifier: Modifier = Modifier,
contentScale: ContentScale = ContentScale.Fit
contentScale: ContentScale = ContentScale.Fit,
reloadMappings: Boolean = false
) {
val context = LocalContext.current
val spriteManager = remember { BattleSpriteManager(context) }
val spriteManager = remember { IndividualSpriteManager(context) }
val animationStateMachine = remember { DigimonAnimationStateMachine(characterId, context) }
val coroutineScope = rememberCoroutineScope()
var bitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }
// Reload mappings when reloadMappings parameter changes
LaunchedEffect(reloadMappings) {
if (reloadMappings) {
animationStateMachine.reloadMappings()
}
}
// Start the animation when the component is first created
LaunchedEffect(characterId) {
coroutineScope.launch {
@ -41,17 +49,16 @@ fun AnimatedSpriteImage(
}
// Update sprite when animation state changes
LaunchedEffect(animationStateMachine.currentSpriteIndex) {
val spriteName = animationStateMachine.getCurrentSpriteName()
val atlasName = animationStateMachine.getCurrentAtlasName()
LaunchedEffect(animationStateMachine.currentFrameNumber) {
val frameNumber = animationStateMachine.getCurrentFrame()
println("Loading animated sprite: $spriteName from atlas: $atlasName")
bitmap = spriteManager.loadSprite(spriteName, atlasName)
println("Loading animated sprite frame: $frameNumber for character: $characterId")
bitmap = spriteManager.loadSpriteFrame(characterId, frameNumber)
if (bitmap == null) {
println("Failed to load animated sprite: $spriteName from atlas: $atlasName")
println("Failed to load animated sprite frame: $frameNumber for character: $characterId")
} else {
println("Successfully loaded animated sprite: $spriteName from atlas: $atlasName")
println("Successfully loaded animated sprite frame: $frameNumber for character: $characterId")
}
}

View File

@ -31,8 +31,8 @@ class AttackSpriteManager(private val context: Context) {
private val gson = Gson()
private val characterDataCache = mutableMapOf<String, CharacterData>()
// Base path for attack textures
private val attackTexturesPath = "battle_sprites/extracted_assets/extracted_atksprites"
// Base path for attack textures (updated for new folder structure)
private val attackTexturesPath = "battle_sprites/extracted_atksprites"
fun getAttackSprite(characterId: String, isLarge: Boolean = false): Bitmap? {
println("AttackSpriteManager: Getting attack sprite for characterId=$characterId, isLarge=$isLarge")

View File

@ -6,7 +6,6 @@ import androidx.compose.runtime.setValue
import kotlinx.coroutines.delay
import android.content.Context
import java.io.File
import com.google.gson.Gson
enum class DigimonAnimationType {
IDLE,
@ -25,7 +24,7 @@ enum class DigimonAnimationType {
data class AnimationState(
val type: DigimonAnimationType,
val spriteIndex: Int, // 00, 01, 02, etc.
val frameNumber: Int, // 1-12 for individual PNG files
val duration: Long = 100L, // Duration in milliseconds
val loop: Boolean = true
)
@ -37,30 +36,31 @@ class DigimonAnimationStateMachine(
var currentAnimation by mutableStateOf<DigimonAnimationType>(DigimonAnimationType.IDLE)
private set
var currentSpriteIndex by mutableStateOf(0)
var currentFrameNumber by mutableStateOf(1)
private set
var isPlaying by mutableStateOf(false)
private set
// Animation mapping based on m_Name values
private val mNameToAnimationType = mapOf(
"01" to DigimonAnimationType.IDLE,
"02" to DigimonAnimationType.IDLE2,
"03" to DigimonAnimationType.WALK,
"04" to DigimonAnimationType.WALK2,
"05" to DigimonAnimationType.RUN,
"06" to DigimonAnimationType.RUN2,
"07" to DigimonAnimationType.WORKOUT,
"08" to DigimonAnimationType.WORKOUT2,
"09" to DigimonAnimationType.HAPPY,
"10" to DigimonAnimationType.SLEEP,
"11" to DigimonAnimationType.ATTACK,
"12" to DigimonAnimationType.FLEE
// Direct mapping of frame numbers (1-12) to animation types
// This is based on the standard Digimon sprite frame order
private val frameToAnimationType = mapOf(
1 to DigimonAnimationType.IDLE,
2 to DigimonAnimationType.IDLE2,
3 to DigimonAnimationType.WALK,
4 to DigimonAnimationType.WALK2,
5 to DigimonAnimationType.RUN,
6 to DigimonAnimationType.RUN2,
7 to DigimonAnimationType.WORKOUT,
8 to DigimonAnimationType.WORKOUT2,
9 to DigimonAnimationType.HAPPY,
10 to DigimonAnimationType.SLEEP,
11 to DigimonAnimationType.ATTACK,
12 to DigimonAnimationType.FLEE
)
// Cache for sprite file mappings
private var spriteFileMappings: Map<DigimonAnimationType, List<String>> = emptyMap()
// Reverse mapping for getting frame numbers for each animation type
private val animationTypeToFrames = frameToAnimationType.entries.groupBy({ it.value }, { it.key })
// Animation durations for each type
private val animationDurations = mapOf(
@ -79,58 +79,8 @@ class DigimonAnimationStateMachine(
)
init {
loadSpriteFileMappings()
}
private fun loadSpriteFileMappings() {
try {
val spriteBaseDir = File(context.filesDir, "battle_sprites/extracted_assets/sprites")
val gson = Gson()
val mappings = mutableMapOf<DigimonAnimationType, MutableList<String>>()
// Initialize all animation types
DigimonAnimationType.values().forEach { animationType ->
mappings[animationType] = mutableListOf()
}
println("Loading sprite mappings for character: $characterId")
// Scan all sprite files for this character
val spriteFiles = spriteBaseDir.listFiles { file ->
file.name.startsWith("${characterId}_sprite_") && file.name.endsWith(".json")
}
println("Found ${spriteFiles?.size ?: 0} sprite files for $characterId")
spriteFiles?.forEach { spriteFile ->
println("Processing sprite file: ${spriteFile.name}")
val spriteDataJson = spriteFile.readText()
val spriteData = gson.fromJson(spriteDataJson, SpriteData::class.java)
println(" m_Name: ${spriteData.m_Name}")
// Get the animation type from m_Name
val animationType = mNameToAnimationType[spriteData.m_Name]
if (animationType != null) {
// Extract the sprite index from filename (e.g., "dim000_mon01_sprite_00.json" -> "00")
val spriteIndex = spriteFile.name.substringAfter("_sprite_").substringBefore(".json")
mappings[animationType]?.add(spriteIndex)
println(" Mapped to animation type: $animationType with sprite index: $spriteIndex")
} else {
println(" Unknown m_Name: ${spriteData.m_Name}")
}
}
// Convert to immutable map
spriteFileMappings = mappings.mapValues { it.value.sorted() }
println("Final sprite mappings for $characterId: $spriteFileMappings")
} catch (e: Exception) {
println("Error loading sprite file mappings: ${e.message}")
e.printStackTrace()
}
println("Initialized DigimonAnimationStateMachine for character: $characterId")
println("Available animation types: ${animationTypeToFrames.keys}")
}
suspend fun playAnimation(animationType: DigimonAnimationType) {
@ -141,27 +91,22 @@ class DigimonAnimationStateMachine(
currentAnimation = animationType
isPlaying = true
val frameSequence = spriteFileMappings[animationType] ?: listOf("00")
val frameNumbers = animationTypeToFrames[animationType] ?: listOf(1)
val duration = animationDurations[animationType] ?: 100L
// Ensure we have at least one frame
if (frameSequence.isEmpty()) {
println("Warning: No sprite files found for animation type $animationType")
currentSpriteIndex = 0
return
}
println("Playing animation: $animationType with frames: $frameNumbers")
// For non-looping animations like ATTACK, play once and return to IDLE
if (animationType == DigimonAnimationType.ATTACK) {
currentSpriteIndex = frameSequence.firstOrNull()?.toIntOrNull() ?: 0
currentFrameNumber = frameNumbers.firstOrNull() ?: 1
delay(duration)
playAnimation(DigimonAnimationType.IDLE)
} else {
// For looping animations, cycle through frames
var frameIndex = 0
while (isPlaying && currentAnimation == animationType) {
val spriteIndex = frameSequence[frameIndex % frameSequence.size]
currentSpriteIndex = spriteIndex.toIntOrNull() ?: 0
val frameNumber = frameNumbers[frameIndex % frameNumbers.size]
currentFrameNumber = frameNumber
delay(duration)
frameIndex++
}
@ -177,26 +122,21 @@ class DigimonAnimationStateMachine(
currentAnimation = DigimonAnimationType.IDLE
isPlaying = true
val idleFrames = spriteFileMappings[DigimonAnimationType.IDLE] ?: listOf("00")
val idle2Frames = spriteFileMappings[DigimonAnimationType.HAPPY] ?: listOf("08")
val idleFrames = animationTypeToFrames[DigimonAnimationType.IDLE] ?: listOf(1)
val idle2Frames = animationTypeToFrames[DigimonAnimationType.IDLE2] ?: listOf(2)
// Combine frames for cycling idle animation
val combinedFrames = (idleFrames + idle2Frames).distinct()
if (combinedFrames.isEmpty()) {
println("Warning: No idle sprite files found")
currentSpriteIndex = 0
return
}
println("Playing idle animation with frames: $combinedFrames")
val duration = animationDurations[DigimonAnimationType.IDLE] ?: 500L
// Cycle through idle frames
var frameIndex = 0
while (isPlaying && currentAnimation == DigimonAnimationType.IDLE) {
val spriteIndex = combinedFrames[frameIndex % combinedFrames.size]
currentSpriteIndex = spriteIndex.toIntOrNull() ?: 0
val frameNumber = combinedFrames[frameIndex % combinedFrames.size]
currentFrameNumber = frameNumber
delay(duration)
frameIndex++
}
@ -206,11 +146,17 @@ class DigimonAnimationStateMachine(
isPlaying = false
}
fun getCurrentSpriteName(): String {
return "${characterId}_sprite_${String.format("%02d", currentSpriteIndex)}"
fun getCurrentFrame(): Int {
return currentFrameNumber
}
fun getCurrentAtlasName(): String {
fun getCurrentCharacterId(): String {
return characterId
}
// Method to reload mappings (useful for testing)
fun reloadMappings() {
println("Reloading mappings for character: $characterId")
// No need to reload since we use direct frame mapping
}
}

View File

@ -0,0 +1,142 @@
package com.github.nacabaro.vbhelper.battle
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import java.io.File
class IndividualSpriteManager(private val context: Context) {
private val spriteCache = mutableMapOf<String, Bitmap>()
// Base directory where individual sprite PNGs are stored
private val spriteBaseDir = File(context.filesDir, "battle_sprites/extracted_assets/sprites")
/**
* Load a specific sprite frame for a character
* @param characterId The character ID (e.g., "dim012_mon03")
* @param frameNumber The frame number (1-12)
* @return Bitmap of the sprite frame, or null if not found
*/
fun loadSpriteFrame(characterId: String, frameNumber: Int): Bitmap? {
val cacheKey = "${characterId}_frame_${frameNumber}"
// Check cache first
if (spriteCache.containsKey(cacheKey)) {
return spriteCache[cacheKey]
}
// Debug: Check if base directory exists
if (!spriteBaseDir.exists()) {
println("Sprite base directory does not exist: ${spriteBaseDir.absolutePath}")
return null
}
try {
// Construct the sprite file path
val spriteFileName = "${characterId}_${String.format("%02d", frameNumber)}.png"
val spriteFile = File(spriteBaseDir, "$characterId/$spriteFileName")
if (!spriteFile.exists()) {
println("Sprite file not found: ${spriteFile.absolutePath}")
return null
}
// Load the PNG file directly
val bitmap = BitmapFactory.decodeFile(spriteFile.absolutePath)
if (bitmap == null) {
println("Failed to decode sprite file: ${spriteFile.absolutePath}")
return null
}
println("Successfully loaded sprite frame: $spriteFileName (${bitmap.width}x${bitmap.height})")
// Cache the result
spriteCache[cacheKey] = bitmap
return bitmap
} catch (e: Exception) {
println("Error loading sprite frame: ${e.message}")
e.printStackTrace()
return null
}
}
/**
* Get all available sprite frames for a character
* @param characterId The character ID
* @return List of frame numbers (1-12) that exist for this character
*/
fun getAvailableFrames(characterId: String): List<Int> {
try {
val characterDir = File(spriteBaseDir, characterId)
if (!characterDir.exists()) {
println("Character directory not found: ${characterDir.absolutePath}")
return emptyList()
}
val spriteFiles = characterDir.listFiles { file ->
file.name.startsWith("${characterId}_") && file.name.endsWith(".png")
} ?: emptyArray()
return spriteFiles.mapNotNull { file ->
// Extract frame number from filename (e.g., "dim012_mon03_01.png" -> 1)
val frameNumberStr = file.name.substringAfter("_").substringBefore(".png")
frameNumberStr.toIntOrNull()
}.sorted()
} catch (e: Exception) {
println("Error getting available frames: ${e.message}")
e.printStackTrace()
return emptyList()
}
}
/**
* Get all available characters
* @return List of character IDs that have sprite directories
*/
fun getAvailableCharacters(): List<String> {
try {
if (!spriteBaseDir.exists()) {
return emptyList()
}
val characterDirs = spriteBaseDir.listFiles { file ->
file.isDirectory && file.name.matches(Regex("dim\\d+_mon\\d+.*"))
} ?: emptyArray()
return characterDirs.map { it.name }.sorted()
} catch (e: Exception) {
println("Error getting available characters: ${e.message}")
e.printStackTrace()
return emptyList()
}
}
/**
* Clear the sprite cache
*/
fun clearCache() {
spriteCache.clear()
}
/**
* Check if a character has sprite files
* @param characterId The character ID to check
* @return true if the character has sprite files, false otherwise
*/
fun hasCharacterSprites(characterId: String): Boolean {
val characterDir = File(spriteBaseDir, characterId)
if (!characterDir.exists()) {
return false
}
val spriteFiles = characterDir.listFiles { file ->
file.name.startsWith("${characterId}_") && file.name.endsWith(".png")
} ?: emptyArray()
return spriteFiles.isNotEmpty()
}
}

View File

@ -9,26 +9,90 @@ class SpriteFileManager(private val context: Context) {
fun copySpriteFilesToInternalStorage() {
try {
// Create the base directory for extracted_assets
val extractedAssetsDir = File(context.filesDir, "battle_sprites/extracted_assets")
if (!extractedAssetsDir.exists()) {
extractedAssetsDir.mkdirs()
println("Starting sprite file copy process...")
// Debug: List what's in the assets directory
val assetManager = context.assets
val battleSpritesFiles = assetManager.list("battle_sprites")
println("battle_sprites directory in assets contains: ${battleSpritesFiles?.joinToString(", ")}")
val extractedAssetsFiles = assetManager.list("battle_sprites/extracted_assets")
println("battle_sprites/extracted_assets directory in assets contains: ${extractedAssetsFiles?.joinToString(", ")}")
// Check specifically for extracted_atksprites in assets (now directly under battle_sprites)
val atkspritesInAssets = assetManager.list("battle_sprites/extracted_atksprites")
println("extracted_atksprites in assets contains: ${atkspritesInAssets?.size ?: 0} files")
if (atkspritesInAssets != null && atkspritesInAssets.isNotEmpty()) {
println("First few attack files in assets: ${atkspritesInAssets.take(5).joinToString(", ")}")
}
// Create the base directory for extracted_digimon_stats
val extractedStatsDir = File(context.filesDir, "battle_sprites/extracted_digimon_stats")
if (!extractedStatsDir.exists()) {
extractedStatsDir.mkdirs()
// Check for extracted_battlebgs in assets (now directly under battle_sprites)
val battlebgsInAssets = assetManager.list("battle_sprites/extracted_battlebgs")
println("extracted_battlebgs in assets contains: ${battlebgsInAssets?.size ?: 0} files")
if (battlebgsInAssets != null && battlebgsInAssets.isNotEmpty()) {
println("First few battle background files in assets: ${battlebgsInAssets.take(5).joinToString(", ")}")
}
// Copy extracted_assets files from assets to internal storage
copyAssetDirectory("battle_sprites/extracted_assets", extractedAssetsDir)
// Try to list all possible subdirectories in battle_sprites
println("Checking all possible subdirectories in battle_sprites...")
battleSpritesFiles?.forEach { subdir ->
try {
val subdirFiles = assetManager.list("battle_sprites/$subdir")
println(" $subdir contains: ${subdirFiles?.size ?: 0} files")
if (subdirFiles != null && subdirFiles.isNotEmpty()) {
println(" First few files: ${subdirFiles.take(3).joinToString(", ")}")
}
} catch (e: Exception) {
println(" Error listing $subdir: ${e.message}")
}
}
// Copy extracted_digimon_stats files from assets to internal storage
copyAssetDirectory("battle_sprites/extracted_digimon_stats", extractedStatsDir)
// Create the base directory for battle_sprites
val battleSpritesDir = File(context.filesDir, "battle_sprites")
if (!battleSpritesDir.exists()) {
battleSpritesDir.mkdirs()
println("Created battle_sprites directory: ${battleSpritesDir.absolutePath}")
} else {
println("battle_sprites directory already exists: ${battleSpritesDir.absolutePath}")
}
println("Sprite files copied successfully to: ${extractedAssetsDir.absolutePath}")
println("Stats files copied successfully to: ${extractedStatsDir.absolutePath}")
// Copy all subdirectories from battle_sprites assets to internal storage
println("Copying all battle_sprites subdirectories...")
battleSpritesFiles?.forEach { subdir ->
val sourcePath = "battle_sprites/$subdir"
val targetDir = File(battleSpritesDir, subdir)
println("Copying $sourcePath to ${targetDir.absolutePath}")
copyAssetDirectory(sourcePath, targetDir)
}
println("Sprite files copied successfully to: ${battleSpritesDir.absolutePath}")
// Verify that attack sprites were copied
val atkspritesDir = File(battleSpritesDir, "extracted_atksprites")
if (atkspritesDir.exists()) {
val attackFiles = atkspritesDir.listFiles()
println("Attack sprites directory exists with ${attackFiles?.size ?: 0} files")
if (attackFiles != null && attackFiles.isNotEmpty()) {
println("First few attack files: ${attackFiles.take(5).map { it.name }}")
}
} else {
println("WARNING: extracted_atksprites directory does not exist!")
// List what's actually in the battle_sprites directory
val battleSpritesContents = battleSpritesDir.listFiles()
println("battle_sprites directory contains: ${battleSpritesContents?.map { it.name }?.joinToString(", ")}")
}
// Verify that battle backgrounds were copied
val battlebgsDir = File(battleSpritesDir, "extracted_battlebgs")
if (battlebgsDir.exists()) {
val bgFiles = battlebgsDir.listFiles()
println("Battle backgrounds directory exists with ${bgFiles?.size ?: 0} files")
if (bgFiles != null && bgFiles.isNotEmpty()) {
println("First few battle background files: ${bgFiles.take(5).map { it.name }}")
}
} else {
println("WARNING: extracted_battlebgs directory does not exist!")
}
} catch (e: Exception) {
println("Error copying sprite files: ${e.message}")
@ -41,6 +105,9 @@ class SpriteFileManager(private val context: Context) {
val assetManager = context.assets
val files = assetManager.list(assetPath) ?: return
println("Copying asset directory: $assetPath (${files.size} items)")
println("Files found: ${files.joinToString(", ")}")
for (file in files) {
val assetFilePath = if (assetPath.isEmpty()) file else "$assetPath/$file"
val targetFile = File(targetDir, file)
@ -50,21 +117,50 @@ class SpriteFileManager(private val context: Context) {
targetFile.parentFile!!.mkdirs()
}
// Check if it's a directory
val subFiles = assetManager.list(assetFilePath)
if (subFiles != null && subFiles.isNotEmpty()) {
// It's a directory, create it and copy contents
if (!targetFile.exists()) {
targetFile.mkdirs()
// Check if it's a directory by trying to list its contents
try {
val subFiles = assetManager.list(assetFilePath)
if (subFiles != null && subFiles.isNotEmpty()) {
// It's a directory, create it and copy contents
println("Copying subdirectory: $assetFilePath (${subFiles.size} files)")
if (!targetFile.exists()) {
targetFile.mkdirs()
}
copyAssetDirectory(assetFilePath, targetFile)
} else {
// It's a file, copy it
copyAssetFile(assetFilePath, targetFile)
}
copyAssetDirectory(assetFilePath, targetFile)
} else {
// It's a file, copy it
} catch (e: Exception) {
// If we can't list contents, it's probably a file
println("Treating $assetFilePath as file (could not list contents)")
copyAssetFile(assetFilePath, targetFile)
}
}
// Special handling for extracted_atksprites - try to copy it directly if it wasn't found
if (assetPath == "battle_sprites/extracted_assets") {
println("Special handling: Checking for extracted_atksprites directory...")
try {
val atkspritesFiles = assetManager.list("battle_sprites/extracted_assets/extracted_atksprites")
if (atkspritesFiles != null && atkspritesFiles.isNotEmpty()) {
println("Found extracted_atksprites with ${atkspritesFiles.size} files")
val atkspritesDir = File(targetDir, "extracted_atksprites")
if (!atkspritesDir.exists()) {
atkspritesDir.mkdirs()
}
copyAssetDirectory("battle_sprites/extracted_assets/extracted_atksprites", atkspritesDir)
} else {
println("extracted_atksprites directory not found in assets")
}
} catch (e: Exception) {
println("Error checking extracted_atksprites: ${e.message}")
}
}
} catch (e: Exception) {
println("Error copying asset directory $assetPath: ${e.message}")
e.printStackTrace()
}
}
@ -84,34 +180,34 @@ class SpriteFileManager(private val context: Context) {
}
fun checkSpriteFilesExist(): Boolean {
val extractedAssetsDir = File(context.filesDir, "battle_sprites/extracted_assets")
val extractedStatsDir = File(context.filesDir, "battle_sprites/extracted_digimon_stats")
val battleSpritesDir = File(context.filesDir, "battle_sprites")
val extractedAssetsDir = File(battleSpritesDir, "extracted_assets")
val extractedStatsDir = File(battleSpritesDir, "extracted_digimon_stats")
val atkspritesDir = File(battleSpritesDir, "extracted_atksprites")
val battlebgsDir = File(battleSpritesDir, "extracted_battlebgs")
val battleSpritesExist = battleSpritesDir.exists() && battleSpritesDir.listFiles()?.isNotEmpty() == true
val assetsExist = extractedAssetsDir.exists() && extractedAssetsDir.listFiles()?.isNotEmpty() == true
val statsExist = extractedStatsDir.exists() && extractedStatsDir.listFiles()?.isNotEmpty() == true
val atkspritesExist = atkspritesDir.exists() && atkspritesDir.listFiles()?.isNotEmpty() == true
val battlebgsExist = battlebgsDir.exists() && battlebgsDir.listFiles()?.isNotEmpty() == true
return assetsExist && statsExist
println("Checking sprite files exist:")
println(" battle_sprites exists: $battleSpritesExist")
println(" extracted_assets exists: $assetsExist")
println(" extracted_digimon_stats exists: $statsExist")
println(" extracted_atksprites exists: $atkspritesExist")
println(" extracted_battlebgs exists: $battlebgsExist")
return battleSpritesExist && assetsExist && statsExist && atkspritesExist && battlebgsExist
}
fun clearSpriteFiles() {
try {
val extractedAssetsDir = File(context.filesDir, "battle_sprites/extracted_assets")
val extractedStatsDir = File(context.filesDir, "battle_sprites/extracted_digimon_stats")
if (extractedAssetsDir.exists()) {
deleteDirectory(extractedAssetsDir)
println("Cleared extracted_assets directory")
}
if (extractedStatsDir.exists()) {
deleteDirectory(extractedStatsDir)
println("Cleared extracted_digimon_stats directory")
}
// Also clear the battle_sprites directory if it's empty
val battleSpritesDir = File(context.filesDir, "battle_sprites")
if (battleSpritesDir.exists() && battleSpritesDir.listFiles()?.isEmpty() == true) {
battleSpritesDir.delete()
if (battleSpritesDir.exists()) {
deleteDirectory(battleSpritesDir)
println("Cleared battle_sprites directory")
}

View File

@ -6,34 +6,33 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import com.github.nacabaro.vbhelper.battle.BattleSpriteManager
@Composable
fun SpriteImage(
spriteName: String,
atlasName: String,
characterId: String,
frameNumber: Int,
modifier: Modifier = Modifier,
contentScale: ContentScale = ContentScale.Fit
) {
val context = LocalContext.current
val spriteManager = remember { BattleSpriteManager(context) }
val spriteManager = remember { IndividualSpriteManager(context) }
var bitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }
LaunchedEffect(spriteName, atlasName) {
println("Loading sprite: $spriteName from atlas: $atlasName")
bitmap = spriteManager.loadSprite(spriteName, atlasName)
LaunchedEffect(characterId, frameNumber) {
println("Loading sprite frame: $frameNumber for character: $characterId")
bitmap = spriteManager.loadSpriteFrame(characterId, frameNumber)
if (bitmap == null) {
println("Failed to load sprite: $spriteName from atlas: $atlasName")
println("Failed to load sprite frame: $frameNumber for character: $characterId")
} else {
println("Successfully loaded sprite: $spriteName from atlas: $atlasName")
println("Successfully loaded sprite frame: $frameNumber for character: $characterId")
}
}
bitmap?.let { bmp ->
Image(
bitmap = bmp.asImageBitmap(),
contentDescription = "Sprite: $spriteName",
contentDescription = "Sprite: $characterId frame $frameNumber",
modifier = modifier,
contentScale = contentScale
)

View File

@ -45,7 +45,6 @@ import com.github.nacabaro.vbhelper.battle.APIBattleCharacter
import android.util.Log
import com.github.nacabaro.vbhelper.components.TopBanner
import com.github.nacabaro.vbhelper.battle.RetrofitHelper
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
@ -286,7 +285,8 @@ fun PlayerBattleView(
modifier = Modifier
.size(80.dp)
.scale(-1f, 1f), // Flip player Digimon horizontally
contentScale = ContentScale.Fit
contentScale = ContentScale.Fit,
reloadMappings = false
)
// Attack sprite visibility and positioning based on attack phase
@ -500,7 +500,8 @@ fun OpponentBattleView(
characterId = activeCharacter?.charaId ?: "dim011_mon01",
animationType = animationType,
modifier = Modifier.size(80.dp),
contentScale = ContentScale.Fit
contentScale = ContentScale.Fit,
reloadMappings = false
)
// Attack sprite visibility and positioning based on attack phase
@ -642,12 +643,13 @@ fun BattlesScreen() {
// Initialize sprite files on first load
LaunchedEffect(Unit) {
println("BATTLESCREEN: LaunchedEffect triggered - checking sprite files...")
val spriteFileManager = SpriteFileManager(context)
if (!spriteFileManager.checkSpriteFilesExist()) {
println("Copying sprite files to internal storage...")
println("BATTLESCREEN: Copying sprite files to internal storage...")
spriteFileManager.copySpriteFilesToInternalStorage()
} else {
println("Sprite files already exist in internal storage")
println("BATTLESCREEN: Sprite files already exist in internal storage")
}
}
@ -856,7 +858,8 @@ fun BattlesScreen() {
characterId = testCharacterId,
animationType = currentTestAnimation,
modifier = Modifier.size(120.dp),
contentScale = ContentScale.Fit
contentScale = ContentScale.Fit,
reloadMappings = false
)
Spacer(modifier = Modifier.height(16.dp))