mirror of
https://github.com/yairm210/Unciv.git
synced 2025-02-01 10:25:57 +07:00
Multiple performance improvements - managed to lower update time of a busy map from 1 second (which is A LOT) to 0.3, still room for improvement but nowhere near as bad!
This commit is contained in:
parent
bed7a37a6b
commit
bbbccc96ef
@ -45,8 +45,16 @@ open class TileInfo {
|
|||||||
val tileImprovement: TileImprovement?
|
val tileImprovement: TileImprovement?
|
||||||
get() = if (improvement == null) null else GameBasics.TileImprovements[improvement!!]
|
get() = if (improvement == null) null else GameBasics.TileImprovements[improvement!!]
|
||||||
|
|
||||||
|
|
||||||
|
// This is for performance - since we access the neighbors of a tile ALL THE TIME,
|
||||||
|
// and the neighbors of a tile never change, it's much more CPU efficient to save the list once and for all!
|
||||||
|
@Transient private var internalNeighbors : List<TileInfo>?=null
|
||||||
val neighbors: List<TileInfo>
|
val neighbors: List<TileInfo>
|
||||||
get() = tileMap.getTilesAtDistance(position, 1)
|
get(){
|
||||||
|
if(internalNeighbors==null)
|
||||||
|
internalNeighbors = tileMap.getTilesAtDistance(position, 1)
|
||||||
|
return internalNeighbors!!
|
||||||
|
}
|
||||||
|
|
||||||
val height: Int
|
val height: Int
|
||||||
get() {
|
get() {
|
||||||
|
@ -16,10 +16,13 @@ open class Stats() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun add(other: Stats) {
|
fun add(other: Stats) {
|
||||||
val hashMap = toHashMap()
|
// Doing this through the hashmap is nicer code but is SUPER INEFFICIENT!
|
||||||
for (stat in Stat.values())
|
production += other.production
|
||||||
hashMap[stat] = hashMap[stat]!! + other.toHashMap()[stat]!!
|
food += other.food
|
||||||
setStats(hashMap)
|
gold += other.gold
|
||||||
|
science += other.science
|
||||||
|
culture += other.culture
|
||||||
|
happiness += other.happiness
|
||||||
}
|
}
|
||||||
|
|
||||||
fun add(stat:Stat, value:Float): Stats {
|
fun add(stat:Stat, value:Float): Stats {
|
||||||
@ -35,12 +38,6 @@ open class Stats() {
|
|||||||
return stats
|
return stats
|
||||||
}
|
}
|
||||||
|
|
||||||
operator fun unaryMinus(): Stats {
|
|
||||||
val hashMap = toHashMap()
|
|
||||||
for(stat in Stat.values()) hashMap[stat]= -hashMap[stat]!!
|
|
||||||
return Stats(hashMap)
|
|
||||||
}
|
|
||||||
|
|
||||||
operator fun times(number: Float): Stats {
|
operator fun times(number: Float): Stats {
|
||||||
val hashMap = toHashMap()
|
val hashMap = toHashMap()
|
||||||
for(stat in Stat.values()) hashMap[stat]= number * hashMap[stat]!!
|
for(stat in Stat.values()) hashMap[stat]= number * hashMap[stat]!!
|
||||||
|
@ -21,8 +21,8 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
|
|||||||
protected var resourceImage: Image? = null
|
protected var resourceImage: Image? = null
|
||||||
protected var improvementImage: Image? =null
|
protected var improvementImage: Image? =null
|
||||||
var populationImage: Image? = null
|
var populationImage: Image? = null
|
||||||
private val roadImages = HashMap<String, Image>()
|
private val roadImages = HashMap<TileInfo, Image>()
|
||||||
private val borderImages = ArrayList<Image>()
|
private val borderImages = HashMap<TileInfo, List<Image>>() // map of neiboring tile to border images
|
||||||
protected var civilianUnitImage: Group? = null
|
protected var civilianUnitImage: Group? = null
|
||||||
protected var militaryUnitImage: Group? = null
|
protected var militaryUnitImage: Group? = null
|
||||||
private val circleImage = ImageGetter.getImage("OtherIcons/Circle.png") // for blue and red circles on the tile
|
private val circleImage = ImageGetter.getImage("OtherIcons/Circle.png") // for blue and red circles on the tile
|
||||||
@ -106,18 +106,36 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateBorderImages() {
|
private fun updateBorderImages() {
|
||||||
for (border in borderImages) border.remove() //clear
|
// This is longer than it could be, because of performance -
|
||||||
borderImages.clear()
|
// before fixing, about half (!) the time of update() was wasted on
|
||||||
|
// removing all the border images and putting them back again!
|
||||||
|
val tileOwner = tileInfo.getOwner()
|
||||||
|
if (tileOwner == null){
|
||||||
|
for(images in borderImages.values)
|
||||||
|
for(image in images)
|
||||||
|
image.remove()
|
||||||
|
|
||||||
if (tileInfo.getOwner() != null) {
|
borderImages.clear()
|
||||||
val civColor = tileInfo.getOwner()!!.getCivilization().getColor()
|
return
|
||||||
for (neighbor in tileInfo.neighbors.filter { it.getOwner() != tileInfo.getOwner() }) {
|
}
|
||||||
|
|
||||||
|
val civColor = tileInfo.getOwner()!!.getCivilization().getColor()
|
||||||
|
for (neighbor in tileInfo.neighbors) {
|
||||||
|
val neigborOwner = neighbor.getOwner()
|
||||||
|
if(neigborOwner == tileOwner && borderImages.containsKey(neighbor)) // the neighbor used to not belong to us, but now it's ours
|
||||||
|
{
|
||||||
|
for(image in borderImages[neighbor]!!)
|
||||||
|
image.remove()
|
||||||
|
borderImages.remove(neighbor)
|
||||||
|
}
|
||||||
|
if(neigborOwner!=tileOwner && !borderImages.containsKey(neighbor)){ // there should be a border here but there isn't
|
||||||
|
|
||||||
val relativeHexPosition = tileInfo.position.cpy().sub(neighbor.position)
|
val relativeHexPosition = tileInfo.position.cpy().sub(neighbor.position)
|
||||||
val relativeWorldPosition = HexMath().Hex2WorldCoords(relativeHexPosition)
|
val relativeWorldPosition = HexMath().Hex2WorldCoords(relativeHexPosition)
|
||||||
|
|
||||||
// This is some crazy voodoo magic so I'll explain.
|
// This is some crazy voodoo magic so I'll explain.
|
||||||
|
val images = mutableListOf<Image>()
|
||||||
|
borderImages.put(neighbor,images)
|
||||||
for(i in -2..2) {
|
for(i in -2..2) {
|
||||||
val image = ImageGetter.getImage("OtherIcons/Circle.png")
|
val image = ImageGetter.getImage("OtherIcons/Circle.png")
|
||||||
image.setSize(5f, 5f)
|
image.setSize(5f, 5f)
|
||||||
@ -136,11 +154,9 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
|
|||||||
|
|
||||||
image.color = civColor
|
image.color = civColor
|
||||||
addActor(image)
|
addActor(image)
|
||||||
borderImages.add(image)
|
images.add(image)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,9 +164,9 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
|
|||||||
if (tileInfo.roadStatus !== RoadStatus.None) {
|
if (tileInfo.roadStatus !== RoadStatus.None) {
|
||||||
for (neighbor in tileInfo.neighbors) {
|
for (neighbor in tileInfo.neighbors) {
|
||||||
if (neighbor.roadStatus === RoadStatus.None) continue
|
if (neighbor.roadStatus === RoadStatus.None) continue
|
||||||
if (!roadImages.containsKey(neighbor.position.toString())) {
|
if (!roadImages.containsKey(neighbor)) {
|
||||||
val image = ImageGetter.getImage(ImageGetter.WhiteDot)
|
val image = ImageGetter.getImage(ImageGetter.WhiteDot)
|
||||||
roadImages[neighbor.position.toString()] = image
|
roadImages[neighbor] = image
|
||||||
|
|
||||||
val relativeHexPosition = tileInfo.position.cpy().sub(neighbor.position)
|
val relativeHexPosition = tileInfo.position.cpy().sub(neighbor.position)
|
||||||
val relativeWorldPosition = HexMath().Hex2WorldCoords(relativeHexPosition)
|
val relativeWorldPosition = HexMath().Hex2WorldCoords(relativeHexPosition)
|
||||||
@ -168,9 +184,9 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (tileInfo.roadStatus === RoadStatus.Railroad && neighbor.roadStatus === RoadStatus.Railroad)
|
if (tileInfo.roadStatus === RoadStatus.Railroad && neighbor.roadStatus === RoadStatus.Railroad)
|
||||||
roadImages[neighbor.position.toString()]!!.color = Color.GRAY // railroad
|
roadImages[neighbor]!!.color = Color.GRAY // railroad
|
||||||
else
|
else
|
||||||
roadImages[neighbor.position.toString()]!!.color = Color.BROWN // road
|
roadImages[neighbor]!!.color = Color.BROWN // road
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,13 +236,15 @@ open class TileGroup(var tileInfo: TileInfo) : Group() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun updateResourceImage(viewable: Boolean) {
|
private fun updateResourceImage(viewable: Boolean) {
|
||||||
if(resourceImage!=null){
|
val shouldDisplayResource = UnCivGame.Current.settings.showResourcesAndImprovements
|
||||||
|
&& tileInfo.hasViewableResource(tileInfo.tileMap.gameInfo.getPlayerCivilization())
|
||||||
|
|
||||||
|
if(resourceImage!=null && !shouldDisplayResource){
|
||||||
resourceImage!!.remove()
|
resourceImage!!.remove()
|
||||||
resourceImage=null
|
resourceImage=null
|
||||||
}
|
}
|
||||||
|
|
||||||
if(UnCivGame.Current.settings.showResourcesAndImprovements
|
if(resourceImage==null && shouldDisplayResource) { // Need to add the resource image!
|
||||||
&& tileInfo.hasViewableResource(tileInfo.tileMap.gameInfo.getPlayerCivilization())) { // Need to add the resource image!
|
|
||||||
val fileName = "ResourceIcons/" + tileInfo.resource + "_(Civ5).png"
|
val fileName = "ResourceIcons/" + tileInfo.resource + "_(Civ5).png"
|
||||||
resourceImage = ImageGetter.getImage(fileName)
|
resourceImage = ImageGetter.getImage(fileName)
|
||||||
resourceImage!!.setSize(20f, 20f)
|
resourceImage!!.setSize(20f, 20f)
|
||||||
|
@ -42,6 +42,10 @@ class WorldScreen : CameraStageBaseScreen() {
|
|||||||
|
|
||||||
tileMapHolder.addTiles()
|
tileMapHolder.addTiles()
|
||||||
|
|
||||||
|
techButton.addClickListener {
|
||||||
|
game.screen = TechPickerScreen(civInfo)
|
||||||
|
}
|
||||||
|
|
||||||
stage.addActor(tileMapHolder)
|
stage.addActor(tileMapHolder)
|
||||||
stage.addActor(minimap)
|
stage.addActor(minimap)
|
||||||
stage.addActor(topBar)
|
stage.addActor(topBar)
|
||||||
@ -87,10 +91,6 @@ class WorldScreen : CameraStageBaseScreen() {
|
|||||||
|
|
||||||
private fun updateTechButton() {
|
private fun updateTechButton() {
|
||||||
techButton.isVisible = civInfo.cities.isNotEmpty()
|
techButton.isVisible = civInfo.cities.isNotEmpty()
|
||||||
techButton.clearListeners()
|
|
||||||
techButton.addClickListener {
|
|
||||||
game.screen = TechPickerScreen(civInfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (civInfo.tech.currentTechnology() == null)
|
if (civInfo.tech.currentTechnology() == null)
|
||||||
techButton.setText("{Pick a tech}!".tr())
|
techButton.setText("{Pick a tech}!".tr())
|
||||||
@ -132,6 +132,7 @@ class WorldScreen : CameraStageBaseScreen() {
|
|||||||
// but the main thread does other stuff, including showing tutorials which guess what? Changes the game data
|
// but the main thread does other stuff, including showing tutorials which guess what? Changes the game data
|
||||||
// BOOM! Exception!
|
// BOOM! Exception!
|
||||||
// That's why this needs to be after the game is saved.
|
// That's why this needs to be after the game is saved.
|
||||||
|
bottomBar.unitTable.shouldUpdateVisually=true
|
||||||
shouldUpdate=true
|
shouldUpdate=true
|
||||||
|
|
||||||
nextTurnButton.setText("Next turn".tr())
|
nextTurnButton.setText("Next turn".tr())
|
||||||
|
@ -25,6 +25,11 @@ class WorldScreenTopBar(val screen: WorldScreen) : Table() {
|
|||||||
private val resourceLabels = HashMap<String, Label>()
|
private val resourceLabels = HashMap<String, Label>()
|
||||||
private val resourceImages = HashMap<String, Image>()
|
private val resourceImages = HashMap<String, Image>()
|
||||||
private val happinessImage = ImageGetter.getStatIcon("Happiness")
|
private val happinessImage = ImageGetter.getStatIcon("Happiness")
|
||||||
|
// These are all to improve performance IE recude update time (was 150 ms on my phone, which is a lot!)
|
||||||
|
private val malcontentColor = Color.valueOf("ef5350")
|
||||||
|
val happinessColor = colorFromRGB(92, 194, 77)
|
||||||
|
val malcontentDrawable = ImageGetter.getStatIcon("Malcontent").drawable
|
||||||
|
val happinessDrawable = ImageGetter.getStatIcon("Happiness").drawable
|
||||||
|
|
||||||
init {
|
init {
|
||||||
background = ImageGetter.getDrawable("skin/whiteDot.png").tint(ImageGetter.getBlue().lerp(Color.BLACK, 0.5f))
|
background = ImageGetter.getDrawable("skin/whiteDot.png").tint(ImageGetter.getBlue().lerp(Color.BLACK, 0.5f))
|
||||||
@ -123,11 +128,11 @@ class WorldScreenTopBar(val screen: WorldScreen) : Table() {
|
|||||||
happinessLabel.setText(getHappinessText(civInfo))
|
happinessLabel.setText(getHappinessText(civInfo))
|
||||||
|
|
||||||
if (civInfo.happiness < 0) {
|
if (civInfo.happiness < 0) {
|
||||||
happinessLabel.setFontColor(Color.valueOf("ef5350"))
|
happinessLabel.setFontColor(malcontentColor)
|
||||||
happinessImage.drawable = ImageGetter.getStatIcon("Malcontent").drawable
|
happinessImage.drawable = malcontentDrawable
|
||||||
} else {
|
} else {
|
||||||
happinessLabel.setFontColor(colorFromRGB(92, 194, 77))
|
happinessLabel.setFontColor(happinessColor)
|
||||||
happinessImage.drawable = ImageGetter.getStatIcon("Happiness").drawable
|
happinessImage.drawable = happinessDrawable
|
||||||
}
|
}
|
||||||
|
|
||||||
cultureLabel.setText(getCultureText(civInfo, nextTurnStats))
|
cultureLabel.setText(getCultureText(civInfo, nextTurnStats))
|
||||||
|
@ -4,8 +4,6 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton
|
|||||||
import com.unciv.logic.map.TileInfo
|
import com.unciv.logic.map.TileInfo
|
||||||
import com.unciv.ui.utils.CameraStageBaseScreen
|
import com.unciv.ui.utils.CameraStageBaseScreen
|
||||||
import com.unciv.ui.utils.addClickListener
|
import com.unciv.ui.utils.addClickListener
|
||||||
import com.unciv.ui.utils.disable
|
|
||||||
import com.unciv.ui.utils.enable
|
|
||||||
import com.unciv.ui.worldscreen.TileMapHolder
|
import com.unciv.ui.worldscreen.TileMapHolder
|
||||||
|
|
||||||
class IdleUnitButton internal constructor(internal val unitTable: UnitTable,
|
class IdleUnitButton internal constructor(internal val unitTable: UnitTable,
|
||||||
@ -32,10 +30,5 @@ class IdleUnitButton internal constructor(internal val unitTable: UnitTable,
|
|||||||
unitTable.worldScreen.update()
|
unitTable.worldScreen.update()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun update() {
|
|
||||||
if (getTilesWithIdleUnits().isNotEmpty()) enable()
|
|
||||||
else disable()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,7 @@ import com.badlogic.gdx.scenes.scene2d.ui.Table
|
|||||||
import com.unciv.logic.map.MapUnit
|
import com.unciv.logic.map.MapUnit
|
||||||
import com.unciv.logic.map.TileInfo
|
import com.unciv.logic.map.TileInfo
|
||||||
import com.unciv.models.gamebasics.unit.UnitType
|
import com.unciv.models.gamebasics.unit.UnitType
|
||||||
import com.unciv.ui.utils.CameraStageBaseScreen
|
import com.unciv.ui.utils.*
|
||||||
import com.unciv.ui.utils.ImageGetter
|
|
||||||
import com.unciv.ui.utils.addClickListener
|
|
||||||
import com.unciv.ui.utils.tr
|
|
||||||
import com.unciv.ui.worldscreen.WorldScreen
|
import com.unciv.ui.worldscreen.WorldScreen
|
||||||
|
|
||||||
class UnitTable(val worldScreen: WorldScreen) : Table(){
|
class UnitTable(val worldScreen: WorldScreen) : Table(){
|
||||||
@ -20,6 +17,10 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
|||||||
var selectedUnit : MapUnit? = null
|
var selectedUnit : MapUnit? = null
|
||||||
var currentlyExecutingAction : String? = null
|
var currentlyExecutingAction : String? = null
|
||||||
|
|
||||||
|
// This is so that not on every update(), we will update the unit table.
|
||||||
|
// Most of the time it's the same unit with the same stats so why waste precious time?
|
||||||
|
var shouldUpdateVisually = false
|
||||||
|
|
||||||
init {
|
init {
|
||||||
pad(5f)
|
pad(5f)
|
||||||
|
|
||||||
@ -33,16 +34,12 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun update() {
|
fun update() {
|
||||||
prevIdleUnitButton.update()
|
|
||||||
nextIdleUnitButton.update()
|
|
||||||
promotionsTable.clear()
|
|
||||||
unitDescriptionLabel.clearListeners()
|
|
||||||
|
|
||||||
if(selectedUnit!=null)
|
if(selectedUnit!=null)
|
||||||
{
|
{
|
||||||
if(selectedUnit!!.civInfo != worldScreen.civInfo) { // The unit that was selected, was captured. It exists but is no longer ours.
|
if(selectedUnit!!.civInfo != worldScreen.civInfo) { // The unit that was selected, was captured. It exists but is no longer ours.
|
||||||
selectedUnit = null
|
selectedUnit = null
|
||||||
currentlyExecutingAction = null
|
currentlyExecutingAction = null
|
||||||
|
shouldUpdateVisually = true
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
try {
|
try {
|
||||||
@ -50,10 +47,25 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
|||||||
} catch (ex: Exception) { // The unit that was there no longer exists}
|
} catch (ex: Exception) { // The unit that was there no longer exists}
|
||||||
selectedUnit = null
|
selectedUnit = null
|
||||||
currentlyExecutingAction = null
|
currentlyExecutingAction = null
|
||||||
|
shouldUpdateVisually=true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!shouldUpdateVisually) return
|
||||||
|
|
||||||
|
if(prevIdleUnitButton.getTilesWithIdleUnits().isNotEmpty()) { // more efficient to do this check once for both
|
||||||
|
prevIdleUnitButton.enable()
|
||||||
|
nextIdleUnitButton.enable()
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
prevIdleUnitButton.disable()
|
||||||
|
nextIdleUnitButton.disable()
|
||||||
|
}
|
||||||
|
|
||||||
|
promotionsTable.clear()
|
||||||
|
unitDescriptionLabel.clearListeners()
|
||||||
|
|
||||||
if(selectedUnit!=null) {
|
if(selectedUnit!=null) {
|
||||||
val unit = selectedUnit!!
|
val unit = selectedUnit!!
|
||||||
var nameLabelText = unit.name
|
var nameLabelText = unit.name
|
||||||
@ -84,9 +96,11 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
pack()
|
pack()
|
||||||
|
shouldUpdateVisually=false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun tileSelected(selectedTile: TileInfo) {
|
fun tileSelected(selectedTile: TileInfo) {
|
||||||
|
val previouslySelectedUnit = selectedUnit
|
||||||
if(currentlyExecutingAction=="moveTo"){
|
if(currentlyExecutingAction=="moveTo"){
|
||||||
if(selectedUnit!!.movementAlgs()
|
if(selectedUnit!!.movementAlgs()
|
||||||
.getShortestPath(selectedTile).isEmpty())
|
.getShortestPath(selectedTile).isEmpty())
|
||||||
@ -100,13 +114,16 @@ class UnitTable(val worldScreen: WorldScreen) : Table(){
|
|||||||
currentlyExecutingAction = null
|
currentlyExecutingAction = null
|
||||||
}
|
}
|
||||||
|
|
||||||
if(selectedTile.militaryUnit!=null && selectedTile.militaryUnit!!.civInfo == worldScreen.civInfo
|
else if(selectedTile.militaryUnit!=null && selectedTile.militaryUnit!!.civInfo == worldScreen.civInfo
|
||||||
&& selectedUnit!=selectedTile.militaryUnit)
|
&& selectedUnit!=selectedTile.militaryUnit)
|
||||||
selectedUnit = selectedTile.militaryUnit
|
selectedUnit = selectedTile.militaryUnit
|
||||||
|
|
||||||
else if (selectedTile.civilianUnit!=null && selectedTile.civilianUnit!!.civInfo == worldScreen.civInfo
|
else if (selectedTile.civilianUnit!=null && selectedTile.civilianUnit!!.civInfo == worldScreen.civInfo
|
||||||
&& selectedUnit!=selectedTile.civilianUnit)
|
&& selectedUnit!=selectedTile.civilianUnit)
|
||||||
selectedUnit = selectedTile.civilianUnit
|
selectedUnit = selectedTile.civilianUnit
|
||||||
|
|
||||||
|
if(selectedUnit != previouslySelectedUnit)
|
||||||
|
shouldUpdateVisually = true
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user