mirror of
https://github.com/nacabaro/vbhelper.git
synced 2026-06-05 22:02:54 +00:00
Fixed atk sprite import bug. Readjusted sprites to load from individual files instead of full spritesheets.
This commit is contained in:
parent
fb09350825
commit
71ba5e0207
@ -13,15 +13,23 @@ fun AnimatedSpriteImage(
|
|||||||
characterId: String,
|
characterId: String,
|
||||||
animationType: DigimonAnimationType = DigimonAnimationType.IDLE,
|
animationType: DigimonAnimationType = DigimonAnimationType.IDLE,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
contentScale: ContentScale = ContentScale.Fit
|
contentScale: ContentScale = ContentScale.Fit,
|
||||||
|
reloadMappings: Boolean = false
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val spriteManager = remember { BattleSpriteManager(context) }
|
val spriteManager = remember { IndividualSpriteManager(context) }
|
||||||
val animationStateMachine = remember { DigimonAnimationStateMachine(characterId, context) }
|
val animationStateMachine = remember { DigimonAnimationStateMachine(characterId, context) }
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
var bitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }
|
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
|
// Start the animation when the component is first created
|
||||||
LaunchedEffect(characterId) {
|
LaunchedEffect(characterId) {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
@ -41,17 +49,16 @@ fun AnimatedSpriteImage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update sprite when animation state changes
|
// Update sprite when animation state changes
|
||||||
LaunchedEffect(animationStateMachine.currentSpriteIndex) {
|
LaunchedEffect(animationStateMachine.currentFrameNumber) {
|
||||||
val spriteName = animationStateMachine.getCurrentSpriteName()
|
val frameNumber = animationStateMachine.getCurrentFrame()
|
||||||
val atlasName = animationStateMachine.getCurrentAtlasName()
|
|
||||||
|
|
||||||
println("Loading animated sprite: $spriteName from atlas: $atlasName")
|
println("Loading animated sprite frame: $frameNumber for character: $characterId")
|
||||||
bitmap = spriteManager.loadSprite(spriteName, atlasName)
|
bitmap = spriteManager.loadSpriteFrame(characterId, frameNumber)
|
||||||
|
|
||||||
if (bitmap == null) {
|
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 {
|
} else {
|
||||||
println("Successfully loaded animated sprite: $spriteName from atlas: $atlasName")
|
println("Successfully loaded animated sprite frame: $frameNumber for character: $characterId")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -31,8 +31,8 @@ class AttackSpriteManager(private val context: Context) {
|
|||||||
private val gson = Gson()
|
private val gson = Gson()
|
||||||
private val characterDataCache = mutableMapOf<String, CharacterData>()
|
private val characterDataCache = mutableMapOf<String, CharacterData>()
|
||||||
|
|
||||||
// Base path for attack textures
|
// Base path for attack textures (updated for new folder structure)
|
||||||
private val attackTexturesPath = "battle_sprites/extracted_assets/extracted_atksprites"
|
private val attackTexturesPath = "battle_sprites/extracted_atksprites"
|
||||||
|
|
||||||
fun getAttackSprite(characterId: String, isLarge: Boolean = false): Bitmap? {
|
fun getAttackSprite(characterId: String, isLarge: Boolean = false): Bitmap? {
|
||||||
println("AttackSpriteManager: Getting attack sprite for characterId=$characterId, isLarge=$isLarge")
|
println("AttackSpriteManager: Getting attack sprite for characterId=$characterId, isLarge=$isLarge")
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import androidx.compose.runtime.setValue
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import com.google.gson.Gson
|
|
||||||
|
|
||||||
enum class DigimonAnimationType {
|
enum class DigimonAnimationType {
|
||||||
IDLE,
|
IDLE,
|
||||||
@ -25,7 +24,7 @@ enum class DigimonAnimationType {
|
|||||||
|
|
||||||
data class AnimationState(
|
data class AnimationState(
|
||||||
val type: DigimonAnimationType,
|
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 duration: Long = 100L, // Duration in milliseconds
|
||||||
val loop: Boolean = true
|
val loop: Boolean = true
|
||||||
)
|
)
|
||||||
@ -37,30 +36,31 @@ class DigimonAnimationStateMachine(
|
|||||||
var currentAnimation by mutableStateOf<DigimonAnimationType>(DigimonAnimationType.IDLE)
|
var currentAnimation by mutableStateOf<DigimonAnimationType>(DigimonAnimationType.IDLE)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var currentSpriteIndex by mutableStateOf(0)
|
var currentFrameNumber by mutableStateOf(1)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
var isPlaying by mutableStateOf(false)
|
var isPlaying by mutableStateOf(false)
|
||||||
private set
|
private set
|
||||||
|
|
||||||
// Animation mapping based on m_Name values
|
// Direct mapping of frame numbers (1-12) to animation types
|
||||||
private val mNameToAnimationType = mapOf(
|
// This is based on the standard Digimon sprite frame order
|
||||||
"01" to DigimonAnimationType.IDLE,
|
private val frameToAnimationType = mapOf(
|
||||||
"02" to DigimonAnimationType.IDLE2,
|
1 to DigimonAnimationType.IDLE,
|
||||||
"03" to DigimonAnimationType.WALK,
|
2 to DigimonAnimationType.IDLE2,
|
||||||
"04" to DigimonAnimationType.WALK2,
|
3 to DigimonAnimationType.WALK,
|
||||||
"05" to DigimonAnimationType.RUN,
|
4 to DigimonAnimationType.WALK2,
|
||||||
"06" to DigimonAnimationType.RUN2,
|
5 to DigimonAnimationType.RUN,
|
||||||
"07" to DigimonAnimationType.WORKOUT,
|
6 to DigimonAnimationType.RUN2,
|
||||||
"08" to DigimonAnimationType.WORKOUT2,
|
7 to DigimonAnimationType.WORKOUT,
|
||||||
"09" to DigimonAnimationType.HAPPY,
|
8 to DigimonAnimationType.WORKOUT2,
|
||||||
"10" to DigimonAnimationType.SLEEP,
|
9 to DigimonAnimationType.HAPPY,
|
||||||
"11" to DigimonAnimationType.ATTACK,
|
10 to DigimonAnimationType.SLEEP,
|
||||||
"12" to DigimonAnimationType.FLEE
|
11 to DigimonAnimationType.ATTACK,
|
||||||
|
12 to DigimonAnimationType.FLEE
|
||||||
)
|
)
|
||||||
|
|
||||||
// Cache for sprite file mappings
|
// Reverse mapping for getting frame numbers for each animation type
|
||||||
private var spriteFileMappings: Map<DigimonAnimationType, List<String>> = emptyMap()
|
private val animationTypeToFrames = frameToAnimationType.entries.groupBy({ it.value }, { it.key })
|
||||||
|
|
||||||
// Animation durations for each type
|
// Animation durations for each type
|
||||||
private val animationDurations = mapOf(
|
private val animationDurations = mapOf(
|
||||||
@ -79,58 +79,8 @@ class DigimonAnimationStateMachine(
|
|||||||
)
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
loadSpriteFileMappings()
|
println("Initialized DigimonAnimationStateMachine for character: $characterId")
|
||||||
}
|
println("Available animation types: ${animationTypeToFrames.keys}")
|
||||||
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun playAnimation(animationType: DigimonAnimationType) {
|
suspend fun playAnimation(animationType: DigimonAnimationType) {
|
||||||
@ -141,27 +91,22 @@ class DigimonAnimationStateMachine(
|
|||||||
currentAnimation = animationType
|
currentAnimation = animationType
|
||||||
isPlaying = true
|
isPlaying = true
|
||||||
|
|
||||||
val frameSequence = spriteFileMappings[animationType] ?: listOf("00")
|
val frameNumbers = animationTypeToFrames[animationType] ?: listOf(1)
|
||||||
val duration = animationDurations[animationType] ?: 100L
|
val duration = animationDurations[animationType] ?: 100L
|
||||||
|
|
||||||
// Ensure we have at least one frame
|
println("Playing animation: $animationType with frames: $frameNumbers")
|
||||||
if (frameSequence.isEmpty()) {
|
|
||||||
println("Warning: No sprite files found for animation type $animationType")
|
|
||||||
currentSpriteIndex = 0
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// For non-looping animations like ATTACK, play once and return to IDLE
|
// For non-looping animations like ATTACK, play once and return to IDLE
|
||||||
if (animationType == DigimonAnimationType.ATTACK) {
|
if (animationType == DigimonAnimationType.ATTACK) {
|
||||||
currentSpriteIndex = frameSequence.firstOrNull()?.toIntOrNull() ?: 0
|
currentFrameNumber = frameNumbers.firstOrNull() ?: 1
|
||||||
delay(duration)
|
delay(duration)
|
||||||
playAnimation(DigimonAnimationType.IDLE)
|
playAnimation(DigimonAnimationType.IDLE)
|
||||||
} else {
|
} else {
|
||||||
// For looping animations, cycle through frames
|
// For looping animations, cycle through frames
|
||||||
var frameIndex = 0
|
var frameIndex = 0
|
||||||
while (isPlaying && currentAnimation == animationType) {
|
while (isPlaying && currentAnimation == animationType) {
|
||||||
val spriteIndex = frameSequence[frameIndex % frameSequence.size]
|
val frameNumber = frameNumbers[frameIndex % frameNumbers.size]
|
||||||
currentSpriteIndex = spriteIndex.toIntOrNull() ?: 0
|
currentFrameNumber = frameNumber
|
||||||
delay(duration)
|
delay(duration)
|
||||||
frameIndex++
|
frameIndex++
|
||||||
}
|
}
|
||||||
@ -177,26 +122,21 @@ class DigimonAnimationStateMachine(
|
|||||||
currentAnimation = DigimonAnimationType.IDLE
|
currentAnimation = DigimonAnimationType.IDLE
|
||||||
isPlaying = true
|
isPlaying = true
|
||||||
|
|
||||||
val idleFrames = spriteFileMappings[DigimonAnimationType.IDLE] ?: listOf("00")
|
val idleFrames = animationTypeToFrames[DigimonAnimationType.IDLE] ?: listOf(1)
|
||||||
|
val idle2Frames = animationTypeToFrames[DigimonAnimationType.IDLE2] ?: listOf(2)
|
||||||
val idle2Frames = spriteFileMappings[DigimonAnimationType.HAPPY] ?: listOf("08")
|
|
||||||
|
|
||||||
// Combine frames for cycling idle animation
|
// Combine frames for cycling idle animation
|
||||||
val combinedFrames = (idleFrames + idle2Frames).distinct()
|
val combinedFrames = (idleFrames + idle2Frames).distinct()
|
||||||
|
|
||||||
if (combinedFrames.isEmpty()) {
|
println("Playing idle animation with frames: $combinedFrames")
|
||||||
println("Warning: No idle sprite files found")
|
|
||||||
currentSpriteIndex = 0
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val duration = animationDurations[DigimonAnimationType.IDLE] ?: 500L
|
val duration = animationDurations[DigimonAnimationType.IDLE] ?: 500L
|
||||||
|
|
||||||
// Cycle through idle frames
|
// Cycle through idle frames
|
||||||
var frameIndex = 0
|
var frameIndex = 0
|
||||||
while (isPlaying && currentAnimation == DigimonAnimationType.IDLE) {
|
while (isPlaying && currentAnimation == DigimonAnimationType.IDLE) {
|
||||||
val spriteIndex = combinedFrames[frameIndex % combinedFrames.size]
|
val frameNumber = combinedFrames[frameIndex % combinedFrames.size]
|
||||||
currentSpriteIndex = spriteIndex.toIntOrNull() ?: 0
|
currentFrameNumber = frameNumber
|
||||||
delay(duration)
|
delay(duration)
|
||||||
frameIndex++
|
frameIndex++
|
||||||
}
|
}
|
||||||
@ -206,11 +146,17 @@ class DigimonAnimationStateMachine(
|
|||||||
isPlaying = false
|
isPlaying = false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCurrentSpriteName(): String {
|
fun getCurrentFrame(): Int {
|
||||||
return "${characterId}_sprite_${String.format("%02d", currentSpriteIndex)}"
|
return currentFrameNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getCurrentAtlasName(): String {
|
fun getCurrentCharacterId(): String {
|
||||||
return characterId
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -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()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,26 +9,90 @@ class SpriteFileManager(private val context: Context) {
|
|||||||
|
|
||||||
fun copySpriteFilesToInternalStorage() {
|
fun copySpriteFilesToInternalStorage() {
|
||||||
try {
|
try {
|
||||||
// Create the base directory for extracted_assets
|
println("Starting sprite file copy process...")
|
||||||
val extractedAssetsDir = File(context.filesDir, "battle_sprites/extracted_assets")
|
|
||||||
if (!extractedAssetsDir.exists()) {
|
// Debug: List what's in the assets directory
|
||||||
extractedAssetsDir.mkdirs()
|
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
|
// Check for extracted_battlebgs in assets (now directly under battle_sprites)
|
||||||
val extractedStatsDir = File(context.filesDir, "battle_sprites/extracted_digimon_stats")
|
val battlebgsInAssets = assetManager.list("battle_sprites/extracted_battlebgs")
|
||||||
if (!extractedStatsDir.exists()) {
|
println("extracted_battlebgs in assets contains: ${battlebgsInAssets?.size ?: 0} files")
|
||||||
extractedStatsDir.mkdirs()
|
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
|
// Try to list all possible subdirectories in battle_sprites
|
||||||
copyAssetDirectory("battle_sprites/extracted_assets", extractedAssetsDir)
|
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
|
// Create the base directory for battle_sprites
|
||||||
copyAssetDirectory("battle_sprites/extracted_digimon_stats", extractedStatsDir)
|
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}")
|
// Copy all subdirectories from battle_sprites assets to internal storage
|
||||||
println("Stats files copied successfully to: ${extractedStatsDir.absolutePath}")
|
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) {
|
} catch (e: Exception) {
|
||||||
println("Error copying sprite files: ${e.message}")
|
println("Error copying sprite files: ${e.message}")
|
||||||
@ -41,6 +105,9 @@ class SpriteFileManager(private val context: Context) {
|
|||||||
val assetManager = context.assets
|
val assetManager = context.assets
|
||||||
val files = assetManager.list(assetPath) ?: return
|
val files = assetManager.list(assetPath) ?: return
|
||||||
|
|
||||||
|
println("Copying asset directory: $assetPath (${files.size} items)")
|
||||||
|
println("Files found: ${files.joinToString(", ")}")
|
||||||
|
|
||||||
for (file in files) {
|
for (file in files) {
|
||||||
val assetFilePath = if (assetPath.isEmpty()) file else "$assetPath/$file"
|
val assetFilePath = if (assetPath.isEmpty()) file else "$assetPath/$file"
|
||||||
val targetFile = File(targetDir, file)
|
val targetFile = File(targetDir, file)
|
||||||
@ -50,21 +117,50 @@ class SpriteFileManager(private val context: Context) {
|
|||||||
targetFile.parentFile!!.mkdirs()
|
targetFile.parentFile!!.mkdirs()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's a directory
|
// Check if it's a directory by trying to list its contents
|
||||||
val subFiles = assetManager.list(assetFilePath)
|
try {
|
||||||
if (subFiles != null && subFiles.isNotEmpty()) {
|
val subFiles = assetManager.list(assetFilePath)
|
||||||
// It's a directory, create it and copy contents
|
if (subFiles != null && subFiles.isNotEmpty()) {
|
||||||
if (!targetFile.exists()) {
|
// It's a directory, create it and copy contents
|
||||||
targetFile.mkdirs()
|
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)
|
} catch (e: Exception) {
|
||||||
} else {
|
// If we can't list contents, it's probably a file
|
||||||
// It's a file, copy it
|
println("Treating $assetFilePath as file (could not list contents)")
|
||||||
copyAssetFile(assetFilePath, targetFile)
|
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) {
|
} catch (e: Exception) {
|
||||||
println("Error copying asset directory $assetPath: ${e.message}")
|
println("Error copying asset directory $assetPath: ${e.message}")
|
||||||
|
e.printStackTrace()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,34 +180,34 @@ class SpriteFileManager(private val context: Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun checkSpriteFilesExist(): Boolean {
|
fun checkSpriteFilesExist(): Boolean {
|
||||||
val extractedAssetsDir = File(context.filesDir, "battle_sprites/extracted_assets")
|
val battleSpritesDir = File(context.filesDir, "battle_sprites")
|
||||||
val extractedStatsDir = File(context.filesDir, "battle_sprites/extracted_digimon_stats")
|
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 assetsExist = extractedAssetsDir.exists() && extractedAssetsDir.listFiles()?.isNotEmpty() == true
|
||||||
val statsExist = extractedStatsDir.exists() && extractedStatsDir.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() {
|
fun clearSpriteFiles() {
|
||||||
try {
|
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")
|
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")
|
println("Cleared battle_sprites directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,34 +6,33 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.graphics.asImageBitmap
|
import androidx.compose.ui.graphics.asImageBitmap
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import com.github.nacabaro.vbhelper.battle.BattleSpriteManager
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SpriteImage(
|
fun SpriteImage(
|
||||||
spriteName: String,
|
characterId: String,
|
||||||
atlasName: String,
|
frameNumber: Int,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
contentScale: ContentScale = ContentScale.Fit
|
contentScale: ContentScale = ContentScale.Fit
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val spriteManager = remember { BattleSpriteManager(context) }
|
val spriteManager = remember { IndividualSpriteManager(context) }
|
||||||
|
|
||||||
var bitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }
|
var bitmap by remember { mutableStateOf<android.graphics.Bitmap?>(null) }
|
||||||
|
|
||||||
LaunchedEffect(spriteName, atlasName) {
|
LaunchedEffect(characterId, frameNumber) {
|
||||||
println("Loading sprite: $spriteName from atlas: $atlasName")
|
println("Loading sprite frame: $frameNumber for character: $characterId")
|
||||||
bitmap = spriteManager.loadSprite(spriteName, atlasName)
|
bitmap = spriteManager.loadSpriteFrame(characterId, frameNumber)
|
||||||
if (bitmap == null) {
|
if (bitmap == null) {
|
||||||
println("Failed to load sprite: $spriteName from atlas: $atlasName")
|
println("Failed to load sprite frame: $frameNumber for character: $characterId")
|
||||||
} else {
|
} else {
|
||||||
println("Successfully loaded sprite: $spriteName from atlas: $atlasName")
|
println("Successfully loaded sprite frame: $frameNumber for character: $characterId")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap?.let { bmp ->
|
bitmap?.let { bmp ->
|
||||||
Image(
|
Image(
|
||||||
bitmap = bmp.asImageBitmap(),
|
bitmap = bmp.asImageBitmap(),
|
||||||
contentDescription = "Sprite: $spriteName",
|
contentDescription = "Sprite: $characterId frame $frameNumber",
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
contentScale = contentScale
|
contentScale = contentScale
|
||||||
)
|
)
|
||||||
|
|||||||
@ -45,7 +45,6 @@ import com.github.nacabaro.vbhelper.battle.APIBattleCharacter
|
|||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.github.nacabaro.vbhelper.components.TopBanner
|
import com.github.nacabaro.vbhelper.components.TopBanner
|
||||||
import com.github.nacabaro.vbhelper.battle.RetrofitHelper
|
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.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
|
||||||
@ -286,7 +285,8 @@ fun PlayerBattleView(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(80.dp)
|
.size(80.dp)
|
||||||
.scale(-1f, 1f), // Flip player Digimon horizontally
|
.scale(-1f, 1f), // Flip player Digimon horizontally
|
||||||
contentScale = ContentScale.Fit
|
contentScale = ContentScale.Fit,
|
||||||
|
reloadMappings = false
|
||||||
)
|
)
|
||||||
|
|
||||||
// Attack sprite visibility and positioning based on attack phase
|
// Attack sprite visibility and positioning based on attack phase
|
||||||
@ -500,7 +500,8 @@ fun OpponentBattleView(
|
|||||||
characterId = activeCharacter?.charaId ?: "dim011_mon01",
|
characterId = activeCharacter?.charaId ?: "dim011_mon01",
|
||||||
animationType = animationType,
|
animationType = animationType,
|
||||||
modifier = Modifier.size(80.dp),
|
modifier = Modifier.size(80.dp),
|
||||||
contentScale = ContentScale.Fit
|
contentScale = ContentScale.Fit,
|
||||||
|
reloadMappings = false
|
||||||
)
|
)
|
||||||
|
|
||||||
// Attack sprite visibility and positioning based on attack phase
|
// Attack sprite visibility and positioning based on attack phase
|
||||||
@ -642,12 +643,13 @@ fun BattlesScreen() {
|
|||||||
|
|
||||||
// Initialize sprite files on first load
|
// Initialize sprite files on first load
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
|
println("BATTLESCREEN: LaunchedEffect triggered - checking sprite files...")
|
||||||
val spriteFileManager = SpriteFileManager(context)
|
val spriteFileManager = SpriteFileManager(context)
|
||||||
if (!spriteFileManager.checkSpriteFilesExist()) {
|
if (!spriteFileManager.checkSpriteFilesExist()) {
|
||||||
println("Copying sprite files to internal storage...")
|
println("BATTLESCREEN: Copying sprite files to internal storage...")
|
||||||
spriteFileManager.copySpriteFilesToInternalStorage()
|
spriteFileManager.copySpriteFilesToInternalStorage()
|
||||||
} else {
|
} 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,
|
characterId = testCharacterId,
|
||||||
animationType = currentTestAnimation,
|
animationType = currentTestAnimation,
|
||||||
modifier = Modifier.size(120.dp),
|
modifier = Modifier.size(120.dp),
|
||||||
contentScale = ContentScale.Fit
|
contentScale = ContentScale.Fit,
|
||||||
|
reloadMappings = false
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user