Fixed battle animation crash (#12585)

This commit is contained in:
Yair Morgenstern
2024-12-06 12:18:09 +02:00
committed by GitHub
parent d745b10a1b
commit 67ce623f05
3 changed files with 24 additions and 15 deletions

View File

@ -29,7 +29,7 @@ import com.unciv.ui.images.ImageGetter
import com.unciv.ui.screens.basescreen.BaseScreen import com.unciv.ui.screens.basescreen.BaseScreen
import com.unciv.ui.screens.worldscreen.UndoHandler.Companion.clearUndoCheckpoints import com.unciv.ui.screens.worldscreen.UndoHandler.Companion.clearUndoCheckpoints
import com.unciv.ui.screens.worldscreen.WorldScreen import com.unciv.ui.screens.worldscreen.WorldScreen
import com.unciv.ui.screens.worldscreen.bottombar.BattleTableHelpers.battleAnimation import com.unciv.ui.screens.worldscreen.bottombar.BattleTableHelpers.battleAnimationDeferred
import com.unciv.ui.screens.worldscreen.bottombar.BattleTableHelpers.getHealthBar import com.unciv.ui.screens.worldscreen.bottombar.BattleTableHelpers.getHealthBar
import com.unciv.utils.DebugUtils import com.unciv.utils.DebugUtils
import kotlin.math.max import kotlin.math.max
@ -305,7 +305,7 @@ class BattleTable(val worldScreen: WorldScreen) : Table() {
SoundPlayer.play(attacker.getAttackSound()) SoundPlayer.play(attacker.getAttackSound())
val (damageToDefender, damageToAttacker) = Battle.attackOrNuke(attacker, attackableTile) val (damageToDefender, damageToAttacker) = Battle.attackOrNuke(attacker, attackableTile)
worldScreen.battleAnimation(attacker, damageToAttacker, defender, damageToDefender) worldScreen.battleAnimationDeferred(attacker, damageToAttacker, defender, damageToDefender)
if (!attacker.canAttack()) hide() if (!attacker.canAttack()) hide()
} }

View File

@ -4,7 +4,6 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.math.Interpolation import com.badlogic.gdx.math.Interpolation
import com.badlogic.gdx.math.Vector2 import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.scenes.scene2d.Actor import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.actions.Actions import com.badlogic.gdx.scenes.scene2d.actions.Actions
import com.badlogic.gdx.scenes.scene2d.actions.FloatAction import com.badlogic.gdx.scenes.scene2d.actions.FloatAction
import com.badlogic.gdx.scenes.scene2d.actions.RelativeTemporalAction import com.badlogic.gdx.scenes.scene2d.actions.RelativeTemporalAction
@ -23,6 +22,7 @@ import com.unciv.ui.components.tilegroups.TileSetStrings
import com.unciv.ui.components.widgets.ShadowedLabel import com.unciv.ui.components.widgets.ShadowedLabel
import com.unciv.ui.images.ImageGetter import com.unciv.ui.images.ImageGetter
import com.unciv.ui.screens.worldscreen.WorldScreen import com.unciv.ui.screens.worldscreen.WorldScreen
import com.unciv.utils.Concurrency
object BattleTableHelpers { object BattleTableHelpers {
@ -144,8 +144,16 @@ object BattleTableHelpers {
} }
} }
fun WorldScreen.battleAnimationDeferred(
attacker: ICombatant, damageToAttacker: Int,
defender: ICombatant, damageToDefender: Int
){
// This ensures that we schedule the animation to happen AFTER the worldscreen.update(),
// where the spriteGroup of the attacker is created on the tile it moves to
Concurrency.runOnGLThread { battleAnimation(attacker, damageToAttacker, defender, damageToDefender) }
}
fun WorldScreen.battleAnimation( private fun WorldScreen.battleAnimation(
attacker: ICombatant, damageToAttacker: Int, attacker: ICombatant, damageToAttacker: Int,
defender: ICombatant, damageToDefender: Int defender: ICombatant, damageToDefender: Int
) { ) {
@ -156,11 +164,12 @@ object BattleTableHelpers {
val icon = tileGroup.layerMisc.improvementIcon val icon = tileGroup.layerMisc.improvementIcon
if (icon != null) yield (icon) if (icon != null) yield (icon)
} else if (!combatant.isAirUnit()) { } else if (!combatant.isAirUnit()) {
val slot = if (combatant.isCivilian()) 0 else 1 val slot = tileGroup.layerUnitArt.getSpriteSlot((combatant as MapUnitCombatant).unit)
yieldAll((tileGroup.layerUnitArt.getChild(slot) as Group).children) if (slot != null) yieldAll(slot.spriteGroup.children)
} }
} }
val actorsToFlashRed = val actorsToFlashRed =
sequence { sequence {
if (damageToDefender != 0) yieldAll(getMapActorsForCombatant(defender)) if (damageToDefender != 0) yieldAll(getMapActorsForCombatant(defender))

View File

@ -44,7 +44,7 @@ import com.unciv.ui.components.widgets.ZoomableScrollPane
import com.unciv.ui.screens.basescreen.UncivStage import com.unciv.ui.screens.basescreen.UncivStage
import com.unciv.ui.screens.worldscreen.UndoHandler.Companion.recordUndoCheckpoint import com.unciv.ui.screens.worldscreen.UndoHandler.Companion.recordUndoCheckpoint
import com.unciv.ui.screens.worldscreen.WorldScreen import com.unciv.ui.screens.worldscreen.WorldScreen
import com.unciv.ui.screens.worldscreen.bottombar.BattleTableHelpers.battleAnimation import com.unciv.ui.screens.worldscreen.bottombar.BattleTableHelpers.battleAnimationDeferred
import com.unciv.utils.Concurrency import com.unciv.utils.Concurrency
import com.unciv.utils.Log import com.unciv.utils.Log
import com.unciv.utils.launchOnGLThread import com.unciv.utils.launchOnGLThread
@ -236,7 +236,7 @@ class WorldMapHolder(
SoundPlayer.play(attacker.getAttackSound()) SoundPlayer.play(attacker.getAttackSound())
val (damageToDefender, damageToAttacker) = Battle.attackOrNuke(attacker, attackableTile) val (damageToDefender, damageToAttacker) = Battle.attackOrNuke(attacker, attackableTile)
if (attackableTile.combatant != null) if (attackableTile.combatant != null)
worldScreen.battleAnimation(attacker, damageToAttacker, attackableTile.combatant, damageToDefender) worldScreen.battleAnimationDeferred(attacker, damageToAttacker, attackableTile.combatant, damageToDefender)
localShouldUpdate = true localShouldUpdate = true
} else if (unit.movement.canReach(tile)) { } else if (unit.movement.canReach(tile)) {
/** ****** Right-click Move ****** */ /** ****** Right-click Move ****** */