Skip to content

Commit

Permalink
Store static data of level in asset store (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
jobe-m authored Oct 22, 2024
1 parent 0e6e9c4 commit 9b5cc05
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import korlibs.image.font.readBitmapFont
import korlibs.image.format.*
import korlibs.image.tiles.*
import korlibs.io.file.std.resourcesVfs
import korlibs.korge.fleks.entity.*
import korlibs.korge.fleks.gameState.GameStateManager.assetStore
import korlibs.korge.fleks.utils.*
import korlibs.korge.ldtk.*
import korlibs.korge.ldtk.view.*
Expand All @@ -22,8 +20,6 @@ import kotlinx.serialization.*
import kotlin.collections.set
import kotlin.math.max

typealias LayerTileMaps = MutableMap<String, TileMapData>
typealias LayerEntityMaps = MutableMap<String, List<EntityConfig>>

/**
* This class is responsible to load all kind of game data and make it usable / consumable by entities of Korge-Fleks.
Expand All @@ -50,15 +46,21 @@ class AssetStore {
internal var currentLevelAssetConfig: AssetModel = AssetModel()
internal var specialAssetConfig: AssetModel = AssetModel()

internal val levelMaps: MutableMap<String, Pair<AssetType, LayerTileMaps>> = mutableMapOf() // 1st string: Level name, 2nd string: Layer name
internal val entityConfigMaps: MutableMap<String, Pair<AssetType, LayerEntityMaps>> = mutableMapOf() // 1st string: Level name, 2nd string: Layer name
internal val levelDataMaps: MutableMap<String, LevelData> = mutableMapOf()
internal var backgrounds: MutableMap<String, Pair<AssetType, ParallaxDataContainer>> = mutableMapOf()
internal var images: MutableMap<String, Pair<AssetType, ImageDataContainer>> = mutableMapOf()
internal var fonts: MutableMap<String, Pair<AssetType, Font>> = mutableMapOf()
internal var sounds: MutableMap<String, Pair<AssetType, SoundChannel>> = mutableMapOf()

// TODO: Create data class for storing level data
// grizSize, entities, tileMapData
// Data class for storing level data like grizSize, width, height, entities, tileMapData
data class LevelData(
val type: AssetType,
val gridSize: Int,
val width: Float,
val height: Float,
val entities: List<String>,
val layerTileMaps: MutableMap<String, TileMapData>
)

fun getSound(name: String) : SoundChannel =
if (sounds.contains(name)) sounds[name]!!.second
Expand All @@ -82,18 +84,24 @@ class AssetStore {
}

fun getTileMapData(level: String, layer: String) : TileMapData =
if (levelMaps.contains(level)) {
if (levelMaps[level]!!.second.contains(layer)) levelMaps[level]!!.second[layer]!!
if (levelDataMaps.contains(level)) {
if (levelDataMaps[level]!!.layerTileMaps.contains(layer)) levelDataMaps[level]!!.layerTileMaps[layer]!!
else error("AssetStore: TileMap layer '$layer' for level '$level' not found!")
}
else error("AssetStore: Level map for level '$level' not found!")

fun getEntityConfigs(level: String, layer: String) : List<EntityConfig> =
if (entityConfigMaps.contains(level)) {
if (entityConfigMaps[level]!!.second.contains(layer)) entityConfigMaps[level]!!.second[layer]!!
else error("AssetStore: Entity layer '$layer' for level '$level' not found!")
fun getEntities(level: String) : List<String> =
if (levelDataMaps.contains(level)) {
levelDataMaps[level]!!.entities
}
else error("AssetStore: EntityConfig for level '$level' not found!")
else error("AssetStore: Entities for level '$level' not found!")

fun getLevelHeight(level: String) : Float =
if (levelDataMaps.contains(level)) {
levelDataMaps[level]!!.height
}
else error("AssetStore: Height for level '$level' not found!")


fun getNinePatch(name: String) : NinePatchBmpSlice =
if (images.contains(name)) {
Expand Down Expand Up @@ -162,14 +170,15 @@ class AssetStore {
ldtkLevel.layerInstances?.forEach { ldtkLayer ->
val layerName = ldtkLayer.identifier
val gridSize = ldtkLayer.gridSize

// Check if layer has tile set -> store tile map data
val tilesetExt = ldtkWorld.tilesetDefsById[ldtkLayer.tilesetDefUid]
if (tilesetExt != null) {
storeTiles(ldtkLayer, tilesetExt, levelName, layerName, type)
}
// Check if layer contains entity data -> create EntityConfigs and store them fo
if (ldtkLayer.entityInstances.isNotEmpty()) {
val entityList = mutableListOf<EntityConfig>()
val entityNames = mutableListOf<String>()

ldtkLayer.entityInstances.forEach { entity ->
// Create YAML string of an entity config from LDtk
Expand Down Expand Up @@ -206,7 +215,7 @@ class AssetStore {
// TODO: We need to store only the name of the entity config for later dynamically spawning of entities
// We need to store the entity configs in a 2D array depending on its position in the level
// Then later we will spawn the entities depending on the position in the level
entityList.add(entityConfig)
entityNames.add(entityConfig.name)

println("INFO: Registering entity config '${entity.identifier}' for '$levelName'")
} catch (e: Throwable) {
Expand All @@ -216,13 +225,19 @@ class AssetStore {
} else println("ERROR: Game object with name '${entity.identifier}' has no field entityConfig!")
}

// Create new map for Entity layer if it does not exist yet
if (!entityConfigMaps.contains(levelName)) {
val layerEntityMaps: LayerEntityMaps = mutableMapOf()
entityConfigMaps[levelName] = Pair(type, layerEntityMaps)
// Create new level data if it does not exist yet
if (!levelDataMaps.contains(levelName)) {
val levelData = LevelData(
type = type,
gridSize = gridSize,
width = (ldtkLayer.cWid * gridSize).toFloat(),
height = (ldtkLayer.cHei * gridSize).toFloat(),
entities = entityNames,
layerTileMaps = mutableMapOf()
)
} else {
levelDataMaps[levelName]!!.entities
}
// Finally store entity config for level and entity layer
entityConfigMaps[levelName]!!.second[layerName] = entityList
}
}
}
Expand Down Expand Up @@ -315,10 +330,22 @@ class AssetStore {
}
}
// Create new map for level layers and store layer in it
val layerTileMaps: LayerTileMaps = mutableMapOf()
val layerTileMaps = mutableMapOf<String, TileMapData>()
layerTileMaps[layer] = tileMapData
// Add layer map to level Maps
levelMaps[level] = Pair(type, layerTileMaps)
if (!levelDataMaps.contains(level)) {
val levelData = LevelData(
type = type,
gridSize = gridSize,
width = (ldtkLayer.cWid * gridSize).toFloat(),
height = (ldtkLayer.cHei * gridSize).toFloat(),
entities = listOf(),
layerTileMaps = layerTileMaps
)
levelDataMaps[level] = levelData
} else {
levelDataMaps[level]!!.layerTileMaps[layer] = tileMapData
}
}

private fun prepareCurrentAssets(type: AssetType, newAssetConfig: AssetModel, currentAssetConfig: AssetModel): AssetModel? =
Expand Down Expand Up @@ -351,6 +378,6 @@ class AssetStore {
images.values.removeAll { it.first == type }
fonts.values.removeAll { it.first == type }
sounds.values.removeAll { it.first == type }
levelMaps.values.removeAll { it.first == type }
levelDataMaps.values.removeAll { it.type == type }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,34 +17,15 @@ data class LdtkLevelMapComponent(
*
* Example: ["Background", "Playfield"]
*/
var layerNames: List<String> = listOf(),

var levelLayer: String = "", // The level and layer name in the LDtk world

// TODO: Move this to AssetStore
var width: Float = 0f, // Size of the level map
var height: Float = 0f,

// internal
var initialized: Boolean = false
var layerNames: List<String> = listOf()
) : CloneableComponent<LdtkLevelMapComponent>() {
override fun type(): ComponentType<LdtkLevelMapComponent> = LdtkLevelMapComponent

// Get size of level map and save it into properties of this component
override fun World.onAdd(entity: Entity) {
// Make sure that initialization is skipped on world snapshot loading (deserialization of save game)
if (initialized) return
else initialized = true

val assetStore: AssetStore = this.inject(name = "AssetStore")
val tileMapData = assetStore.getTileMapData(levelName, layerNames.first())
// TODO: remove hardcoded values - assetStore.getLevelWidth(levelName) : Float
width = (tileMapData.data.width * 16).toFloat()
height = (tileMapData.data.height * 16).toFloat()
}

companion object : ComponentType<LdtkLevelMapComponent>()

// Author's hint: Check if deep copy is needed on any change in the component!
override fun clone(): LdtkLevelMapComponent = this.copy()
override fun clone(): LdtkLevelMapComponent =
LdtkLevelMapComponent(
levelName = levelName,
layerNames = layerNames.clone()
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,16 @@ fun List<Entity>.clone() : List<Entity> {
}
return listCopy
}

/**
* Clone function (deep copy) for [List] of String elements.
*/
@JvmName("ListOfStrings")
fun List<String>.clone() : List<String> {
val listCopy = mutableListOf<String>()
// Perform deep copy of list elements
forEach { string ->
listCopy.add(string)
}
return listCopy
}

0 comments on commit 9b5cc05

Please sign in to comment.