Enemy indicator, city culture hex outline + misc (#8629)

* Rework of UnitGroup, City culture tile hex-outline, tweak enemy indicators

* Rework of UnitGroup, City culture tile hex-outline, tweak enemy indicators

* Better embarked selection sprite

* Small fixes

* Hotfix fog

---------

Co-authored-by: tunerzinc@gmail.com <vfylfhby>
This commit is contained in:
vegeta1k95
2023-02-09 17:46:02 +01:00
committed by GitHub
parent 4a3f7f0250
commit ca86e6fde7
18 changed files with 706 additions and 619 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 891 KiB

After

Width:  |  Height:  |  Size: 897 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 469 KiB

After

Width:  |  Height:  |  Size: 493 KiB

View File

@ -28,6 +28,7 @@ import com.unciv.ui.tilegroups.TileSetStrings
import com.unciv.ui.utils.BaseScreen
import com.unciv.ui.utils.KeyCharAndCode
import com.unciv.ui.utils.RecreateOnResize
import com.unciv.ui.utils.extensions.colorFromRGB
import com.unciv.ui.utils.extensions.disable
import com.unciv.ui.utils.extensions.keyShortcuts
import com.unciv.ui.utils.extensions.onActivation
@ -226,18 +227,16 @@ class CityScreen(
}
for (tileGroup in tileGroups) {
tileGroup.update()
tileGroup.layerOverlay.hideHighlight()
tileGroup.layerMisc.removeHexOutline()
when {
tileGroup.tile == nextTileToOwn -> {
tileGroup.layerOverlay.showHighlight(Color.PURPLE)
tileGroup.setColor(0f, 0f, 0f, 0.7f)
}
tileGroup.tile == nextTileToOwn ->
tileGroup.layerMisc.addHexOutline(colorFromRGB(200, 20, 220))
/** Support for [UniqueType.CreatesOneImprovement] */
tileGroup.tile == selectedQueueEntryTargetTile ->
tileGroup.layerOverlay.showHighlight(Color.BROWN, 0.7f)
tileGroup.layerMisc.addHexOutline(Color.BROWN)
pickTileData != null && city.tiles.contains(tileGroup.tile.position) ->
getPickImprovementColor(tileGroup.tile).run {
tileGroup.layerOverlay.showHighlight(first, second) }
tileGroup.layerMisc.addHexOutline(first.cpy().apply { this.a = second }) }
}
}
}

View File

