mirror of
https://github.com/yairm210/Unciv.git
synced 2025-07-28 21:58:54 +07:00
World Wrap Part 1 (#3604)
* Adding fake infinite scroll functionality * improve scroll jump * really smooth jump now * World wrap has functionality now This is not compileable on its own! Needs branches WorldWrap-v1 and WorldWrap-v2 to be mergeable * Mirror tiles rendering * changed to run v2-alternative code * Use generic type * default worldWrap to false * forward continousScrollingX as parameter * added unit movement button for mirror tiles * Add clickable tile layer * Smooth wrap jump * code a bit better to read * Removed unnecessary overrides and catches * mirrorTiles are stored in one HashMap now instead of two seperate ones
This commit is contained in:
@ -4,24 +4,44 @@ import com.badlogic.gdx.graphics.g2d.Batch
|
||||
import com.badlogic.gdx.math.Vector2
|
||||
import com.badlogic.gdx.scenes.scene2d.Group
|
||||
import com.unciv.logic.HexMath
|
||||
import com.unciv.logic.map.TileInfo
|
||||
import com.unciv.ui.tilegroups.TileGroup
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
class TileGroupMap<T: TileGroup>(val tileGroups: Collection<T>, val padding: Float): Group(){
|
||||
class TileGroupMap<T: TileGroup>(val tileGroups: Collection<T>, val padding: Float, worldWrap: Boolean = false): Group(){
|
||||
var topX = -Float.MAX_VALUE
|
||||
var topY = -Float.MAX_VALUE
|
||||
var bottomX = Float.MAX_VALUE
|
||||
var bottomY = Float.MAX_VALUE
|
||||
val groupSize = 50
|
||||
private val mirrorTileGroups = HashMap<TileInfo, Pair<T, T>>()
|
||||
|
||||
init{
|
||||
for(tileGroup in tileGroups){
|
||||
if (worldWrap) {
|
||||
for(tileGroup in tileGroups) {
|
||||
mirrorTileGroups[tileGroup.tileInfo] = Pair(tileGroup.clone() as T, tileGroup.clone() as T)
|
||||
}
|
||||
}
|
||||
|
||||
for(tileGroup in tileGroups) {
|
||||
val positionalVector = HexMath.hex2WorldCoords(tileGroup.tileInfo.position)
|
||||
|
||||
tileGroup.setPosition(positionalVector.x * 0.8f * groupSize.toFloat(),
|
||||
positionalVector.y * 0.8f * groupSize.toFloat())
|
||||
|
||||
topX = max(topX, tileGroup.x + groupSize)
|
||||
topX =
|
||||
if (worldWrap)
|
||||
// Well it's not pretty but it works
|
||||
// This is so topX is the same no matter what worldWrap is
|
||||
// wrapped worlds are missing one tile width on the right side
|
||||
// which would result in a smaller topX
|
||||
// The resulting topX was always missing 1.2 * groupSize in every possible
|
||||
// combination of map size and shape
|
||||
max(topX, tileGroup.x + groupSize * 2.2f)
|
||||
else
|
||||
max(topX, tileGroup.x + groupSize)
|
||||
|
||||
topY = max(topY, tileGroup.y + groupSize)
|
||||
bottomX = min(bottomX, tileGroup.x)
|
||||
bottomY = min(bottomY, tileGroup.y)
|
||||
@ -31,6 +51,20 @@ class TileGroupMap<T: TileGroup>(val tileGroups: Collection<T>, val padding: Flo
|
||||
group.moveBy(-bottomX + padding, -bottomY + padding * 0.5f)
|
||||
}
|
||||
|
||||
if (worldWrap) {
|
||||
for (mirrorTiles in mirrorTileGroups.values){
|
||||
val positionalVector = HexMath.hex2WorldCoords(mirrorTiles.first.tileInfo.position)
|
||||
|
||||
mirrorTiles.first.setPosition(positionalVector.x * 0.8f * groupSize.toFloat(),
|
||||
positionalVector.y * 0.8f * groupSize.toFloat())
|
||||
mirrorTiles.first.moveBy(-bottomX + padding - bottomX * 2, -bottomY + padding * 0.5f)
|
||||
|
||||
mirrorTiles.second.setPosition(positionalVector.x * 0.8f * groupSize.toFloat(),
|
||||
positionalVector.y * 0.8f * groupSize.toFloat())
|
||||
mirrorTiles.second.moveBy(-bottomX + padding + bottomX * 2, -bottomY + padding * 0.5f)
|
||||
}
|
||||
}
|
||||
|
||||
val baseLayers = ArrayList<Group>()
|
||||
val featureLayers = ArrayList<Group>()
|
||||
val miscLayers = ArrayList<Group>()
|
||||
@ -49,12 +83,30 @@ class TileGroupMap<T: TileGroup>(val tileGroups: Collection<T>, val padding: Flo
|
||||
unitImageLayers.add(group.unitImageLayerGroup.apply { setPosition(group.x,group.y) })
|
||||
cityButtonLayers.add(group.cityButtonLayerGroup.apply { setPosition(group.x,group.y) })
|
||||
circleCrosshairFogLayers.add(group.circleCrosshairFogLayerGroup.apply { setPosition(group.x,group.y) })
|
||||
|
||||
if (worldWrap){
|
||||
for (mirrorTile in mirrorTileGroups[group.tileInfo]!!.toList()){
|
||||
baseLayers.add(mirrorTile.baseLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) })
|
||||
featureLayers.add(mirrorTile.terrainFeatureLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) })
|
||||
miscLayers.add(mirrorTile.miscLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) })
|
||||
unitLayers.add(mirrorTile.unitLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) })
|
||||
unitImageLayers.add(mirrorTile.unitImageLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) })
|
||||
cityButtonLayers.add(mirrorTile.cityButtonLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) })
|
||||
circleCrosshairFogLayers.add(mirrorTile.circleCrosshairFogLayerGroup.apply { setPosition(mirrorTile.x,mirrorTile.y) })
|
||||
}
|
||||
}
|
||||
}
|
||||
for(group in baseLayers) addActor(group)
|
||||
for(group in featureLayers) addActor(group)
|
||||
for(group in miscLayers) addActor(group)
|
||||
for(group in circleCrosshairFogLayers) addActor(group)
|
||||
for(group in tileGroups) addActor(group) // The above layers are for the visual layers, this is for the clickability of the tile
|
||||
if (worldWrap){
|
||||
for (mirrorTiles in mirrorTileGroups.values){
|
||||
addActor(mirrorTiles.first)
|
||||
addActor(mirrorTiles.second)
|
||||
}
|
||||
}
|
||||
for(group in unitLayers) addActor(group) // Aaand units above everything else.
|
||||
for(group in unitImageLayers) addActor(group) // This is so the individual textures for the units are rendered together
|
||||
for(group in cityButtonLayers) addActor(group) // city buttons + clickability
|
||||
@ -62,7 +114,7 @@ class TileGroupMap<T: TileGroup>(val tileGroups: Collection<T>, val padding: Flo
|
||||
|
||||
// there are tiles "below the zero",
|
||||
// so we zero out the starting position of the whole board so they will be displayed as well
|
||||
setSize(topX - bottomX + padding * 2, topY - bottomY + padding * 2 * 0.5f)
|
||||
setSize(topX - bottomX + padding * 2 - groupSize, topY - bottomY + padding * 2 * 0.5f)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,6 +128,7 @@ class TileGroupMap<T: TileGroup>(val tileGroups: Collection<T>, val padding: Flo
|
||||
.scl(1f / trueGroupSize)
|
||||
}
|
||||
|
||||
fun getMirrorTiles(): HashMap<TileInfo, Pair<T, T>> = mirrorTileGroups
|
||||
|
||||
// For debugging purposes
|
||||
override fun draw(batch: Batch?, parentAlpha: Float) { super.draw(batch, parentAlpha) }
|
||||
|
@ -133,6 +133,8 @@ open class TileGroup(var tileInfo: TileInfo, var tileSetStrings:TileSetStrings)
|
||||
isTransform = false // performance helper - nothing here is rotated or scaled
|
||||
}
|
||||
|
||||
open fun clone(): TileGroup = TileGroup(tileInfo, tileSetStrings)
|
||||
|
||||
|
||||
//region init functions
|
||||
private fun addCircleImage() {
|
||||
|
@ -63,4 +63,5 @@ class WorldTileGroup(internal val worldScreen: WorldScreen, tileInfo: TileInfo,
|
||||
return worldScreen.bottomUnitTable.citySelected(city)
|
||||
}
|
||||
|
||||
}
|
||||
override fun clone(): WorldTileGroup = WorldTileGroup(worldScreen, tileInfo , tileSetStrings)
|
||||
}
|
||||
|
@ -1,13 +1,17 @@
|
||||
package com.unciv.ui.utils
|
||||
|
||||
import com.badlogic.gdx.scenes.scene2d.Event
|
||||
import com.badlogic.gdx.scenes.scene2d.InputEvent
|
||||
import com.badlogic.gdx.scenes.scene2d.InputListener
|
||||
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
|
||||
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.sqrt
|
||||
|
||||
|
||||
open class ZoomableScrollPane: ScrollPane(null) {
|
||||
var continousScrollingX = false
|
||||
|
||||
init{
|
||||
// Remove the existing inputListener
|
||||
// which defines that mouse scroll = vertical movement
|
||||
@ -45,4 +49,30 @@ open class ZoomableScrollPane: ScrollPane(null) {
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFlickScrollListener(): ActorGestureListener {
|
||||
//This is mostly just Java code from the ScrollPane class reimplemented as Kotlin code
|
||||
//Had to change a few things to bypass private access modifiers
|
||||
return object : ActorGestureListener() {
|
||||
override fun pan(event: InputEvent, x: Float, y: Float, deltaX: Float, deltaY: Float) {
|
||||
setScrollbarsVisible(true)
|
||||
scrollX -= deltaX
|
||||
scrollY += deltaY
|
||||
|
||||
//this is the new feature to fake an infinite scroll
|
||||
when {
|
||||
continousScrollingX && scrollPercentX >= 1 && deltaX < 0 -> {
|
||||
scrollPercentX = 0f
|
||||
}
|
||||
continousScrollingX && scrollPercentX <= 0 && deltaX > 0-> {
|
||||
scrollPercentX = 1f
|
||||
}
|
||||
}
|
||||
|
||||
//clamp() call is missing here but it doesn't seem to make any big difference in this case
|
||||
|
||||
if ((isScrollX && deltaX != 0f || isScrollY && deltaY != 0f)) cancelTouchFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import com.unciv.models.AttackableTile
|
||||
import com.unciv.models.UncivSound
|
||||
import com.unciv.models.ruleset.unit.UnitType
|
||||
import com.unciv.ui.map.TileGroupMap
|
||||
import com.unciv.ui.tilegroups.TileGroup
|
||||
import com.unciv.ui.tilegroups.TileSetStrings
|
||||
import com.unciv.ui.tilegroups.WorldTileGroup
|
||||
import com.unciv.ui.utils.*
|
||||
@ -34,9 +35,13 @@ import kotlin.concurrent.thread
|
||||
|
||||
class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap: TileMap): ZoomableScrollPane() {
|
||||
internal var selectedTile: TileInfo? = null
|
||||
val tileGroups = HashMap<TileInfo, WorldTileGroup>()
|
||||
val tileGroups = HashMap<TileInfo, List<WorldTileGroup>>()
|
||||
//allWorldTileGroups exists to easily access all WordTileGroups
|
||||
//since tileGroup is a HashMap of Lists and getting all WordTileGroups
|
||||
//would need a double for loop
|
||||
val allWorldTileGroups = ArrayList<WorldTileGroup>()
|
||||
|
||||
var unitActionOverlay: Actor? = null
|
||||
val unitActionOverlays: ArrayList<Actor> = ArrayList()
|
||||
|
||||
init {
|
||||
if (Gdx.app.type == Application.ApplicationType.Desktop) this.setFlingTime(0f)
|
||||
@ -48,12 +53,26 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
internal fun addTiles() {
|
||||
val tileSetStrings = TileSetStrings()
|
||||
val daTileGroups = tileMap.values.map { WorldTileGroup(worldScreen, it, tileSetStrings) }
|
||||
val tileGroupMap = TileGroupMap(daTileGroups, worldScreen.stage.width, continousScrollingX)
|
||||
val mirrorTileGroups = tileGroupMap.getMirrorTiles()
|
||||
|
||||
for (tileGroup in daTileGroups) tileGroups[tileGroup.tileInfo] = tileGroup
|
||||
for (tileGroup in daTileGroups) {
|
||||
if (continousScrollingX){
|
||||
val mirrorTileGroupLeft = mirrorTileGroups[tileGroup.tileInfo]!!.first
|
||||
val mirrorTileGroupRight = mirrorTileGroups[tileGroup.tileInfo]!!.second
|
||||
|
||||
val allTiles = TileGroupMap(daTileGroups, worldScreen.stage.width)
|
||||
allWorldTileGroups.add(tileGroup)
|
||||
allWorldTileGroups.add(mirrorTileGroupLeft)
|
||||
allWorldTileGroups.add(mirrorTileGroupRight)
|
||||
|
||||
for (tileGroup in tileGroups.values) {
|
||||
tileGroups[tileGroup.tileInfo] = listOf(tileGroup, mirrorTileGroupLeft, mirrorTileGroupRight)
|
||||
} else {
|
||||
tileGroups[tileGroup.tileInfo] = listOf(tileGroup)
|
||||
allWorldTileGroups.add(tileGroup)
|
||||
}
|
||||
}
|
||||
|
||||
for (tileGroup in allWorldTileGroups) {
|
||||
tileGroup.cityButtonLayerGroup.onClick(UncivSound.Silent) {
|
||||
onTileClicked(tileGroup.tileInfo)
|
||||
}
|
||||
@ -90,7 +109,7 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
})
|
||||
}
|
||||
|
||||
actor = allTiles
|
||||
actor = tileGroupMap
|
||||
|
||||
setSize(worldScreen.stage.width * 2, worldScreen.stage.height * 2)
|
||||
setOrigin(width / 2, height / 2)
|
||||
@ -101,7 +120,7 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
}
|
||||
|
||||
private fun onTileClicked(tileInfo: TileInfo) {
|
||||
unitActionOverlay?.remove()
|
||||
removeUnitActionOverlay()
|
||||
selectedTile = tileInfo
|
||||
|
||||
val unitTable = worldScreen.bottomUnitTable
|
||||
@ -176,7 +195,7 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
worldScreen.shouldUpdate = true
|
||||
if (selectedUnits.size > 1) { // We have more tiles to move
|
||||
moveUnitToTargetTile(selectedUnits.subList(1, selectedUnits.size), targetTile)
|
||||
} else unitActionOverlay?.remove() //we're done here
|
||||
} else removeUnitActionOverlay() //we're done here
|
||||
} catch (e: Exception) {
|
||||
}
|
||||
}
|
||||
@ -230,34 +249,36 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
}
|
||||
|
||||
private fun addTileOverlays(tileInfo: TileInfo, moveHereDto: MoveHereButtonDto? = null) {
|
||||
val table = Table().apply { defaults().pad(10f) }
|
||||
if (moveHereDto != null && worldScreen.canChangeState)
|
||||
table.add(getMoveHereButton(moveHereDto))
|
||||
for (group in tileGroups[tileInfo]!!){
|
||||
val table = Table().apply { defaults().pad(10f) }
|
||||
if (moveHereDto != null && worldScreen.canChangeState)
|
||||
table.add(getMoveHereButton(moveHereDto))
|
||||
|
||||
val unitList = ArrayList<MapUnit>()
|
||||
if (tileInfo.isCityCenter()
|
||||
&& (tileInfo.getOwner() == worldScreen.viewingCiv || worldScreen.viewingCiv.isSpectator())) {
|
||||
unitList.addAll(tileInfo.getCity()!!.getCenterTile().getUnits())
|
||||
} else if (tileInfo.airUnits.isNotEmpty()
|
||||
&& (tileInfo.airUnits.first().civInfo == worldScreen.viewingCiv || worldScreen.viewingCiv.isSpectator())) {
|
||||
unitList.addAll(tileInfo.getUnits())
|
||||
}
|
||||
|
||||
for (unit in unitList) {
|
||||
val unitGroup = UnitGroup(unit, 60f).surroundWithCircle(80f)
|
||||
unitGroup.circle.color = Color.GRAY.cpy().apply { a = 0.5f }
|
||||
if (unit.currentMovement == 0f) unitGroup.color.a = 0.5f
|
||||
unitGroup.touchable = Touchable.enabled
|
||||
unitGroup.onClick {
|
||||
worldScreen.bottomUnitTable.selectUnit(unit, Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT))
|
||||
worldScreen.shouldUpdate = true
|
||||
unitActionOverlay?.remove()
|
||||
val unitList = ArrayList<MapUnit>()
|
||||
if (tileInfo.isCityCenter()
|
||||
&& (tileInfo.getOwner() == worldScreen.viewingCiv || worldScreen.viewingCiv.isSpectator())) {
|
||||
unitList.addAll(tileInfo.getCity()!!.getCenterTile().getUnits())
|
||||
} else if (tileInfo.airUnits.isNotEmpty()
|
||||
&& (tileInfo.airUnits.first().civInfo == worldScreen.viewingCiv || worldScreen.viewingCiv.isSpectator())) {
|
||||
unitList.addAll(tileInfo.getUnits())
|
||||
}
|
||||
table.add(unitGroup)
|
||||
}
|
||||
|
||||
addOverlayOnTileGroup(tileInfo, table)
|
||||
table.moveBy(0f, 60f)
|
||||
for (unit in unitList) {
|
||||
val unitGroup = UnitGroup(unit, 60f).surroundWithCircle(80f)
|
||||
unitGroup.circle.color = Color.GRAY.cpy().apply { a = 0.5f }
|
||||
if (unit.currentMovement == 0f) unitGroup.color.a = 0.5f
|
||||
unitGroup.touchable = Touchable.enabled
|
||||
unitGroup.onClick {
|
||||
worldScreen.bottomUnitTable.selectUnit(unit, Gdx.input.isKeyPressed(Input.Keys.SHIFT_LEFT))
|
||||
worldScreen.shouldUpdate = true
|
||||
removeUnitActionOverlay()
|
||||
}
|
||||
table.add(unitGroup)
|
||||
}
|
||||
|
||||
addOverlayOnTileGroup(group, table)
|
||||
table.moveBy(0f, 60f)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMoveHereButton(dto: MoveHereButtonDto): Group {
|
||||
@ -293,9 +314,7 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
}
|
||||
|
||||
|
||||
private fun addOverlayOnTileGroup(tileInfo: TileInfo, actor: Actor) {
|
||||
|
||||
val group = tileGroups[tileInfo]!!
|
||||
private fun addOverlayOnTileGroup(group: TileGroup, actor: Actor) {
|
||||
|
||||
actor.center(group)
|
||||
actor.x += group.x
|
||||
@ -304,7 +323,7 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
actor.toFront()
|
||||
|
||||
actor.y += actor.height
|
||||
unitActionOverlay = actor
|
||||
unitActionOverlays.add(actor)
|
||||
|
||||
}
|
||||
|
||||
@ -319,12 +338,12 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
// Only needs to be done once - this is so the minimap will also be revealed
|
||||
if (viewingCiv.exploredTiles.size != tileMap.values.size)
|
||||
viewingCiv.exploredTiles = tileMap.values.map { it.position }.toHashSet()
|
||||
tileGroups.values.forEach { it.showEntireMap = true } // So we can see all resources, regardless of tech
|
||||
allWorldTileGroups.forEach { it.showEntireMap = true } // So we can see all resources, regardless of tech
|
||||
}
|
||||
|
||||
val playerViewableTilePositions = viewingCiv.viewableTiles.map { it.position }.toHashSet()
|
||||
|
||||
for (tileGroup in tileGroups.values) {
|
||||
for (tileGroup in allWorldTileGroups) {
|
||||
tileGroup.update(viewingCiv)
|
||||
|
||||
if (tileGroup.tileInfo.improvement == Constants.barbarianEncampment
|
||||
@ -349,21 +368,25 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
updateTilegroupsForSelectedUnit(unit, playerViewableTilePositions)
|
||||
}
|
||||
}
|
||||
unitActionOverlay != null -> {
|
||||
unitActionOverlay!!.remove()
|
||||
unitActionOverlay = null
|
||||
unitActionOverlays.isNotEmpty() -> {
|
||||
removeUnitActionOverlay()
|
||||
}
|
||||
}
|
||||
|
||||
tileGroups[selectedTile]?.showCircle(Color.WHITE)
|
||||
for (group in tileGroups[selectedTile]!!) {
|
||||
group.showCircle(Color.WHITE)
|
||||
}
|
||||
|
||||
zoom(scaleX) // zoom to current scale, to set the size of the city buttons after "next turn"
|
||||
}
|
||||
|
||||
private fun updateTilegroupsForSelectedUnit(unit: MapUnit, playerViewableTilePositions: HashSet<Vector2>) {
|
||||
val tileGroup = tileGroups[unit.getTile()]
|
||||
if (tileGroup == null) return // Entirely unclear when this happens, but this seems to happen since version 520 (3.12.9)
|
||||
val tileGroup = tileGroups[unit.getTile()]?: return
|
||||
// Entirely unclear when this happens, but this seems to happen since version 520 (3.12.9)
|
||||
// so maybe has to do with the construction list being asyc?
|
||||
tileGroup.selectUnit(unit)
|
||||
for (group in tileGroup){
|
||||
group.selectUnit(unit)
|
||||
}
|
||||
|
||||
val isAirUnit = unit.type.isAirUnit()
|
||||
val tilesInMoveRange =
|
||||
@ -373,19 +396,20 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
unit.movement.getDistanceToTiles().keys.asSequence()
|
||||
|
||||
for (tile in tilesInMoveRange) {
|
||||
val tileToColor = tileGroups.getValue(tile)
|
||||
if (isAirUnit)
|
||||
if (tile.aerialDistanceTo(unit.getTile()) <= unit.getRange()) {
|
||||
// The tile is within attack range
|
||||
tileToColor.showCircle(Color.RED, 0.3f)
|
||||
} else {
|
||||
// The tile is within move range
|
||||
tileToColor.showCircle(Color.BLUE, 0.3f)
|
||||
}
|
||||
if (unit.movement.canMoveTo(tile) ||
|
||||
unit.movement.isUnknownTileWeShouldAssumeToBePassable(tile) && !unit.type.isAirUnit())
|
||||
tileToColor.showCircle(Color.WHITE,
|
||||
if (UncivGame.Current.settings.singleTapMove || isAirUnit) 0.7f else 0.3f)
|
||||
for (tileToColor in tileGroups[tile]!!){
|
||||
if (isAirUnit)
|
||||
if (tile.aerialDistanceTo(unit.getTile()) <= unit.getRange()) {
|
||||
// The tile is within attack range
|
||||
tileToColor.showCircle(Color.RED, 0.3f)
|
||||
} else {
|
||||
// The tile is within move range
|
||||
tileToColor.showCircle(Color.BLUE, 0.3f)
|
||||
}
|
||||
if (unit.movement.canMoveTo(tile) ||
|
||||
unit.movement.isUnknownTileWeShouldAssumeToBePassable(tile) && !unit.type.isAirUnit())
|
||||
tileToColor.showCircle(Color.WHITE,
|
||||
if (UncivGame.Current.settings.singleTapMove || isAirUnit) 0.7f else 0.3f)
|
||||
}
|
||||
}
|
||||
|
||||
val attackableTiles: List<AttackableTile> = if (unit.type.isCivilian()) listOf()
|
||||
@ -399,19 +423,22 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
}
|
||||
|
||||
for (attackableTile in attackableTiles) {
|
||||
tileGroups[attackableTile.tileToAttack]!!.showCircle(colorFromRGB(237, 41, 57))
|
||||
tileGroups[attackableTile.tileToAttack]!!.showCrosshair(
|
||||
// the targets which cannot be attacked without movements shown as orange-ish
|
||||
if (attackableTile.tileToAttackFrom != unit.currentTile)
|
||||
colorFromRGB(255, 75, 0)
|
||||
else Color.RED
|
||||
)
|
||||
for (tileGroup in tileGroups[attackableTile.tileToAttack]!!){
|
||||
tileGroup.showCircle(colorFromRGB(237, 41, 57))
|
||||
tileGroup.showCrosshair(
|
||||
// the targets which cannot be attacked without movements shown as orange-ish
|
||||
if (attackableTile.tileToAttackFrom != unit.currentTile)
|
||||
colorFromRGB(255, 75, 0)
|
||||
else Color.RED
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Fade out less relevant images if a military unit is selected
|
||||
val fadeout = if (unit.type.isCivilian()) 1f
|
||||
else 0.5f
|
||||
for (tile in tileGroups.values) {
|
||||
for (tile in allWorldTileGroups) {
|
||||
if (tile.icons.populationIcon != null) tile.icons.populationIcon!!.color.a = fadeout
|
||||
if (tile.icons.improvementIcon != null && tile.tileInfo.improvement != Constants.barbarianEncampment
|
||||
&& tile.tileInfo.improvement != Constants.ancientRuins)
|
||||
@ -426,14 +453,16 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
val attackableTiles = UnitAutomation.getBombardTargets(city)
|
||||
.filter { (UncivGame.Current.viewEntireMapForDebug || playerViewableTilePositions.contains(it.position)) }
|
||||
for (attackableTile in attackableTiles) {
|
||||
tileGroups[attackableTile]!!.showCircle(colorFromRGB(237, 41, 57))
|
||||
tileGroups[attackableTile]!!.showCrosshair(Color.RED)
|
||||
for (group in tileGroups[attackableTile]!!) {
|
||||
group.showCircle(colorFromRGB(237, 41, 57))
|
||||
group.showCrosshair(Color.RED)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var blinkAction: Action? = null
|
||||
fun setCenterPosition(vector: Vector2, immediately: Boolean = false, selectUnit: Boolean = true) {
|
||||
val tileGroup = tileGroups.values.firstOrNull { it.tileInfo.position == vector } ?: return
|
||||
val tileGroup = allWorldTileGroups.firstOrNull { it.tileInfo.position == vector } ?: return
|
||||
selectedTile = tileGroup.tileInfo
|
||||
if (selectUnit)
|
||||
worldScreen.bottomUnitTable.tileSelected(selectedTile!!)
|
||||
@ -480,10 +509,10 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
super.zoom(zoomScale)
|
||||
val scale = 1 / scaleX // don't use zoomScale itself, in case it was out of bounds and not applied
|
||||
if (scale >= 1)
|
||||
for (tileGroup in tileGroups.values)
|
||||
for (tileGroup in allWorldTileGroups)
|
||||
tileGroup.cityButtonLayerGroup.isTransform = false // to save on rendering time to improve framerate
|
||||
if (scale < 1 && scale > 0.5f)
|
||||
for (tileGroup in tileGroups.values) {
|
||||
for (tileGroup in allWorldTileGroups) {
|
||||
// ONLY set those groups that have active citybuttons as transformable!
|
||||
// This is massively framerate-improving!
|
||||
if (tileGroup.cityButtonLayerGroup.hasChildren())
|
||||
@ -492,6 +521,12 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
||||
}
|
||||
}
|
||||
|
||||
fun removeUnitActionOverlay(){
|
||||
for (overlay in unitActionOverlays)
|
||||
overlay.remove()
|
||||
unitActionOverlays.clear()
|
||||
}
|
||||
|
||||
// For debugging purposes
|
||||
override fun draw(batch: Batch?, parentAlpha: Float) = super.draw(batch, parentAlpha)
|
||||
|
||||
|
@ -211,7 +211,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
|
||||
else {
|
||||
attackButton.onClick {
|
||||
Battle.moveAndAttack(attacker, attackableTile)
|
||||
worldScreen.mapHolder.unitActionOverlay?.remove() // the overlay was one of attacking
|
||||
worldScreen.mapHolder.removeUnitActionOverlay() // the overlay was one of attacking
|
||||
worldScreen.shouldUpdate = true
|
||||
}
|
||||
}
|
||||
@ -283,7 +283,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
|
||||
else {
|
||||
attackButton.onClick {
|
||||
Battle.nuke(attacker, targetTile)
|
||||
worldScreen.mapHolder.unitActionOverlay?.remove() // the overlay was one of attacking
|
||||
worldScreen.mapHolder.removeUnitActionOverlay() // the overlay was one of attacking
|
||||
worldScreen.shouldUpdate = true
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user