mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-27 05:46:43 -04:00
Added experimental movment which assumes unknown tiles are impassible - hopefully will resolve #3009
This commit is contained in:
parent
aa944bad87
commit
30e5722c24
@ -2,6 +2,7 @@ package com.unciv.logic.map
|
|||||||
|
|
||||||
import com.badlogic.gdx.math.Vector2
|
import com.badlogic.gdx.math.Vector2
|
||||||
import com.unciv.Constants
|
import com.unciv.Constants
|
||||||
|
import com.unciv.UncivGame
|
||||||
import com.unciv.logic.civilization.CivilizationInfo
|
import com.unciv.logic.civilization.CivilizationInfo
|
||||||
|
|
||||||
class UnitMovementAlgorithms(val unit:MapUnit) {
|
class UnitMovementAlgorithms(val unit:MapUnit) {
|
||||||
@ -57,7 +58,12 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
|
|||||||
|
|
||||||
class ParentTileAndTotalDistance(val parentTile: TileInfo, val totalDistance: Float)
|
class ParentTileAndTotalDistance(val parentTile: TileInfo, val totalDistance: Float)
|
||||||
|
|
||||||
|
val MOVEMENT_TESTING = UncivGame.Current.settings.unitMovementIncludesImpassibles
|
||||||
|
fun isUnknownTileWeShouldAssumeToBePassable(tileInfo: TileInfo) = MOVEMENT_TESTING && !unit.civInfo.exploredTiles.contains(tileInfo.position)
|
||||||
|
|
||||||
fun getDistanceToTilesWithinTurn(origin: Vector2, unitMovement: Float): PathsToTilesWithinTurn {
|
fun getDistanceToTilesWithinTurn(origin: Vector2, unitMovement: Float): PathsToTilesWithinTurn {
|
||||||
|
if(MOVEMENT_TESTING) return getDistanceToTilesWithinTurnIncludingUnknownImpassibles(origin, unitMovement)
|
||||||
|
|
||||||
val distanceToTiles = PathsToTilesWithinTurn()
|
val distanceToTiles = PathsToTilesWithinTurn()
|
||||||
if (unitMovement == 0f) return distanceToTiles
|
if (unitMovement == 0f) return distanceToTiles
|
||||||
|
|
||||||
@ -102,6 +108,53 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
|
|||||||
return distanceToTiles
|
return distanceToTiles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getDistanceToTilesWithinTurnIncludingUnknownImpassibles(origin: Vector2, unitMovement: Float): PathsToTilesWithinTurn {
|
||||||
|
val distanceToTiles = PathsToTilesWithinTurn()
|
||||||
|
if (unitMovement == 0f) return distanceToTiles
|
||||||
|
|
||||||
|
val currentUnitTile = unit.currentTile
|
||||||
|
// This is for performance, because this is called all the time
|
||||||
|
val unitTile = if(origin==currentUnitTile.position) currentUnitTile else currentUnitTile.tileMap[origin]
|
||||||
|
distanceToTiles[unitTile] = ParentTileAndTotalDistance(unitTile, 0f)
|
||||||
|
var tilesToCheck = listOf(unitTile)
|
||||||
|
|
||||||
|
while (tilesToCheck.isNotEmpty()) {
|
||||||
|
val updatedTiles = ArrayList<TileInfo>()
|
||||||
|
for (tileToCheck in tilesToCheck)
|
||||||
|
for (neighbor in tileToCheck.neighbors) {
|
||||||
|
var totalDistanceToTile: Float
|
||||||
|
|
||||||
|
if (unit.civInfo.exploredTiles.contains(neighbor.position)) {
|
||||||
|
if (!canPassThrough(neighbor))
|
||||||
|
totalDistanceToTile = unitMovement // Can't go here.
|
||||||
|
// The reason that we don't just "return" is so that when calculating how to reach an enemy,
|
||||||
|
// You need to assume his tile is reachable, otherwise all movement algs on reaching enemy
|
||||||
|
// cities and units goes kaput.
|
||||||
|
|
||||||
|
else {
|
||||||
|
val distanceBetweenTiles = getMovementCostBetweenAdjacentTiles(tileToCheck, neighbor, unit.civInfo)
|
||||||
|
totalDistanceToTile = distanceToTiles[tileToCheck]!!.totalDistance + distanceBetweenTiles
|
||||||
|
}
|
||||||
|
} else totalDistanceToTile = distanceToTiles[tileToCheck]!!.totalDistance + 1f // If we don't know then we just guess it to be 1.
|
||||||
|
|
||||||
|
if (!distanceToTiles.containsKey(neighbor) || distanceToTiles[neighbor]!!.totalDistance > totalDistanceToTile) { // this is the new best path
|
||||||
|
if (totalDistanceToTile < unitMovement) // We can still keep moving from here!
|
||||||
|
updatedTiles += neighbor
|
||||||
|
else
|
||||||
|
totalDistanceToTile = unitMovement
|
||||||
|
// In Civ V, you can always travel between adjacent tiles, even if you don't technically
|
||||||
|
// have enough movement points - it simple depletes what you have
|
||||||
|
|
||||||
|
distanceToTiles[neighbor] = ParentTileAndTotalDistance(tileToCheck, totalDistanceToTile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tilesToCheck = updatedTiles
|
||||||
|
}
|
||||||
|
|
||||||
|
return distanceToTiles
|
||||||
|
}
|
||||||
|
|
||||||
/** Returns an empty list if there's no way to get there */
|
/** Returns an empty list if there's no way to get there */
|
||||||
fun getShortestPath(destination: TileInfo): List<TileInfo> {
|
fun getShortestPath(destination: TileInfo): List<TileInfo> {
|
||||||
val currentTile = unit.getTile()
|
val currentTile = unit.getTile()
|
||||||
@ -127,7 +180,8 @@ class UnitMovementAlgorithms(val unit:MapUnit) {
|
|||||||
distanceToDestination[tileToCheck] = distanceToTilesThisTurn[reachableTile]!!.totalDistance
|
distanceToDestination[tileToCheck] = distanceToTilesThisTurn[reachableTile]!!.totalDistance
|
||||||
else {
|
else {
|
||||||
if (movementTreeParents.containsKey(reachableTile)) continue // We cannot be faster than anything existing...
|
if (movementTreeParents.containsKey(reachableTile)) continue // We cannot be faster than anything existing...
|
||||||
if (!canMoveTo(reachableTile)) continue // This is a tile that we can't actually enter - either an intermediary tile containing our unit, or an enemy unit/city
|
if (!isUnknownTileWeShouldAssumeToBePassable(reachableTile) &&
|
||||||
|
!canMoveTo(reachableTile)) continue // This is a tile that we can't actually enter - either an intermediary tile containing our unit, or an enemy unit/city
|
||||||
movementTreeParents[reachableTile] = tileToCheck
|
movementTreeParents[reachableTile] = tileToCheck
|
||||||
newTilesToCheck.add(reachableTile)
|
newTilesToCheck.add(reachableTile)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ class GameSettings {
|
|||||||
var showTileYields: Boolean = false
|
var showTileYields: Boolean = false
|
||||||
var checkForDueUnits: Boolean = true
|
var checkForDueUnits: Boolean = true
|
||||||
var singleTapMove: Boolean = false
|
var singleTapMove: Boolean = false
|
||||||
|
var unitMovementIncludesImpassibles: Boolean = false
|
||||||
var language: String = "English"
|
var language: String = "English"
|
||||||
var resolution: String = "900x600" // Auto-detecting resolution was a BAD IDEA since it needs to be based on DPI AND resolution.
|
var resolution: String = "900x600" // Auto-detecting resolution was a BAD IDEA since it needs to be based on DPI AND resolution.
|
||||||
var tutorialsShown = HashSet<String>()
|
var tutorialsShown = HashSet<String>()
|
||||||
|
@ -112,7 +112,9 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
|||||||
|
|
||||||
if (previousSelectedUnits.isNotEmpty() && previousSelectedUnits.any { it.getTile() != tileInfo }
|
if (previousSelectedUnits.isNotEmpty() && previousSelectedUnits.any { it.getTile() != tileInfo }
|
||||||
&& worldScreen.isPlayersTurn
|
&& worldScreen.isPlayersTurn
|
||||||
&& previousSelectedUnits.any { it.movement.canMoveTo(tileInfo) }) {
|
&& previousSelectedUnits.any { it.movement.canMoveTo(tileInfo) ||
|
||||||
|
it.movement.isUnknownTileWeShouldAssumeToBePassable(tileInfo)
|
||||||
|
}) {
|
||||||
// this can take a long time, because of the unit-to-tile calculation needed, so we put it in a different thread
|
// this can take a long time, because of the unit-to-tile calculation needed, so we put it in a different thread
|
||||||
addTileOverlaysWithUnitMovement(previousSelectedUnits, tileInfo)
|
addTileOverlaysWithUnitMovement(previousSelectedUnits, tileInfo)
|
||||||
} else addTileOverlays(tileInfo) // no unit movement but display the units in the tile etc.
|
} else addTileOverlays(tileInfo) // no unit movement but display the units in the tile etc.
|
||||||
@ -376,7 +378,7 @@ class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap
|
|||||||
// The tile is within move range
|
// The tile is within move range
|
||||||
tileToColor.showCircle(Color.BLUE, 0.3f)
|
tileToColor.showCircle(Color.BLUE, 0.3f)
|
||||||
}
|
}
|
||||||
if (unit.movement.canMoveTo(tile))
|
if (unit.movement.canMoveTo(tile) || unit.movement.isUnknownTileWeShouldAssumeToBePassable(tile))
|
||||||
tileToColor.showCircle(Color.WHITE,
|
tileToColor.showCircle(Color.WHITE,
|
||||||
if (UncivGame.Current.settings.singleTapMove || isAirUnit) 0.7f else 0.3f)
|
if (UncivGame.Current.settings.singleTapMove || isAirUnit) 0.7f else 0.3f)
|
||||||
}
|
}
|
||||||
|
@ -108,6 +108,8 @@ class OptionsPopup(val previousScreen:CameraStageBaseScreen) : Popup(previousScr
|
|||||||
|
|
||||||
addYesNoRow ("Check for idle units", settings.checkForDueUnits, true) { settings.checkForDueUnits = it }
|
addYesNoRow ("Check for idle units", settings.checkForDueUnits, true) { settings.checkForDueUnits = it }
|
||||||
addYesNoRow ("Move units with a single tap", settings.singleTapMove) { settings.singleTapMove = it }
|
addYesNoRow ("Move units with a single tap", settings.singleTapMove) { settings.singleTapMove = it }
|
||||||
|
addYesNoRow ("Movement assumes unknown tiles to be passable", settings.unitMovementIncludesImpassibles)
|
||||||
|
{ settings.unitMovementIncludesImpassibles = it }
|
||||||
addYesNoRow ("Auto-assign city production", settings.autoAssignCityProduction, true) {
|
addYesNoRow ("Auto-assign city production", settings.autoAssignCityProduction, true) {
|
||||||
settings.autoAssignCityProduction = it
|
settings.autoAssignCityProduction = it
|
||||||
if (it && previousScreen is WorldScreen &&
|
if (it && previousScreen is WorldScreen &&
|
||||||
|
Loading…
x
Reference in New Issue
Block a user