TileMapHolder refactor & Map Editor update (#1584)

* TileMapHolder renamed to MapHolder
* EditorMapHolder and WorldMapHolder inherits from ZoomableScrollPane
* MapEditor Brush Size (from 1 to 5)
* MapEditor painting mode (dragging the pointer on screen paints continuously)
This commit is contained in:
r3versi 2020-01-02 19:02:38 +01:00 committed by Yair Morgenstern
parent 908c6ad54a
commit a1b0c1dcd4
20 changed files with 349 additions and 170 deletions

View File

@ -945,6 +945,7 @@ Clear improvements = Elimina miglioramenti
Clear resource = Elimina risorsa
Requires = Richiede
Menu = Menu
Brush Size = Dimensione pennello
# Civilopedia Tutorials names

View File

@ -945,6 +945,7 @@ Clear improvements =
Clear resource =
Requires =
Menu =
Brush Size =
# Civilopedia Tutorials names

View File

@ -1,10 +1,8 @@
package com.unciv.logic
import com.badlogic.gdx.math.Vector2
import java.util.*
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.sqrt
import com.badlogic.gdx.math.Vector3
import kotlin.math.*
class HexMath {
@ -16,6 +14,18 @@ class HexMath {
return getVectorForAngle((2 * Math.PI * (hour / 12f)).toFloat())
}
fun getAdjacentVectors(origin: Vector2): ArrayList<Vector2> {
val vectors = ArrayList<Vector2>()
vectors += Vector2(1f, 0f)
vectors += Vector2(1f, 1f)
vectors += Vector2(0f, 1f)
vectors += Vector2(-1f, 0f)
vectors += Vector2(-1f, -1f)
vectors += Vector2(0f, -1f)
for (vector in vectors) vector.add(origin)
return vectors
}
// HexCoordinates are a (x,y) vector, where x is the vector getting us to the top-left hex (e.g. 10 o'clock)
// and y is the vector getting us to the top-right hex (e.g. 2 o'clock)
@ -30,16 +40,45 @@ class HexMath {
return xVector.scl(hexCoord.x).add(yVector.scl(hexCoord.y))
}
fun getAdjacentVectors(origin: Vector2): ArrayList<Vector2> {
val vectors = ArrayList<Vector2>()
vectors += Vector2(1f, 0f)
vectors += Vector2(1f, 1f)
vectors += Vector2(0f, 1f)
vectors += Vector2(-1f, 0f)
vectors += Vector2(-1f, -1f)
vectors += Vector2(0f, -1f)
for (vector in vectors) vector.add(origin)
return vectors
fun world2HexCoords(worldCoord: Vector2): Vector2 {
// D: diagonal, A: antidiagonal versors
val D = getVectorByClockHour(10).scl(sqrt(3.0).toFloat())
val A = getVectorByClockHour(2).scl(sqrt(3.0).toFloat())
val den = D.x * A.y - D.y * A.x
val x = (worldCoord.x * A.y - worldCoord.y * A.x) / den
val y = (worldCoord.y * D.x - worldCoord.x * D.y) / den
return Vector2(x, y)
}
fun hex2CubicCoords(hexCoord: Vector2): Vector3 {
return Vector3(hexCoord.y - hexCoord.x, hexCoord.x, -hexCoord.y)
}
fun cubic2HexCoords(cubicCoord: Vector3): Vector2 {
return Vector2(cubicCoord.y, -cubicCoord.z)
}
fun roundCubicCoords(cubicCoords: Vector3): Vector3 {
var rx = round(cubicCoords.x)
var ry = round(cubicCoords.y)
var rz = round(cubicCoords.z)
val deltaX = abs(rx - cubicCoords.x)
val deltaY = abs(ry - cubicCoords.y)
val deltaZ = abs(rz - cubicCoords.z)
if (deltaX > deltaY && deltaX > deltaZ)
rx = -ry-rz
else if (deltaY > deltaZ)
ry = -rx-rz
else
rz = -rx-ry
return Vector3(rx, ry, rz)
}
fun roundHexCoords(hexCoord: Vector2): Vector2 {
return cubic2HexCoords(roundCubicCoords(hex2CubicCoords(hexCoord)))
}
fun getVectorsAtDistance(origin: Vector2, distance: Int): List<Vector2> {

View File

@ -29,9 +29,9 @@ data class LocationAction(var locations: ArrayList<Vector2> = ArrayList()) : Not
override fun execute(worldScreen: WorldScreen) {
if (locations.isNotEmpty()) {
var index = locations.indexOf(worldScreen.tileMapHolder.selectedTile?.position)
var index = locations.indexOf(worldScreen.mapHolder.selectedTile?.position)
index = ++index % locations.size // cycle through tiles
worldScreen.tileMapHolder.setCenterPosition(locations[index], selectUnit = false)
worldScreen.mapHolder.setCenterPosition(locations[index], selectUnit = false)
}
}
@ -49,7 +49,7 @@ class TechAction(val techName: String = "") : NotificationAction {
data class CityAction(val city: Vector2 = Vector2.Zero): NotificationAction {
override fun execute(worldScreen: WorldScreen) {
worldScreen.tileMapHolder.tileMap[city].getCity()?.let {
worldScreen.mapHolder.tileMap[city].getCity()?.let {
worldScreen.game.setScreen(CityScreen(it))
}
}

View File

@ -307,7 +307,7 @@ class EmpireOverviewScreen(val viewingPlayer:CivilizationInfo) : CameraStageBase
val button = TextButton(unit.name.tr(), skin)
button.onClick {
UncivGame.Current.setWorldScreen()
UncivGame.Current.worldScreen.tileMapHolder.setCenterPosition(unit.currentTile.position)
UncivGame.Current.worldScreen.mapHolder.setCenterPosition(unit.currentTile.position)
}
table.add(button).left()
val mapUnitAction = unit.mapUnitAction

View File

@ -17,7 +17,7 @@ import com.unciv.models.stats.Stats
import com.unciv.models.translations.tr
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.TileGroupMap
import com.unciv.ui.map.TileGroupMap
import java.util.*
import kotlin.math.ceil
import kotlin.math.floor

View File

@ -87,7 +87,7 @@ class CityScreenCityPickerTable(val cityScreen: CityScreen) : Table(){
exitCityButton.onClick {
val game = cityScreen.game
game.setWorldScreen()
game.worldScreen.tileMapHolder.setCenterPosition(city.location)
game.worldScreen.mapHolder.setCenterPosition(city.location)
game.worldScreen.bottomUnitTable.selectedUnit=null
}

View File

@ -1,19 +1,20 @@
package com.unciv.ui.worldscreen
package com.unciv.ui.map
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.scenes.scene2d.Group
import com.unciv.logic.HexMath
import com.unciv.ui.tilegroups.TileGroup
class TileGroupMap<T: TileGroup>(val tileGroups:Collection<T>, padding:Float): Group(){
init{
class TileGroupMap<T: TileGroup>(val tileGroups: Collection<T>, val padding: Float): Group(){
var topX = -Float.MAX_VALUE
var topY = -Float.MAX_VALUE
var bottomX = Float.MAX_VALUE
var bottomY = Float.MAX_VALUE
val groupSize = 50
init{
for(tileGroup in tileGroups){
val positionalVector = HexMath().hex2WorldCoords(tileGroup.tileInfo.position)
val groupSize = 50
tileGroup.setPosition(positionalVector.x * 0.8f * groupSize.toFloat(),
positionalVector.y * 0.8f * groupSize.toFloat())
@ -56,6 +57,16 @@ class TileGroupMap<T: TileGroup>(val tileGroups:Collection<T>, padding:Float): G
// 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)
}
/**
* Returns the positional coordinates of the TileGroupMap center.
*/
fun getPositionalVector(stageCoords: Vector2): Vector2 {
val trueGroupSize = 0.8f * groupSize.toFloat()
return Vector2(bottomX - padding, bottomY - padding)
.add(stageCoords)
.sub(groupSize.toFloat() / 2f, groupSize.toFloat() / 2f)
.scl(1f / trueGroupSize)
}
}

View File

@ -0,0 +1,73 @@
package com.unciv.ui.mapeditor
import com.badlogic.gdx.math.Vector2
import com.unciv.logic.map.TileMap
import com.unciv.logic.map.TileInfo
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.onClick
import com.unciv.ui.map.TileGroupMap
import com.unciv.ui.utils.*
import com.unciv.logic.HexMath
class EditorMapHolder(internal val mapEditorScreen: MapEditorScreen, internal val tileMap: TileMap): ZoomableScrollPane() {
val tileGroups = HashMap<TileInfo, TileGroup>()
lateinit var tileGroupMap: TileGroupMap<TileGroup>
internal fun addTiles() {
val tileSetStrings = TileSetStrings()
for (tileGroup in tileMap.values.map { TileGroup(it, tileSetStrings) })
tileGroups[tileGroup.tileInfo] = tileGroup
tileGroupMap = TileGroupMap(tileGroups.values, mapEditorScreen.stage.width)
actor = tileGroupMap
for (tileGroup in tileGroups.values) {
tileGroup.showEntireMap = true
tileGroup.update()
tileGroup.onClick {
val distance = mapEditorScreen.tileEditorOptions.brushSize - 1
for (tileInfo in mapEditorScreen.tileMap.getTilesInDistance(tileGroup.tileInfo.position, distance)) {
mapEditorScreen.tileEditorOptions.updateTileWhenClicked(tileInfo)
tileInfo.setTransients()
tileGroups[tileInfo]!!.update()
}
}
}
setSize(mapEditorScreen.stage.width * 2, mapEditorScreen.stage.height * 2)
setOrigin(width / 2,height / 2)
center(mapEditorScreen.stage)
layout()
scrollPercentX = .5f
scrollPercentY = .5f
updateVisualScroll()
}
fun updateTileGroups() {
for (tileGroup in tileGroups.values)
tileGroup.update()
}
fun setTransients() {
for (tileInfo in tileGroups.keys)
tileInfo.setTransients()
}
fun getClosestTileTo(stageCoords: Vector2): TileInfo? {
val positionalCoords = tileGroupMap.getPositionalVector(stageCoords)
val hexPosition = HexMath().world2HexCoords(positionalCoords)
val rounded = HexMath().roundHexCoords(hexPosition)
if (tileMap.contains(rounded))
return tileMap.get(rounded)
else
return null
}
}

View File

@ -24,7 +24,7 @@ class MapEditorMenuPopup(mapEditorScreen: MapEditorScreen): PopupTable(mapEditor
val clearCurrentMapButton = TextButton("Clear current map".tr(),skin)
clearCurrentMapButton.onClick {
for(tileGroup in mapEditorScreen.mapHolder.tileGroups)
for(tileGroup in mapEditorScreen.mapHolder.tileGroups.values)
{
val tile = tileGroup.tileInfo
tile.baseTerrain=Constants.ocean

View File

@ -1,51 +1,59 @@
package com.unciv.ui.mapeditor
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.InputListener
import com.badlogic.gdx.scenes.scene2d.actions.Actions
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.UncivGame
import com.unciv.logic.MapSaver
import com.unciv.logic.map.TileMap
import com.unciv.models.translations.tr
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.setFontSize
import com.unciv.ui.worldscreen.TileGroupMap
class MapEditorScreen(): CameraStageBaseScreen(){
var tileMap = TileMap()
class MapEditorScreen(): CameraStageBaseScreen() {
val ruleset = UncivGame.Current.ruleset
var mapName = "My first map"
lateinit var mapHolder: TileGroupMap<TileGroup>
private val showHideEditorOptionsButton = TextButton(">",skin)
val ruleSet = UncivGame.Current.ruleset
private val tileEditorOptions = TileEditorOptionsTable(this)
constructor(mapNameToLoad:String?):this(){
var tileMap = TileMap()
lateinit var mapHolder: EditorMapHolder
val tileEditorOptions = TileEditorOptionsTable(this)
private val showHideEditorOptionsButton = TextButton(">", skin)
constructor(mapNameToLoad: String?): this() {
var mapToLoad = mapNameToLoad
if (mapToLoad == null) {
val existingSaves = MapSaver().getMaps()
if(existingSaves.isNotEmpty())
mapToLoad = existingSaves.first()
}
if(mapToLoad!=null){
mapName=mapToLoad
tileMap= MapSaver().loadMap(mapName)
if(mapToLoad != null){
mapName = mapToLoad
tileMap = MapSaver().loadMap(mapName)
}
initialize()
}
constructor(map: TileMap):this(){
constructor(map: TileMap): this() {
tileMap = map
initialize()
}
fun initialize() {
tileMap.setTransients(ruleSet)
val mapHolder = getMapHolder(tileMap)
tileMap.setTransients(ruleset)
mapHolder = EditorMapHolder(this, tileMap)
mapHolder.addTiles()
stage.addActor(mapHolder)
stage.addActor(tileEditorOptions)
tileEditorOptions.setPosition(stage.width - tileEditorOptions.width, 0f)
@ -76,35 +84,60 @@ class MapEditorScreen(): CameraStageBaseScreen(){
optionsMenuButton.pack()
optionsMenuButton.x = 30f
optionsMenuButton.y = 30f
stage.addActor(optionsMenuButton)
mapHolder.addCaptureListener(object: InputListener() {
var isDragging = false
var isPainting = false
var touchDownTime = System.currentTimeMillis()
override fun touchDown(event: InputEvent?, x: Float, y: Float, pointer: Int, button: Int): Boolean {
touchDownTime = System.currentTimeMillis()
return true
}
private fun getMapHolder(tileMap: TileMap): ScrollPane {
val tileSetStrings = TileSetStrings()
val tileGroups = tileMap.values.map { TileGroup(it, tileSetStrings) }
for (tileGroup in tileGroups) {
tileGroup.showEntireMap = true
tileGroup.update()
tileGroup.onClick {
val tileInfo = tileGroup.tileInfo
override fun touchDragged(event: InputEvent?, x: Float, y: Float, pointer: Int) {
if (!isDragging) {
isDragging = true
val deltaTime = System.currentTimeMillis() - touchDownTime
if (deltaTime > 400) {
isPainting = true
stage.cancelTouchFocusExcept(this, mapHolder)
}
}
if (isPainting) {
mapHolder.updateTileGroups()
mapHolder.setTransients()
val stageCoords = mapHolder.actor.stageToLocalCoordinates(Vector2(event!!.stageX, event.stageY))
val centerTileInfo = mapHolder.getClosestTileTo(stageCoords)
if (centerTileInfo != null) {
val distance = tileEditorOptions.brushSize - 1
for (tileInfo in tileMap.getTilesInDistance(centerTileInfo.position, distance)) {
tileEditorOptions.updateTileWhenClicked(tileInfo)
tileGroup.tileInfo.setTransients()
tileGroup.update()
tileInfo.setTransients()
mapHolder.tileGroups[tileInfo]!!.update()
mapHolder.tileGroups[tileInfo]!!.showCircle(Color.WHITE)
}
}
}
}
mapHolder = TileGroupMap(tileGroups, 300f)
val scrollPane = ScrollPane(mapHolder)
scrollPane.setSize(stage.width, stage.height)
scrollPane.layout()
scrollPane.scrollPercentX=0.5f
scrollPane.scrollPercentY=0.5f
scrollPane.updateVisualScroll()
return scrollPane
override fun touchUp(event: InputEvent?, x: Float, y: Float, pointer: Int, button: Int) {
// Reset tile overlays
if (isPainting) {
mapHolder.updateTileGroups()
mapHolder.setTransients()
}
isDragging = false
isPainting = false
}
})
}
}

View File

@ -4,8 +4,10 @@ import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
import com.badlogic.gdx.scenes.scene2d.ui.Slider
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.map.RoadStatus
@ -19,6 +21,7 @@ import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.*
class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(CameraStageBaseScreen.skin){
val tileSetLocation = "TileSets/"+ UncivGame.Current.settings.tileSet +"/"
@ -37,13 +40,14 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
val editorPickTable = Table()
var brushSize = 1
private var currentHex: Actor = Group()
val ruleSet = mapEditorScreen.ruleSet
val ruleset = mapEditorScreen.ruleset
init{
height=mapEditorScreen.stage.height
width=mapEditorScreen.stage.width/3
height = mapEditorScreen.stage.height
width = mapEditorScreen.stage.width/3
setTerrainsAndResources()
@ -52,10 +56,28 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
.onClick { setTerrainsAndResources() }
tabPickerTable.add(terrainsAndResourcesTabButton)
val civLocationsButton = TextButton("Improvements".tr(),skin)
val civLocationsButton = TextButton("Improvements".tr(), skin)
.onClick { setImprovements() }
tabPickerTable.add(civLocationsButton)
tabPickerTable.pack()
val sliderTab = Table()
val slider = Slider(1f,5f,1f, false, skin)
val sliderLabel = "{Brush Size} $brushSize".toLabel()
slider.addListener(object : ChangeListener() {
override fun changed(event: ChangeEvent?, actor: Actor?) {
brushSize = slider.getValue().toInt()
sliderLabel.setText("{Brush Size} $brushSize".tr())
}
})
sliderTab.defaults().pad(5f)
sliderTab.add(sliderLabel)
sliderTab.add(slider)
add(sliderTab).row()
add(ScrollPane(tabPickerTable).apply { this.width= mapEditorScreen.stage.width/3}).row()
add(editorPickTable).row()
@ -74,7 +96,7 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
}
}).row()
for(improvement in ruleSet.tileImprovements.values){
for(improvement in ruleset.tileImprovements.values){
if(improvement.name.startsWith("Remove")) continue
val improvementImage = getHex(Color.WHITE,ImageGetter.getImprovementIcon(improvement.name,40f))
improvementImage.onClick {
@ -88,7 +110,7 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
editorPickTable.add(ScrollPane(improvementsTable)).height(mapEditorScreen.stage.height*0.7f)
val nationsTable = Table()
for(nation in ruleSet.nations.values){
for(nation in ruleset.nations.values){
val nationImage = getHex(Color.WHITE,ImageGetter.getNationIndicator(nation,40f))
nationImage.onClick {
clearSelection()
@ -151,16 +173,16 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
}
})
for (resource in ruleSet.tileResources.values) {
for (resource in ruleset.tileResources.values) {
val resourceHex = getHex(Color.WHITE, ImageGetter.getResourceImage(resource.name, 40f))
resourceHex.onClick {
clearSelection()
selectedResource = resource
val tileInfo = TileInfo()
tileInfo.ruleset = mapEditorScreen.ruleSet
tileInfo.ruleset = mapEditorScreen.ruleset
val terrain = resource.terrainsCanBeFoundOn.first()
val terrainObject = ruleSet.terrains[terrain]!!
val terrainObject = ruleset.terrains[terrain]!!
if (terrainObject.type == TerrainType.TerrainFeature) {
tileInfo.baseTerrain = when {
terrainObject.occursOn == null -> terrainObject.occursOn!!.first()
@ -179,9 +201,9 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
}
private fun addTerrainOptions(terrainFeaturesTable: Table, baseTerrainTable: Table) {
for (terrain in ruleSet.terrains.values) {
for (terrain in ruleset.terrains.values) {
val tileInfo = TileInfo()
tileInfo.ruleset = mapEditorScreen.ruleSet
tileInfo.ruleset = mapEditorScreen.ruleset
if (terrain.type == TerrainType.TerrainFeature) {
tileInfo.baseTerrain = when {
terrain.occursOn != null -> terrain.occursOn.first()
@ -318,7 +340,7 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
else tileInfo.improvement = improvement.name
if(improvement.name.startsWith("StartingLocation"))
for(tileGroup in mapEditorScreen.mapHolder.tileGroups){
for(tileGroup in mapEditorScreen.mapHolder.tileGroups.values){
val tile = tileGroup.tileInfo
if(tile.improvement==improvement.name && tile!=tileInfo)
tile.improvement=null
@ -332,7 +354,6 @@ class TileEditorOptionsTable(val mapEditorScreen: MapEditorScreen): Table(Camera
}
normalizeTile(tileInfo)
tileInfo.setTransients()
}
fun normalizeTile(tileInfo: TileInfo){

View File

@ -0,0 +1,48 @@
package com.unciv.ui.utils
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.sqrt
open class ZoomableScrollPane: ScrollPane(null) {
init{
// Remove the existing inputListener
// which defines that mouse scroll = vertical movement
val zoomListener = listeners.last { it is InputListener && it !in captureListeners }
removeListener(zoomListener)
addZoomListeners()
}
fun zoom(zoomScale: Float) {
if (zoomScale < 0.5f) return
setScale(zoomScale)
}
private fun addZoomListeners() {
addListener(object: InputListener() {
override fun scrolled(event: InputEvent?, x: Float, y: Float, amount: Int): Boolean {
if(amount > 0) zoom(scaleX * 0.8f)
else zoom(scaleX / 0.8f)
return false
}
})
addListener(object : ActorGestureListener() {
var lastScale = 1f
var lastInitialDistance = 0f
override fun zoom(event: InputEvent?, initialDistance: Float, distance: Float) {
if (lastInitialDistance != initialDistance) {
lastInitialDistance = initialDistance
lastScale = scaleX
}
val scale: Float = sqrt((distance / initialDistance).toDouble()).toFloat() * lastScale
zoom(scale)
}
})
}
}

View File

@ -16,14 +16,14 @@ import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.onClick
import com.unciv.ui.utils.surroundWithCircle
class Minimap(val tileMapHolder: TileMapHolder) : ScrollPane(null){
class Minimap(val mapHolder: WorldMapHolder) : ScrollPane(null){
val allTiles = Group()
val tileImages = HashMap<TileInfo, Image>()
fun setScrollToTileMapHolder(){
scrollPercentX = tileMapHolder.scrollPercentX
scrollPercentY = tileMapHolder.scrollPercentY
fun setScrollTomapHolder(){
scrollPercentX = mapHolder.scrollPercentX
scrollPercentY = mapHolder.scrollPercentY
}
init{
@ -32,7 +32,7 @@ class Minimap(val tileMapHolder: TileMapHolder) : ScrollPane(null){
var bottomX = 0f
var bottomY = 0f
for (tileInfo in tileMapHolder.tileMap.values) {
for (tileInfo in mapHolder.tileMap.values) {
val hex = ImageGetter.getImage("OtherIcons/Hexagon")
val positionalVector = HexMath().hex2WorldCoords(tileInfo.position)
@ -41,8 +41,8 @@ class Minimap(val tileMapHolder: TileMapHolder) : ScrollPane(null){
hex.setPosition(positionalVector.x * 0.5f * groupSize,
positionalVector.y * 0.5f * groupSize)
hex.onClick {
tileMapHolder.setCenterPosition(tileInfo.position)
setScrollToTileMapHolder()
mapHolder.setCenterPosition(tileInfo.position)
setScrollTomapHolder()
}
allTiles.addActor(hex)
tileImages[tileInfo] = hex
@ -61,19 +61,19 @@ class Minimap(val tileMapHolder: TileMapHolder) : ScrollPane(null){
// so we zero out the starting position of the whole board so they will be displayed as well
allTiles.setSize(10 + topX - bottomX, 10 + topY - bottomY)
widget = allTiles
actor = allTiles
layout()
updateVisualScroll()
tileMapHolder.addListener(object : InputListener(){
mapHolder.addListener(object : InputListener(){
override fun handle(e: Event?): Boolean {
setScrollToTileMapHolder()
setScrollTomapHolder()
return true
}
})
}
fun update(cloneCivilization: CivilizationInfo) {
for(tileInfo in tileMapHolder.tileMap.values) {
for(tileInfo in mapHolder.tileMap.values) {
val hex = tileImages[tileInfo]!!
if (!(UncivGame.Current.viewEntireMapForDebug || cloneCivilization.exploredTiles.contains(tileInfo.position)))
hex.color = Color.DARK_GRAY
@ -86,9 +86,9 @@ class Minimap(val tileMapHolder: TileMapHolder) : ScrollPane(null){
}
}
class MinimapHolder(tileMapHolder: TileMapHolder): Table(){
val minimap = Minimap(tileMapHolder)
val worldScreen = tileMapHolder.worldScreen
class MinimapHolder(mapHolder: WorldMapHolder): Table(){
val minimap = Minimap(mapHolder)
val worldScreen = mapHolder.worldScreen
init{
add(getToggleIcons()).align(Align.bottom)

View File

@ -6,9 +6,7 @@ import com.badlogic.gdx.math.Interpolation
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.scenes.scene2d.*
import com.badlogic.gdx.scenes.scene2d.actions.FloatAction
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener
import com.unciv.Constants
import com.unciv.UncivGame
import com.unciv.logic.automation.UnitAutomation
@ -21,26 +19,18 @@ import com.unciv.models.UncivSound
import com.unciv.models.ruleset.unit.UnitType
import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.tilegroups.WorldTileGroup
import com.unciv.ui.map.TileGroupMap
import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.unit.UnitContextMenu
import kotlin.concurrent.thread
import kotlin.math.sqrt
class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap: TileMap) : ScrollPane(null) {
class WorldMapHolder(internal val worldScreen: WorldScreen, internal val tileMap: TileMap): ZoomableScrollPane() {
internal var selectedTile: TileInfo? = null
val tileGroups = HashMap<TileInfo, WorldTileGroup>()
var unitActionOverlay :Actor?=null
init{
// Remove the existing inputListener
// which defines that mouse scroll = vertical movement
val zoomListener = listeners.last { it is InputListener && it !in captureListeners }
removeListener (zoomListener)
}
// Used to transfer data on the "move here" button that should be created, from the side thread to the main thread
class MoveHereButtonDto(val unit: MapUnit, val tileInfo: TileInfo, val turnsToGetThere: Int)
@ -65,46 +55,9 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
setOrigin(width/2,height/2)
center(worldScreen.stage)
addGestureListener()
addListener(object :InputListener(){
override fun scrolled(event: InputEvent?, x: Float, y: Float, amount: Int): Boolean {
if(amount>0) zoom(scaleX*0.8f)
else zoom(scaleX/0.8f)
return false
}
})
layout() // Fit the scroll pane to the contents - otherwise, setScroll won't work!
}
fun zoom(zoomScale:Float){
if (zoomScale < 0.5f) return
setScale(zoomScale)
for (tilegroup in tileGroups.values.filter { it.cityButton != null })
tilegroup.cityButton!!.setScale(1 / zoomScale)
}
private fun addGestureListener() {
addListener(object : ActorGestureListener() {
var lastScale = 1f
var lastInitialDistance = 0f
override fun zoom(event: InputEvent?, initialDistance: Float, distance: Float) {
// deselect any unit, as zooming occasionally forwards clicks on to the map
worldScreen.bottomUnitTable.selectedUnit = null
worldScreen.shouldUpdate = true
if (lastInitialDistance != initialDistance) {
lastInitialDistance = initialDistance
lastScale = scaleX
}
val scale: Float = sqrt((distance / initialDistance).toDouble()).toFloat() * lastScale
zoom(scale)
}
})
}
private fun onTileClicked(tileInfo: TileInfo) {
unitActionOverlay?.remove()
selectedTile = tileInfo
@ -357,5 +310,4 @@ class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap:
worldScreen.shouldUpdate=true
}
}

View File

@ -48,8 +48,8 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
var isPlayersTurn = viewingCiv == gameInfo.currentPlayerCiv // todo this should be updated when passing turns
var waitingForAutosave = false
val tileMapHolder: TileMapHolder = TileMapHolder(this, gameInfo.tileMap)
val minimapWrapper = MinimapHolder(tileMapHolder)
val mapHolder = WorldMapHolder(this, gameInfo.tileMap)
val minimapWrapper = MinimapHolder(mapHolder)
private val topBar = WorldScreenTopBar(this)
val bottomUnitTable = UnitTable(this)
@ -76,7 +76,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
minimapWrapper.x = stage.width - minimapWrapper.width
tileMapHolder.addTiles()
mapHolder.addTiles()
techButtonHolder.touchable=Touchable.enabled
techButtonHolder.onClick(UncivSound.Paper) {
@ -92,7 +92,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
techPolicyAndVictoryHolder.add(policyScreenButton).pad(10f)
}
stage.addActor(tileMapHolder)
stage.addActor(mapHolder)
stage.addActor(minimapWrapper)
stage.addActor(topBar)
stage.addActor(nextTurnButton)
@ -119,7 +119,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
viewingCiv.getCivUnits().isNotEmpty() -> viewingCiv.getCivUnits().first().getTile().position
else -> Vector2.Zero
}
tileMapHolder.setCenterPosition(tileToCenterOn,true)
mapHolder.setCenterPosition(tileToCenterOn,true)
if(gameInfo.gameParameters.isOnlineMultiplayer && !gameInfo.isUpToDate)
@ -173,7 +173,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
displayTutorialsOnUpdate()
bottomUnitTable.update()
bottomTileInfoTable.updateTileTable(tileMapHolder.selectedTile!!)
bottomTileInfoTable.updateTileTable(mapHolder.selectedTile!!)
bottomTileInfoTable.x = stage.width - bottomTileInfoTable.width
bottomTileInfoTable.y = if (UncivGame.Current.settings.showMinimap) minimapWrapper.height else 0f
battleTable.update()
@ -198,7 +198,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
// if we use the clone, then when we update viewable tiles
// it doesn't update the explored tiles of the civ... need to think about that harder
// it causes a bug when we move a unit to an unexplored tile (for instance a cavalry unit which can move far)
tileMapHolder.updateTiles(viewingCiv)
mapHolder.updateTiles(viewingCiv)
topBar.update(viewingCiv)
@ -344,7 +344,7 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
if (viewingCiv.shouldGoToDueUnit()) {
val nextDueUnit = viewingCiv.getNextDueUnit()
if(nextDueUnit!=null) {
tileMapHolder.setCenterPosition(nextDueUnit.currentTile.position, false, false)
mapHolder.setCenterPosition(nextDueUnit.currentTile.position, false, false)
bottomUnitTable.selectedUnit = nextDueUnit
shouldUpdate=true
}
@ -413,11 +413,11 @@ class WorldScreen(val viewingCiv:CivilizationInfo) : CameraStageBaseScreen() {
fun createNewWorldScreen(){
val newWorldScreen = WorldScreen(gameInfoClone.getPlayerToViewAs())
newWorldScreen.tileMapHolder.scrollX = tileMapHolder.scrollX
newWorldScreen.tileMapHolder.scrollY = tileMapHolder.scrollY
newWorldScreen.tileMapHolder.scaleX = tileMapHolder.scaleX
newWorldScreen.tileMapHolder.scaleY = tileMapHolder.scaleY
newWorldScreen.tileMapHolder.updateVisualScroll()
newWorldScreen.mapHolder.scrollX = mapHolder.scrollX
newWorldScreen.mapHolder.scrollY = mapHolder.scrollY
newWorldScreen.mapHolder.scaleX = mapHolder.scaleX
newWorldScreen.mapHolder.scaleY = mapHolder.scaleY
newWorldScreen.mapHolder.updateVisualScroll()
game.worldScreen = newWorldScreen
game.setWorldScreen()
}

View File

@ -61,8 +61,8 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
private fun tryGetDefender(): ICombatant? {
val attackerCiv = worldScreen.viewingCiv
if (worldScreen.tileMapHolder.selectedTile == null) return null // no selected tile
val selectedTile = worldScreen.tileMapHolder.selectedTile!!
if (worldScreen.mapHolder.selectedTile == null) return null // no selected tile
val selectedTile = worldScreen.mapHolder.selectedTile!!
val defender: ICombatant? = Battle(worldScreen.gameInfo).getMapCombatantOfTile(selectedTile)
@ -197,7 +197,7 @@ class BattleTable(val worldScreen: WorldScreen): Table() {
attackButton.onClick {
try {
battle.moveAndAttack(attacker, attackableEnemy)
worldScreen.tileMapHolder.unitActionOverlay?.remove() // the overlay was one of attacking
worldScreen.mapHolder.unitActionOverlay?.remove() // the overlay was one of attacking
worldScreen.shouldUpdate = true
}
catch (ex:Exception){

View File

@ -7,11 +7,11 @@ import com.badlogic.gdx.utils.Align
import com.unciv.logic.map.MapUnit
import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.onClick
import com.unciv.ui.worldscreen.TileMapHolder
import com.unciv.ui.worldscreen.WorldMapHolder
class IdleUnitButton (
internal val unitTable: UnitTable,
val tileMapHolder: TileMapHolder,
val tileMapHolder: WorldMapHolder,
val previous:Boolean
) : Table() {

View File

@ -13,10 +13,10 @@ import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.utils.Sounds
import com.unciv.ui.utils.onClick
import com.unciv.ui.worldscreen.TileMapHolder
import com.unciv.ui.worldscreen.WorldMapHolder
import kotlin.concurrent.thread
class UnitContextMenu(val tileMapHolder: TileMapHolder, val selectedUnit: MapUnit, val targetTile: TileInfo) : VerticalGroup() {
class UnitContextMenu(val tileMapHolder: WorldMapHolder, val selectedUnit: MapUnit, val targetTile: TileInfo) : VerticalGroup() {
init {

View File

@ -16,8 +16,8 @@ import com.unciv.ui.utils.*
import com.unciv.ui.worldscreen.WorldScreen
class UnitTable(val worldScreen: WorldScreen) : Table(){
private val prevIdleUnitButton = IdleUnitButton(this,worldScreen.tileMapHolder,true)
private val nextIdleUnitButton = IdleUnitButton(this,worldScreen.tileMapHolder,false)
private val prevIdleUnitButton = IdleUnitButton(this,worldScreen.mapHolder,true)
private val nextIdleUnitButton = IdleUnitButton(this,worldScreen.mapHolder,false)
private val unitIconHolder=Table()
private val unitNameLabel = "".toLabel()
private val promotionsTable = Table()
@ -64,7 +64,7 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
touchable = Touchable.enabled
onClick {
selectedUnit?.currentTile?.position?.let {
worldScreen.tileMapHolder.setCenterPosition(it, false, false)
worldScreen.mapHolder.setCenterPosition(it, false, false)
}
}
}).expand()