mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-22 10:54:19 -04:00
UNIT MOVEMENT ANIMATION
LET'S FUKKEN GO
This commit is contained in:
parent
7c1e0c0d25
commit
f021fb692d
@ -11,7 +11,7 @@ import com.unciv.ui.components.tilegroups.layers.TileLayerFeatures
|
|||||||
import com.unciv.ui.components.tilegroups.layers.TileLayerMisc
|
import com.unciv.ui.components.tilegroups.layers.TileLayerMisc
|
||||||
import com.unciv.ui.components.tilegroups.layers.TileLayerOverlay
|
import com.unciv.ui.components.tilegroups.layers.TileLayerOverlay
|
||||||
import com.unciv.ui.components.tilegroups.layers.TileLayerTerrain
|
import com.unciv.ui.components.tilegroups.layers.TileLayerTerrain
|
||||||
import com.unciv.ui.components.tilegroups.layers.TileLayerUnitArt
|
import com.unciv.ui.components.tilegroups.layers.TileLayerUnitSprite
|
||||||
import com.unciv.ui.components.tilegroups.layers.TileLayerUnitFlag
|
import com.unciv.ui.components.tilegroups.layers.TileLayerUnitFlag
|
||||||
import com.unciv.utils.DebugUtils
|
import com.unciv.utils.DebugUtils
|
||||||
import kotlin.math.pow
|
import kotlin.math.pow
|
||||||
@ -49,7 +49,7 @@ open class TileGroup(
|
|||||||
@Suppress("LeakingThis") val layerBorders = TileLayerBorders(this, groupSize)
|
@Suppress("LeakingThis") val layerBorders = TileLayerBorders(this, groupSize)
|
||||||
@Suppress("LeakingThis") val layerMisc = TileLayerMisc(this, groupSize)
|
@Suppress("LeakingThis") val layerMisc = TileLayerMisc(this, groupSize)
|
||||||
@Suppress("LeakingThis") val layerOverlay = TileLayerOverlay(this, groupSize)
|
@Suppress("LeakingThis") val layerOverlay = TileLayerOverlay(this, groupSize)
|
||||||
@Suppress("LeakingThis") val layerUnitArt = TileLayerUnitArt(this, groupSize)
|
@Suppress("LeakingThis") val layerUnitArt = TileLayerUnitSprite(this, groupSize)
|
||||||
@Suppress("LeakingThis") val layerUnitFlag = TileLayerUnitFlag(this, groupSize)
|
@Suppress("LeakingThis") val layerUnitFlag = TileLayerUnitFlag(this, groupSize)
|
||||||
@Suppress("LeakingThis") val layerCityButton = TileLayerCityButton(this, groupSize)
|
@Suppress("LeakingThis") val layerCityButton = TileLayerCityButton(this, groupSize)
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import com.unciv.ui.components.tilegroups.layers.TileLayerFeatures
|
|||||||
import com.unciv.ui.components.tilegroups.layers.TileLayerMisc
|
import com.unciv.ui.components.tilegroups.layers.TileLayerMisc
|
||||||
import com.unciv.ui.components.tilegroups.layers.TileLayerOverlay
|
import com.unciv.ui.components.tilegroups.layers.TileLayerOverlay
|
||||||
import com.unciv.ui.components.tilegroups.layers.TileLayerTerrain
|
import com.unciv.ui.components.tilegroups.layers.TileLayerTerrain
|
||||||
import com.unciv.ui.components.tilegroups.layers.TileLayerUnitArt
|
import com.unciv.ui.components.tilegroups.layers.TileLayerUnitSprite
|
||||||
import com.unciv.ui.components.tilegroups.layers.TileLayerUnitFlag
|
import com.unciv.ui.components.tilegroups.layers.TileLayerUnitFlag
|
||||||
import com.unciv.ui.components.widgets.ZoomableScrollPane
|
import com.unciv.ui.components.widgets.ZoomableScrollPane
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
@ -106,7 +106,7 @@ class TileGroupMap<T: TileGroup>(
|
|||||||
val featureLayers = ArrayList<TileLayerFeatures>()
|
val featureLayers = ArrayList<TileLayerFeatures>()
|
||||||
val borderLayers = ArrayList<TileLayerBorders>()
|
val borderLayers = ArrayList<TileLayerBorders>()
|
||||||
val miscLayers = ArrayList<TileLayerMisc>()
|
val miscLayers = ArrayList<TileLayerMisc>()
|
||||||
val pixelUnitLayers = ArrayList<TileLayerUnitArt>()
|
val pixelUnitLayers = ArrayList<TileLayerUnitSprite>()
|
||||||
val circleFogCrosshairLayers = ArrayList<TileLayerOverlay>()
|
val circleFogCrosshairLayers = ArrayList<TileLayerOverlay>()
|
||||||
val unitLayers = ArrayList<TileLayerUnitFlag>()
|
val unitLayers = ArrayList<TileLayerUnitFlag>()
|
||||||
val cityButtonLayers = ArrayList<TileLayerCityButton>()
|
val cityButtonLayers = ArrayList<TileLayerCityButton>()
|
||||||
|
@ -9,28 +9,30 @@ import com.unciv.models.ruleset.unique.LocalUniqueCache
|
|||||||
import com.unciv.ui.images.ImageGetter
|
import com.unciv.ui.images.ImageGetter
|
||||||
import com.unciv.ui.components.tilegroups.TileGroup
|
import com.unciv.ui.components.tilegroups.TileGroup
|
||||||
|
|
||||||
private class UnitArtSlot : Group() {
|
class UnitSpriteSlot : Group() {
|
||||||
var imageLocation = ""
|
var imageLocation = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
class TileLayerUnitArt(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup, size) {
|
class TileLayerUnitSprite(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup, size) {
|
||||||
|
|
||||||
override fun act(delta: Float) {}
|
override fun act(delta: Float) {}
|
||||||
override fun hit(x: Float, y: Float, touchable: Boolean): Actor? = null
|
override fun hit(x: Float, y: Float, touchable: Boolean): Actor? = null
|
||||||
|
|
||||||
private var civilianSlot: UnitArtSlot = UnitArtSlot()
|
private var civilianSlot: UnitSpriteSlot = UnitSpriteSlot()
|
||||||
private var militarySlot: UnitArtSlot = UnitArtSlot()
|
private var militarySlot: UnitSpriteSlot = UnitSpriteSlot()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
addActor(civilianSlot)
|
addActor(civilianSlot)
|
||||||
addActor(militarySlot)
|
addActor(militarySlot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getSpriteSlot(unit:MapUnit) = if (unit.isCivilian()) civilianSlot else militarySlot
|
||||||
|
|
||||||
private fun showMilitaryUnit(viewingCiv: Civilization) = tileGroup.isForceVisible
|
private fun showMilitaryUnit(viewingCiv: Civilization) = tileGroup.isForceVisible
|
||||||
|| viewingCiv.viewableInvisibleUnitsTiles.contains(tileGroup.tile)
|
|| viewingCiv.viewableInvisibleUnitsTiles.contains(tileGroup.tile)
|
||||||
|| !tileGroup.tile.hasEnemyInvisibleUnit(viewingCiv)
|
|| !tileGroup.tile.hasEnemyInvisibleUnit(viewingCiv)
|
||||||
|
|
||||||
private fun updateSlot(slot: UnitArtSlot, unit: MapUnit?, isShown: Boolean) {
|
private fun updateSlot(slot: UnitSpriteSlot, unit: MapUnit?, isShown: Boolean) {
|
||||||
|
|
||||||
var location = ""
|
var location = ""
|
||||||
var nationName = ""
|
var nationName = ""
|
@ -53,7 +53,7 @@ import com.unciv.ui.components.tilegroups.TileGroup
|
|||||||
import com.unciv.ui.components.tilegroups.TileGroupMap
|
import com.unciv.ui.components.tilegroups.TileGroupMap
|
||||||
import com.unciv.ui.components.tilegroups.TileSetStrings
|
import com.unciv.ui.components.tilegroups.TileSetStrings
|
||||||
import com.unciv.ui.components.tilegroups.WorldTileGroup
|
import com.unciv.ui.components.tilegroups.WorldTileGroup
|
||||||
import com.unciv.ui.components.widgets.UnitGroup
|
import com.unciv.ui.components.widgets.UnitIconGroup
|
||||||
import com.unciv.ui.components.widgets.ZoomableScrollPane
|
import com.unciv.ui.components.widgets.ZoomableScrollPane
|
||||||
import com.unciv.ui.images.ImageGetter
|
import com.unciv.ui.images.ImageGetter
|
||||||
import com.unciv.ui.screens.basescreen.BaseScreen
|
import com.unciv.ui.screens.basescreen.BaseScreen
|
||||||
@ -299,8 +299,10 @@ class WorldMapHolder(
|
|||||||
// Since this runs in a different thread, even if we check movement.canReach()
|
// Since this runs in a different thread, even if we check movement.canReach()
|
||||||
// then it might change until we get to the getTileToMoveTo, so we just try/catch it
|
// then it might change until we get to the getTileToMoveTo, so we just try/catch it
|
||||||
val tileToMoveTo: Tile
|
val tileToMoveTo: Tile
|
||||||
|
val pathToTile: List<Tile>
|
||||||
try {
|
try {
|
||||||
tileToMoveTo = selectedUnit.movement.getTileToMoveToThisTurn(targetTile)
|
tileToMoveTo = selectedUnit.movement.getTileToMoveToThisTurn(targetTile)
|
||||||
|
pathToTile = selectedUnit.movement.getDistanceToTiles().getPathToTile(targetTile)
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
when (ex) {
|
when (ex) {
|
||||||
is UnitMovement.UnreachableDestinationException -> {
|
is UnitMovement.UnreachableDestinationException -> {
|
||||||
@ -308,9 +310,7 @@ class WorldMapHolder(
|
|||||||
// Or telling a ship to run onto a coastal land tile.
|
// Or telling a ship to run onto a coastal land tile.
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
else -> {
|
else -> Log.error("Exception in getTileToMoveToThisTurn", ex)
|
||||||
Log.error("Exception in getTileToMoveToThisTurn", ex)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return@run // can't move here
|
return@run // can't move here
|
||||||
}
|
}
|
||||||
@ -325,6 +325,7 @@ class WorldMapHolder(
|
|||||||
// but until it reaches the headTowards the board has changed and so the headTowards fails.
|
// but until it reaches the headTowards the board has changed and so the headTowards fails.
|
||||||
// I can't think of any way to avoid this,
|
// I can't think of any way to avoid this,
|
||||||
// but it's so rare and edge-case-y that ignoring its failure is actually acceptable, hence the empty catch
|
// but it's so rare and edge-case-y that ignoring its failure is actually acceptable, hence the empty catch
|
||||||
|
val previousTile = selectedUnit.currentTile
|
||||||
selectedUnit.movement.moveToTile(tileToMoveTo)
|
selectedUnit.movement.moveToTile(tileToMoveTo)
|
||||||
if (selectedUnit.isExploring() || selectedUnit.isMoving())
|
if (selectedUnit.isExploring() || selectedUnit.isMoving())
|
||||||
selectedUnit.action = null // remove explore on manual move
|
selectedUnit.action = null // remove explore on manual move
|
||||||
@ -335,6 +336,9 @@ class WorldMapHolder(
|
|||||||
if (selectedUnit.currentMovement > 0) worldScreen.bottomUnitTable.selectUnit(selectedUnit)
|
if (selectedUnit.currentMovement > 0) worldScreen.bottomUnitTable.selectUnit(selectedUnit)
|
||||||
|
|
||||||
worldScreen.shouldUpdate = true
|
worldScreen.shouldUpdate = true
|
||||||
|
|
||||||
|
animateMovement(previousTile, selectedUnit, targetTile, pathToTile)
|
||||||
|
|
||||||
if (selectedUnits.size > 1) { // We have more tiles to move
|
if (selectedUnits.size > 1) { // We have more tiles to move
|
||||||
moveUnitToTargetTile(selectedUnits.subList(1, selectedUnits.size), targetTile)
|
moveUnitToTargetTile(selectedUnits.subList(1, selectedUnits.size), targetTile)
|
||||||
} else removeUnitActionOverlay() //we're done here
|
} else removeUnitActionOverlay() //we're done here
|
||||||
@ -349,6 +353,44 @@ class WorldMapHolder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun animateMovement(
|
||||||
|
previousTile: Tile,
|
||||||
|
selectedUnit: MapUnit,
|
||||||
|
targetTile: Tile,
|
||||||
|
pathToTile: List<Tile>
|
||||||
|
) {
|
||||||
|
val tileGroup = tileGroups[previousTile]!!
|
||||||
|
|
||||||
|
// Steal the current sprites to our new group
|
||||||
|
val unitSpriteAndIcon = Group().apply { setPosition(tileGroup.x, tileGroup.y) }
|
||||||
|
val unitSpriteSlot = tileGroup.layerUnitArt.getSpriteSlot(selectedUnit)
|
||||||
|
for (spriteImage in unitSpriteSlot.children) unitSpriteAndIcon.addActor(spriteImage)
|
||||||
|
tileGroup.parent.addActor(unitSpriteAndIcon)
|
||||||
|
|
||||||
|
// Disable the final tile, so we won't have one image "merging into" the other
|
||||||
|
val targetTileSpriteSlot = tileGroups[targetTile]!!.layerUnitArt.getSpriteSlot(selectedUnit)
|
||||||
|
targetTileSpriteSlot.isVisible = false
|
||||||
|
|
||||||
|
|
||||||
|
unitSpriteAndIcon.addAction(
|
||||||
|
Actions.sequence(
|
||||||
|
*pathToTile.map { tile ->
|
||||||
|
Actions.moveTo(
|
||||||
|
tileGroups[tile]!!.x,
|
||||||
|
tileGroups[tile]!!.y,
|
||||||
|
0.5f / pathToTile.size
|
||||||
|
)
|
||||||
|
}.toTypedArray(),
|
||||||
|
Actions.run {
|
||||||
|
// Re-enable the final tile
|
||||||
|
targetTileSpriteSlot.isVisible = true
|
||||||
|
worldScreen.shouldUpdate = true
|
||||||
|
},
|
||||||
|
Actions.removeActor(),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun swapMoveUnitToTargetTile(selectedUnit: MapUnit, targetTile: Tile) {
|
private fun swapMoveUnitToTargetTile(selectedUnit: MapUnit, targetTile: Tile) {
|
||||||
markUnitMoveTutorialComplete(selectedUnit)
|
markUnitMoveTutorialComplete(selectedUnit)
|
||||||
selectedUnit.movement.swapMoveToTile(targetTile)
|
selectedUnit.movement.swapMoveToTile(targetTile)
|
||||||
@ -505,9 +547,9 @@ class WorldMapHolder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (unit in unitList) {
|
for (unit in unitList) {
|
||||||
val unitGroup = UnitGroup(unit, 48f).surroundWithCircle(68f, resizeActor = false)
|
val unitIconGroup = UnitIconGroup(unit, 48f).surroundWithCircle(68f, resizeActor = false)
|
||||||
unitGroup.circle.color = Color.GRAY.cpy().apply { a = 0.5f }
|
unitIconGroup.circle.color = Color.GRAY.cpy().apply { a = 0.5f }
|
||||||
if (unit.currentMovement == 0f) unitGroup.color.a = 0.66f
|
if (unit.currentMovement == 0f) unitIconGroup.color.a = 0.66f
|
||||||
val clickableCircle = ClickableCircle(68f)
|
val clickableCircle = ClickableCircle(68f)
|
||||||
clickableCircle.touchable = Touchable.enabled
|
clickableCircle.touchable = Touchable.enabled
|
||||||
clickableCircle.onClick {
|
clickableCircle.onClick {
|
||||||
@ -515,8 +557,8 @@ class WorldMapHolder(
|
|||||||
worldScreen.shouldUpdate = true
|
worldScreen.shouldUpdate = true
|
||||||
removeUnitActionOverlay()
|
removeUnitActionOverlay()
|
||||||
}
|
}
|
||||||
unitGroup.addActor(clickableCircle)
|
unitIconGroup.addActor(clickableCircle)
|
||||||
table.add(unitGroup)
|
table.add(unitIconGroup)
|
||||||
}
|
}
|
||||||
|
|
||||||
addOverlayOnTileGroup(tileGroups[tile]!!, table)
|
addOverlayOnTileGroup(tileGroups[tile]!!, table)
|
||||||
@ -546,7 +588,7 @@ class WorldMapHolder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val firstUnit = dto.unitToTurnsToDestination.keys.first()
|
val firstUnit = dto.unitToTurnsToDestination.keys.first()
|
||||||
val unitIcon = if (dto.unitToTurnsToDestination.size == 1) UnitGroup(firstUnit, smallerCircleSizes)
|
val unitIcon = if (dto.unitToTurnsToDestination.size == 1) UnitIconGroup(firstUnit, smallerCircleSizes)
|
||||||
else dto.unitToTurnsToDestination.size.toString().toLabel(fontColor = firstUnit.civ.nation.getInnerColor()).apply { setAlignment(Align.center) }
|
else dto.unitToTurnsToDestination.size.toString().toLabel(fontColor = firstUnit.civ.nation.getInnerColor()).apply { setAlignment(Align.center) }
|
||||||
.surroundWithCircle(smallerCircleSizes).apply { circle.color = firstUnit.civ.nation.getOuterColor() }
|
.surroundWithCircle(smallerCircleSizes).apply { circle.color = firstUnit.civ.nation.getOuterColor() }
|
||||||
unitIcon.y = buttonSize - unitIcon.height
|
unitIcon.y = buttonSize - unitIcon.height
|
||||||
@ -575,7 +617,7 @@ class WorldMapHolder(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val unitIcon = UnitGroup(dto.unit, smallerCircleSizes)
|
val unitIcon = UnitIconGroup(dto.unit, smallerCircleSizes)
|
||||||
unitIcon.y = buttonSize - unitIcon.height
|
unitIcon.y = buttonSize - unitIcon.height
|
||||||
swapWithButton.addActor(unitIcon)
|
swapWithButton.addActor(unitIcon)
|
||||||
|
|
||||||
@ -595,7 +637,7 @@ class WorldMapHolder(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val unitIcon = UnitGroup(dto.unit, smallerCircleSizes)
|
val unitIcon = UnitIconGroup(dto.unit, smallerCircleSizes)
|
||||||
unitIcon.y = buttonSize - unitIcon.height
|
unitIcon.y = buttonSize - unitIcon.height
|
||||||
connectRoadButton.addActor(unitIcon)
|
connectRoadButton.addActor(unitIcon)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user