@ -178,6 +178,12 @@ object ImageGetter {
return textureRegionDrawables[fileName] ?: textureRegionDrawables[whiteDotLocation]!!
}
fun getDrawableOrNull(fileName: String?): TextureRegionDrawable? {
if (fileName == null)
return null
return textureRegionDrawables[fileName]
}
fun getNinePatch(fileName: String?, tintColor: Color? = null): NinePatchDrawable {
val drawable = ninePatchDrawables[fileName] ?: NinePatchDrawable(NinePatch(textureRegionDrawables[whiteDotLocation]!!.region))

View File

@ -78,13 +78,14 @@ open class TileGroup(
layerTerrain.reset()
layerBorders.reset()
layerMisc.reset()
layerOverlay.reset()
layerUnitArt.reset()
layerUnitFlag.reset()
layerOverlay.setFog(true)
}
open fun update(viewingCiv: Civilization? = null) {
layerMisc.removeHexOutline()
layerOverlay.hideHighlight()
layerOverlay.hideCrosshair()

View File

@ -61,6 +61,7 @@ class TileLayerMisc(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup, si
private val arrowsToDraw = ArrayList<MapArrow>()
private val arrows = HashMap<Tile, ArrayList<Actor>>()
private var hexOutlineIcon: Actor? = null
private var resourceName: String? = null
private var resourceIcon: Actor? = null
private var workedIcon: Actor? = null
@ -256,6 +257,21 @@ class TileLayerMisc(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup, si
determineVisibility()
}
fun addHexOutline(color: Color) {
hexOutlineIcon?.remove()
hexOutlineIcon = ImageGetter.getImage("OtherIcons/HexagonOutline").setHexagonSize(1f)
hexOutlineIcon!!.color = color
addActor(hexOutlineIcon)
hexOutlineIcon!!.toBack()
determineVisibility()
}
fun removeHexOutline() {
hexOutlineIcon?.remove()
hexOutlineIcon = null
determineVisibility()
}
fun addArrow(targetTile: Tile, type: MapArrowType) {
if (targetTile.position != tile().position)
@ -298,6 +314,7 @@ class TileLayerMisc(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup, si
|| resourceIcon?.isVisible == true
|| improvementIcon != null
|| workedIcon != null
|| hexOutlineIcon != null
|| arrows.isNotEmpty()
|| startingLocationIcons.isNotEmpty()
}

View File

@ -40,11 +40,6 @@ class TileLayerOverlay(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup,
determineVisibility()
}
fun setFog(isVisible: Boolean) {
fog.isVisible = isVisible && !tileGroup.isForceVisible
determineVisibility()
}
fun showHighlight(color: Color, alpha: Float = 0.3f) {
highlight.isVisible = true
highlight.color = color.cpy().apply { a = alpha }
@ -61,10 +56,19 @@ class TileLayerOverlay(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup,
determineVisibility()
}
fun reset() {
fog.isVisible = true
highlight.isVisible = false
crosshair.isVisible = false
determineVisibility()
}
override fun doUpdate(viewingCiv: Civilization?) {
val isViewable = viewingCiv == null || isViewable(viewingCiv)
setFog(!isViewable)
if (!isViewable && !tileGroup.isForceVisible)
fog.isVisible = true
if (viewingCiv == null)
return

View File

@ -8,15 +8,17 @@ import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.tilegroups.TileGroup
private class UnitArtSlot : Group() {
var imageLocation = ""
}
class TileLayerUnitArt(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup, size) {
override fun act(delta: Float) {}
override fun hit(x: Float, y: Float, touchable: Boolean): Actor? = null
private var locations = Array(2){""}
private var slot1: Group = Group()
private var slot2: Group = Group()
private var slot1: UnitArtSlot = UnitArtSlot()
private var slot2: UnitArtSlot = UnitArtSlot()
init {
addActor(slot1)
@ -27,7 +29,7 @@ class TileLayerUnitArt(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup,
|| viewingCiv.viewableInvisibleUnitsTiles.contains(tileGroup.tile)
|| !tileGroup.tile.hasEnemyInvisibleUnit(viewingCiv)
private fun updateSlot(index: Int, unit: MapUnit?, isShown: Boolean) {
private fun updateSlot(slot: UnitArtSlot, unit: MapUnit?, isShown: Boolean) {
var location = ""
var nationName = ""
@ -37,11 +39,9 @@ class TileLayerUnitArt(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup,
nationName = "${unit.civ.civName}-"
}
if (locations[index] != "$nationName$location") {
locations[index] = "$nationName$location"
val group: Group = if (index == 0) slot1 else slot2
group.clear()
if (slot.imageLocation != "$nationName$location") {
slot.imageLocation = "$nationName$location"
slot.clear()
if (location != "" && ImageGetter.imageExists(location)) {
val nation = unit!!.civ.nation
@ -52,7 +52,7 @@ class TileLayerUnitArt(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup,
nation.getOuterColor()
)
for (pixelUnitImage in pixelUnitImages) {
group.addActor(pixelUnitImage)
slot.addActor(pixelUnitImage)
pixelUnitImage.setHexagonSize()// Treat this as A TILE, which gets overlayed on the base tile.
}
}
@ -75,8 +75,8 @@ class TileLayerUnitArt(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup,
val isSlot1Shown = isPixelUnitsEnabled && isViewable
val isSlot2Shown = isPixelUnitsEnabled && isViewable && isVisibleMilitary
updateSlot(0, slot1Unit, isShown = isSlot1Shown)
updateSlot(1, slot2Unit, isShown = isSlot2Shown)
updateSlot(slot1, slot1Unit, isShown = isSlot1Shown)
updateSlot(slot2, slot2Unit, isShown = isSlot2Shown)
}
override fun determineVisibility() {
@ -84,7 +84,10 @@ class TileLayerUnitArt(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup,
}
fun reset() {
updateSlot(0, null, false)
updateSlot(1, null, false)
slot1.clear()
slot2.clear()
slot1.imageLocation = ""
slot2.imageLocation = ""
}
}

View File

@ -51,7 +51,7 @@ class TileLayerUnitFlag(tileGroup: TileGroup, size: Float) : TileLayer(tileGroup
var newIcon: UnitGroup? = null
if (unit != null && isViewable) {
newIcon = UnitGroup(unit, 25f)
newIcon = UnitGroup(unit, 30f)
addActor(newIcon)
setIconPosition(slot, newIcon)

View File

@ -1,102 +1,149 @@
package com.unciv.ui.utils
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.g2d.Batch
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.actions.Actions
import com.badlogic.gdx.scenes.scene2d.actions.RepeatAction
import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable
import com.badlogic.gdx.utils.Align
import com.unciv.UncivGame
import com.unciv.logic.map.mapunit.MapUnit
import com.unciv.ui.images.ImageGetter
import com.unciv.ui.utils.extensions.center
import com.unciv.ui.utils.extensions.addToCenter
import com.unciv.ui.utils.extensions.colorFromRGB
import com.unciv.ui.utils.extensions.setSize
import com.unciv.ui.utils.extensions.surroundWithCircle
import com.unciv.ui.utils.extensions.surroundWithThinCircle
class UnitGroup(val unit: MapUnit, val size: Float): Group() {
var actionGroup :Group? = null
val flagIcon = ImageGetter.getUnitIcon(unit.name, unit.civ.nation.getInnerColor())
.apply {
if (unit.isCivilian())
setSize(size * 0.60f, size * 0.60f)
else
setSize(size * 0.75f, size * 0.75f) }
var flagSelection: Image = getBackgroundSelectionForUnit()
var flagBg: Group = Group()
class FlagBackground(drawable: TextureRegionDrawable, size: Float): Image(drawable) {
var drawableInner: TextureRegionDrawable? = null
var innerColor: Color = Color.WHITE
var outerColor: Color = Color.RED
var outlineColor: Color = Color.WHITE
var drawOutline = false
private val innerMultiplier = 0.88f
private val outlineMultiplier = 1.08f
private val innerWidth: Float; private val innerHeight: Float
private val innerOffsetX: Float; private val innerOffsetY: Float
private val outlineWidth: Float; private val outlineHeight: Float
private val outlineOffsetX: Float; private val outlineOffsetY: Float
init {
val outerBg = getBackgroundImageForUnit()
val innerBg = getBackgroundImageForUnit()
val maskBg = getBackgroundMaskForUnit()
val ratio = height/width
width = size
height = size * ratio
val sizeSelectionX = size*1.9f; val sizeSelectionY = sizeSelectionX*flagSelection.height/flagSelection.width
val sizeOuterBgX = size*1.15f; val sizeOuterBgY = sizeOuterBgX*outerBg.height/outerBg.width
val sizeInnerBgX = size; val sizeInnerBgY = sizeInnerBgX*innerBg.height/innerBg.width
innerWidth = width * innerMultiplier; innerHeight = height * innerMultiplier
innerOffsetX = (width - innerWidth) / 2; innerOffsetY = (height - innerHeight) / 2
setSize(sizeOuterBgX, sizeOuterBgY)
outlineWidth = width * outlineMultiplier; outlineHeight = height * outlineMultiplier
outlineOffsetX = (outlineWidth - width) / 2; outlineOffsetY = (outlineHeight - height) / 2
}
flagSelection.color.set(1f, 1f, 1f, 0f)
override fun getDrawable(): TextureRegionDrawable {
return super.getDrawable() as TextureRegionDrawable
}
override fun draw(batch: Batch?, parentAlpha: Float) {
val alpha = color.a*parentAlpha
val drawable = drawable
if (drawOutline) {
batch?.setColor(outlineColor.r, outlineColor.g, outlineColor.b, outlineColor.a*alpha)
drawable.draw(batch, x-outlineOffsetX, y-outlineOffsetY, outlineWidth, outlineHeight)
}
batch?.setColor(outerColor.r, outerColor.g, outerColor.b, outerColor.a*alpha)
drawable.draw(batch, x, y, width, height)
batch?.setColor(innerColor.r, innerColor.g, innerColor.b, innerColor.a * alpha)
if (drawableInner == null) {
drawable.draw(batch, x + innerOffsetX, y + innerOffsetY, innerWidth, innerHeight)
} else {
drawableInner!!.draw(batch, x, y, width, height)
}
}
}
class UnitGroup(val unit: MapUnit, val size: Float): Group() {
var actionGroup :Group? = null
private val flagIcon = ImageGetter.getUnitIcon(unit.name, unit.civ.nation.getInnerColor())
private var flagBg: FlagBackground = FlagBackground(getBackgroundDrawableForUnit(), size)
private var flagSelection: Image = getBackgroundSelectionForUnit()
private var flagMask: Image? = getBackgroundMaskForUnit()
init {
isTransform = false // performance helper - nothing here is rotated or scaled
color.a *= UncivGame.Current.settings.unitIconOpacity
val sizeSelectionX = size*1.6f
val sizeSelectionY = sizeSelectionX*flagSelection.height/flagSelection.width
setSize(flagBg.width, flagBg.height)
flagSelection.color.set(1f, 1f, 0.9f, 0f)
flagSelection.align = Align.center
flagSelection.setSize(sizeSelectionX, sizeSelectionY)
flagSelection.center(this)
flagBg.setSize(sizeOuterBgX, sizeOuterBgY)
flagBg.innerColor = unit.civ.nation.getOuterColor()
flagBg.outerColor = unit.civ.nation.getInnerColor()
flagBg.outlineColor = flagBg.innerColor
flagBg.drawableInner = getBackgroundInnerDrawableForUnit()
// 0f (invisible) to 1f (fully opaque)
flagIcon.color.a = UncivGame.Current.settings.unitIconOpacity
if (flagMask != null) {
flagMask!!.setSize(size*0.88f, size*0.88f * flagMask!!.height / flagMask!!.width)
}
outerBg.color = unit.civ.nation.getInnerColor()
outerBg.color.a = UncivGame.Current.settings.unitIconOpacity
outerBg.setSize(sizeOuterBgX, sizeOuterBgY)
outerBg.center(flagBg)
val flagIconSizeMultiplier: Float = if (unit.isCivilian()) 0.5f else 0.65f
flagIcon.setSize(size * flagIconSizeMultiplier)
innerBg.color = unit.civ.nation.getOuterColor()
innerBg.color.a = UncivGame.Current.settings.unitIconOpacity
innerBg.setSize(sizeInnerBgX, sizeInnerBgY)
innerBg.center(flagBg)
maskBg?.color?.a = UncivGame.Current.settings.unitIconOpacity
maskBg?.setSize(size, size*maskBg.height / maskBg.width)
maskBg?.center(flagBg)
flagBg.addActor(outerBg)
flagBg.addActor(innerBg)
if (maskBg != null)
flagBg.addActor(maskBg)
flagBg.center(this)
flagIcon.center(this)
addActor(flagSelection)
addActor(flagBg)
addActor(flagIcon)
addToCenter(flagSelection)
addToCenter(flagBg)
if (flagMask != null)
addToCenter(flagMask!!)
addToCenter(flagIcon)
val actionImage = getActionImage()
if (actionImage != null) {
val actionCircle = actionImage
.surroundWithCircle(size / 2 * 0.9f)
actionGroup = actionImage
.surroundWithCircle(size/2 * 0.9f)
.surroundWithThinCircle()
actionCircle.setPosition(size / 2, 0f)
actionCircle.color.a = UncivGame.Current.settings.unitIconOpacity
addActor(actionCircle)
actionGroup = actionCircle
actionCircle.toFront()
actionGroup!!.setPosition(size/2, 0f)
addActor(actionGroup)
}
if (unit.health < 100) { // add health bar
addActor(ImageGetter.getHealthBar(unit.health.toFloat(), 100f, size))
}
isTransform = false // performance helper - nothing here is rotated or scaled
}
private fun getBackgroundImageForUnit(): Image {
private fun getBackgroundDrawableForUnit(): TextureRegionDrawable {
return when {
unit.isEmbarked() -> ImageGetter.getImage("UnitFlagIcons/UnitFlagEmbark")
unit.isFortified() -> ImageGetter.getImage("UnitFlagIcons/UnitFlagFortify")
unit.isCivilian() -> ImageGetter.getImage("UnitFlagIcons/UnitFlagCivilian")
else -> ImageGetter.getImage("UnitFlagIcons/UnitFlag")
unit.isEmbarked() -> ImageGetter.getDrawable("UnitFlagIcons/UnitFlagEmbark")
unit.isFortified() -> ImageGetter.getDrawable("UnitFlagIcons/UnitFlagFortify")
unit.isCivilian() -> ImageGetter.getDrawable("UnitFlagIcons/UnitFlagCivilian")
else -> ImageGetter.getDrawable("UnitFlagIcons/UnitFlag")
}
}
private fun getBackgroundInnerDrawableForUnit(): TextureRegionDrawable? {
return when {
unit.isEmbarked() -> ImageGetter.getDrawableOrNull("UnitFlagIcons/UnitFlagEmbarkInner")
unit.isFortified() -> ImageGetter.getDrawableOrNull("UnitFlagIcons/UnitFlagFortifyInner")
unit.isCivilian() -> ImageGetter.getDrawableOrNull("UnitFlagIcons/UnitFlagCivilianInner")
else -> ImageGetter.getDrawableOrNull("UnitFlagIcons/UnitFlagInner")
}
}
@ -135,16 +182,12 @@ class UnitGroup(val unit: MapUnit, val size: Float): Group() {
}
fun highlightRed() {
flagSelection.color = colorFromRGB(230, 20, 0).apply { a = 1.0f }
flagSelection.width *= 0.9f
flagSelection.height *= 0.9f
flagSelection.center(flagSelection.parent)
flagSelection.color = colorFromRGB(230, 0, 0).apply { a = 1f }
flagBg.drawOutline = true
}
fun selectUnit() {
//Make unit icon background colors fully opaque when units are selected
flagBg.children.forEach { it.color?.a = 1f }
color.a = 1f
//If unit is idle, leave actionGroup at 50% opacity when selected
if (unit.isIdle()) {
@ -160,6 +203,7 @@ class UnitGroup(val unit: MapUnit, val size: Float): Group() {
val alpha = if (shouldBeFaded) 0.5f else 1f
flagIcon.color.a = alpha
flagBg.color.a = alpha
flagSelection.color.a = 1f
if (UncivGame.Current.settings.continuousRendering) {
flagSelection.color.a = 1f
@ -167,7 +211,7 @@ class UnitGroup(val unit: MapUnit, val size: Float): Group() {
Actions.repeat(
RepeatAction.FOREVER,
Actions.sequence(
Actions.alpha(0.6f, 1f),
Actions.alpha(0.7f, 1f),
Actions.alpha(1f, 1f)
)
)

View File

@ -733,8 +733,7 @@ class WorldMapHolder(
for (tileGroup in tileGroups.values) {
tileGroup.layerCityButton.isTransform = false // to save on rendering time to improve framerate
}
}
if (clampedCityButtonZoom < 1 && clampedCityButtonZoom >= minZoom) {
} else if (clampedCityButtonZoom >= minZoom) {
for (tileGroup in tileGroups.values) {
// ONLY set those groups that have active city buttons as transformable!
// This is massively framerate-improving!