mirror of
https://github.com/yairm210/Unciv.git
synced 2025-09-30 15:30:43 -04:00
Improved city button (#771)
* improved CityButton * keep city button out of the way if a unit on the city tile is selected * fixed city button to be clickable always. however this hides units behind it * added click area for city buttons in an own layer, so the units render in front and the city button click area handles the clicks * city button: simplified code
This commit is contained in:
parent
054b3b000d
commit
73e397c2c2
@ -2,9 +2,10 @@ package com.unciv.ui.tilegroups
|
|||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color
|
import com.badlogic.gdx.graphics.Color
|
||||||
import com.badlogic.gdx.math.Interpolation
|
import com.badlogic.gdx.math.Interpolation
|
||||||
|
import com.badlogic.gdx.scenes.scene2d.Actor
|
||||||
import com.badlogic.gdx.scenes.scene2d.Group
|
import com.badlogic.gdx.scenes.scene2d.Group
|
||||||
import com.badlogic.gdx.scenes.scene2d.Touchable
|
import com.badlogic.gdx.scenes.scene2d.Touchable
|
||||||
import com.badlogic.gdx.scenes.scene2d.actions.FloatAction
|
import com.badlogic.gdx.scenes.scene2d.actions.Actions
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Skin
|
import com.badlogic.gdx.scenes.scene2d.ui.Skin
|
||||||
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
import com.badlogic.gdx.scenes.scene2d.ui.Table
|
||||||
import com.badlogic.gdx.utils.Align
|
import com.badlogic.gdx.utils.Align
|
||||||
@ -24,9 +25,8 @@ class CityButton(val city: CityInfo, internal val tileGroup: WorldTileGroup, ski
|
|||||||
touchable= Touchable.disabled
|
touchable= Touchable.disabled
|
||||||
}
|
}
|
||||||
|
|
||||||
var offset: Float = 0f;
|
var buttonDownClickArea: Actor? = null
|
||||||
var isButtonMoved = false
|
fun isButtonMoved() = buttonDownClickArea != null
|
||||||
var isLabelClicked = false
|
|
||||||
|
|
||||||
fun update(isCityViewable:Boolean) {
|
fun update(isCityViewable:Boolean) {
|
||||||
val cityButtonText = city.population.population.toString() + " | " + city.name
|
val cityButtonText = city.population.population.toString() + " | " + city.name
|
||||||
@ -36,61 +36,37 @@ class CityButton(val city: CityInfo, internal val tileGroup: WorldTileGroup, ski
|
|||||||
label.setFontColor(city.civInfo.getNation().getSecondaryColor())
|
label.setFontColor(city.civInfo.getNation().getSecondaryColor())
|
||||||
|
|
||||||
clear()
|
clear()
|
||||||
|
val unitTable = tileGroup.worldScreen.bottomBar.unitTable
|
||||||
if (UnCivGame.Current.viewEntireMapForDebug || city.civInfo.isCurrentPlayer()) {
|
if (UnCivGame.Current.viewEntireMapForDebug || city.civInfo.isCurrentPlayer()) {
|
||||||
|
|
||||||
// So you can click anywhere on the button to go to the city
|
// So you can click anywhere on the button to go to the city
|
||||||
touchable = Touchable.enabled
|
touchable = Touchable.enabled
|
||||||
|
|
||||||
label.touchable = Touchable.enabled
|
label.touchable = Touchable.enabled
|
||||||
label.onClick {
|
|
||||||
isLabelClicked = true
|
|
||||||
// clicking on the label swings that label a little down to allow selection of units there.
|
|
||||||
// second tap on the label will go to the city screen
|
|
||||||
if (tileGroup.selectCity(city)) {
|
|
||||||
val floatAction = object : FloatAction(0f, 1f, 0.4f) {
|
|
||||||
override fun update(percent: Float) {
|
|
||||||
offset = -height*percent
|
|
||||||
update(isCityViewable)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun end() {
|
|
||||||
isButtonMoved=true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
floatAction.interpolation = Interpolation.swingOut
|
|
||||||
tileGroup.addAction(floatAction)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
UnCivGame.Current.screen = CityScreen(city)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// clicking anywhere else on the button opens the city screen immediately
|
// clicking anywhere else on the button opens the city screen immediately
|
||||||
onClick {
|
onClickEvent { _, x, y ->
|
||||||
// we need to check if the label was just clicked, as onClick will propagate
|
if (!isButtonMoved()) {
|
||||||
// the click event to its touchable parent.
|
if (hit(x, y, true) == label) {
|
||||||
if(!isLabelClicked)
|
// clicking on the label swings that label a little down to allow selection of units there.
|
||||||
UnCivGame.Current.screen = CityScreen(city)
|
// this also allows to target selected units to move to the city tile from elsewhere.
|
||||||
isLabelClicked=false
|
// second tap on the label will go to the city screen
|
||||||
|
moveButtonDown()
|
||||||
|
if (unitTable.selectedUnit == null || unitTable.selectedUnit!!.currentMovement==0f)
|
||||||
|
tileGroup.selectCity(city)
|
||||||
|
} else {
|
||||||
|
UnCivGame.Current.screen = CityScreen(city)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// when deselected, move city button to its original position
|
// when deselected, move city button to its original position
|
||||||
val unitTable = tileGroup.worldScreen.bottomBar.unitTable
|
if (isButtonMoved()
|
||||||
if (isButtonMoved
|
&& unitTable.selectedCity != city
|
||||||
&& unitTable.selectedCity == null
|
|
||||||
&& unitTable.selectedUnit?.currentTile != city.ccenterTile) {
|
&& unitTable.selectedUnit?.currentTile != city.ccenterTile) {
|
||||||
|
|
||||||
isButtonMoved = false
|
moveButtonUp()
|
||||||
val floatAction = object : FloatAction(0f, 1f, 0.4f) {
|
|
||||||
override fun update(percent: Float) {
|
|
||||||
offset = -height*(1-percent)
|
|
||||||
update(isCityViewable)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
floatAction.interpolation = Interpolation.sine
|
|
||||||
tileGroup.addAction(floatAction)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isCityViewable && city.health < city.getMaxHealth().toFloat()) {
|
if (isCityViewable && city.health < city.getMaxHealth().toFloat()) {
|
||||||
@ -129,12 +105,47 @@ class CityButton(val city: CityInfo, internal val tileGroup: WorldTileGroup, ski
|
|||||||
add(iconTable).row()
|
add(iconTable).row()
|
||||||
pack()
|
pack()
|
||||||
setOrigin(Align.center)
|
setOrigin(Align.center)
|
||||||
center(tileGroup)
|
centerX(tileGroup)
|
||||||
y += offset // for animated shifting of City button
|
|
||||||
touchable = Touchable.enabled
|
touchable = Touchable.enabled
|
||||||
|
updateClickArea()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun moveButtonDown() {
|
||||||
|
val floatAction = Actions.sequence(
|
||||||
|
Actions.moveBy(0f, -height, 0.4f, Interpolation.swingOut),
|
||||||
|
Actions.run {
|
||||||
|
buttonDownClickArea = Actor().onClick {
|
||||||
|
UnCivGame.Current.screen = CityScreen(city)
|
||||||
|
}
|
||||||
|
tileGroup.cityButtonLayerGroup.addActor(buttonDownClickArea)
|
||||||
|
updateClickArea()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
tileGroup.addAction(floatAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun moveButtonUp() {
|
||||||
|
val floatAction = Actions.sequence(
|
||||||
|
Actions.moveBy(0f, height, 0.4f, Interpolation.sine),
|
||||||
|
Actions.run {
|
||||||
|
buttonDownClickArea?.remove()
|
||||||
|
buttonDownClickArea = null
|
||||||
|
}
|
||||||
|
)
|
||||||
|
tileGroup.addAction(floatAction)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateClickArea() {
|
||||||
|
buttonDownClickArea?.let { clickArea ->
|
||||||
|
clickArea.setSize(width, height)
|
||||||
|
clickArea.setScale(scaleX, scaleY)
|
||||||
|
clickArea.setOrigin(Align.center)
|
||||||
|
clickArea.centerX(tileGroup.cityButtonLayerGroup)
|
||||||
|
clickArea.y = y-height
|
||||||
|
clickArea.touchable = Touchable.enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getConstructionGroup(cityConstructions: CityConstructions): Group {
|
private fun getConstructionGroup(cityConstructions: CityConstructions): Group {
|
||||||
val group= Group()
|
val group= Group()
|
||||||
|
@ -55,6 +55,8 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
|
|||||||
protected var civilianUnitImage: UnitGroup? = null
|
protected var civilianUnitImage: UnitGroup? = null
|
||||||
protected var militaryUnitImage: UnitGroup? = null
|
protected var militaryUnitImage: UnitGroup? = null
|
||||||
|
|
||||||
|
val cityButtonLayerGroup = Group().apply { isTransform=true; setSize(groupSize,groupSize);touchable=Touchable.childrenOnly }
|
||||||
|
|
||||||
val circleCrosshairFogLayerGroup = Group().apply { isTransform=false; setSize(groupSize,groupSize) }
|
val circleCrosshairFogLayerGroup = Group().apply { isTransform=false; setSize(groupSize,groupSize) }
|
||||||
private val circleImage = ImageGetter.getCircle() // for blue and red circles on the tile
|
private val circleImage = ImageGetter.getCircle() // for blue and red circles on the tile
|
||||||
private val crosshairImage = ImageGetter.getImage("OtherIcons/Crosshair.png") // for when a unit is targete
|
private val crosshairImage = ImageGetter.getImage("OtherIcons/Crosshair.png") // for when a unit is targete
|
||||||
@ -76,6 +78,7 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
|
|||||||
this.addActor(featureLayerGroup)
|
this.addActor(featureLayerGroup)
|
||||||
this.addActor(miscLayerGroup)
|
this.addActor(miscLayerGroup)
|
||||||
this.addActor(unitLayerGroup)
|
this.addActor(unitLayerGroup)
|
||||||
|
this.addActor(cityButtonLayerGroup)
|
||||||
this.addActor(circleCrosshairFogLayerGroup)
|
this.addActor(circleCrosshairFogLayerGroup)
|
||||||
|
|
||||||
updateTileImage(false)
|
updateTileImage(false)
|
||||||
|
@ -122,20 +122,23 @@ fun Label.setFontSize(size:Int): Label {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** same as [onClick], but sends the [InputEvent] and coordinates along */
|
||||||
// If there are other buttons that require special clicks then we'll have an onclick that will accept a string parameter, no worries
|
fun Actor.onClickEvent(sound: String = "click", function: (event: InputEvent?, x: Float, y: Float) -> Unit) {
|
||||||
|
|
||||||
fun Actor.onClick(sound:String,function: () -> Unit){
|
|
||||||
this.addListener(object : ClickListener() {
|
this.addListener(object : ClickListener() {
|
||||||
override fun clicked(event: InputEvent?, x: Float, y: Float) {
|
override fun clicked(event: InputEvent?, x: Float, y: Float) {
|
||||||
if(sound!="") Sounds.play(sound)
|
if (sound != "") Sounds.play(sound)
|
||||||
function()
|
function(event, x, y)
|
||||||
}
|
}
|
||||||
} )
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are other buttons that require special clicks then we'll have an onclick that will accept a string parameter, no worries
|
||||||
|
fun Actor.onClick(sound: String = "click", function: () -> Unit) {
|
||||||
|
onClickEvent(sound) { _, _, _ -> function() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Actor.onClick(function: () -> Unit): Actor {
|
fun Actor.onClick(function: () -> Unit): Actor {
|
||||||
onClick("click",function)
|
onClick("click", function)
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ class TileGroupMap<T: TileGroup>(val tileGroups:Collection<T>, padding:Float): G
|
|||||||
val featureLayers = ArrayList<Group>()
|
val featureLayers = ArrayList<Group>()
|
||||||
val miscLayers = ArrayList<Group>()
|
val miscLayers = ArrayList<Group>()
|
||||||
val unitLayers = ArrayList<Group>()
|
val unitLayers = ArrayList<Group>()
|
||||||
|
val cityButtonLayers = ArrayList<Group>()
|
||||||
val circleCrosshairFogLayers = ArrayList<Group>()
|
val circleCrosshairFogLayers = ArrayList<Group>()
|
||||||
|
|
||||||
for(group in tileGroups.sortedByDescending { it.tileInfo.position.x + it.tileInfo.position.y }){
|
for(group in tileGroups.sortedByDescending { it.tileInfo.position.x + it.tileInfo.position.y }){
|
||||||
@ -39,6 +40,7 @@ class TileGroupMap<T: TileGroup>(val tileGroups:Collection<T>, padding:Float): G
|
|||||||
featureLayers.add(group.featureLayerGroup.apply { setPosition(group.x,group.y) })
|
featureLayers.add(group.featureLayerGroup.apply { setPosition(group.x,group.y) })
|
||||||
miscLayers.add(group.miscLayerGroup.apply { setPosition(group.x,group.y) })
|
miscLayers.add(group.miscLayerGroup.apply { setPosition(group.x,group.y) })
|
||||||
unitLayers.add(group.unitLayerGroup.apply { setPosition(group.x,group.y) })
|
unitLayers.add(group.unitLayerGroup.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) })
|
circleCrosshairFogLayers.add(group.circleCrosshairFogLayerGroup.apply { setPosition(group.x,group.y) })
|
||||||
}
|
}
|
||||||
for(group in baseLayers) addActor(group)
|
for(group in baseLayers) addActor(group)
|
||||||
@ -46,6 +48,7 @@ class TileGroupMap<T: TileGroup>(val tileGroups:Collection<T>, padding:Float): G
|
|||||||
for(group in miscLayers) addActor(group)
|
for(group in miscLayers) addActor(group)
|
||||||
for(group in circleCrosshairFogLayers) 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
|
for(group in tileGroups) addActor(group) // The above layers are for the visual layers, this is for the clickability
|
||||||
|
for(group in cityButtonLayers) addActor(group) // city buttons clickability
|
||||||
for(group in unitLayers) addActor(group) // Aaand units above everything else.
|
for(group in unitLayers) addActor(group) // Aaand units above everything else.
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user