diff --git a/core/src/main/kotlin/com/last/commit/map/Collectible.kt b/core/src/main/kotlin/com/last/commit/map/Collectible.kt index d81303b..8357cec 100644 --- a/core/src/main/kotlin/com/last/commit/map/Collectible.kt +++ b/core/src/main/kotlin/com/last/commit/map/Collectible.kt @@ -1,23 +1,18 @@ package com.last.commit.map import com.badlogic.gdx.math.Rectangle +import com.badlogic.gdx.math.Vector2 import com.last.commit.audio.GameSoundEffect -import Position import GameState -class Collectible( - name: String, - val pos: Position, - width: Float, - height: Float -) : Interactable { +class Collectible(name: String, val pos: Position, private val size: Vector2) : Interactable { val name: String private val collider: Rectangle init { this.name = name - this.collider = Rectangle(pos.x, pos.y, width, height) + this.collider = Rectangle(pos.x, pos.y, size.x, size.y) } override fun interact(otherCollider: Rectangle, state: GameState) { diff --git a/core/src/main/kotlin/com/last/commit/map/MapState.kt b/core/src/main/kotlin/com/last/commit/map/MapState.kt new file mode 100644 index 0000000..bfbbbd7 --- /dev/null +++ b/core/src/main/kotlin/com/last/commit/map/MapState.kt @@ -0,0 +1,112 @@ +package com.last.commit.map + +import com.last.commit.map.Collectible +import com.last.commit.map.Door +import com.last.commit.Wall +import com.badlogic.gdx.maps.tiled.TiledMap +import com.badlogic.gdx.maps.tiled.TiledMapTileLayer +import com.badlogic.gdx.maps.MapObject +import com.badlogic.gdx.maps.objects.RectangleMapObject +import com.badlogic.gdx.math.Vector2 +import com.badlogic.gdx.math.Rectangle +import kotlin.math.round; + +class MapState(val map: TiledMap) { + private val CELL_SIZE = 64 + + val size: Vector2 + val gridSize: Vector2 + val tileSize: Vector2 + val description: String? + + val collectibles: ArrayList = ArrayList() + val teleporters: ArrayList = ArrayList() + val walls: ArrayList = ArrayList() + val doors: ArrayList = ArrayList() + + init { + val prop = map.properties + val gridWidth = prop.get("width", Int::class.java) + val gridHeight = prop.get("height", Int::class.java) + gridSize = Vector2(gridWidth.toFloat(), gridHeight.toFloat()) + description = prop.get("description", String::class.java) + + val width = gridWidth * CELL_SIZE + val height = gridHeight * CELL_SIZE + size = Vector2(width.toFloat(), height.toFloat()) + + val tileWidth = map.properties.get("tilewidth", Int::class.java) + val tileHeight = map.properties.get("tileheight", Int::class.java) + tileSize = Vector2(tileWidth.toFloat(), tileHeight.toFloat()) + this.loadCollectibles() + this.loadWalls() + for (obj in map.layers["Teleporter"].objects) { + if (obj is RectangleMapObject) { + this.teleporters.add(obj) + println("Teleporter ${obj}") + } + } + if (this.teleporters.isEmpty()) { + println("No Teleporters defined!") + } + } + + private fun loadCollectibles() { + val collectiableLayer = map.layers["Collectibles"] + if (collectiableLayer == null) { + println("Could not load collectibles layer. Check map.") + return + } + + collectiableLayer.objects.mapNotNullTo(collectibles) { createCollectible(it) } + + println("Loaded ${collectibles.size} collectibles") + } + + private fun createCollectible(obj: MapObject): Collectible? { + val x = obj.properties.get("x", Float::class.java) + val y = obj.properties.get("y", Float::class.java) + val coords = Vector2(x, y) + val gridCoords = Vector2(round(x / tileSize.x), round(y / tileSize.y)) + + val width = obj.properties.get("width", Float::class.java) + val height = obj.properties.get("height", Float::class.java) + val size = Vector2(width, height) + + return if (obj is RectangleMapObject) { + val itemName: String? = obj.properties.get("item", String::class.java) + if (itemName != null) { + Collectible(itemName, Position(coords, gridCoords), size) + } else { + null + } + } else { + null + } + } + + private fun loadWalls() { + walls.clear() + doors.clear() + val wallsLayer = map.layers["Walls"] as TiledMapTileLayer + + for (column in 0 until wallsLayer.width) { + for (row in 0 until wallsLayer.height) { + val cell = wallsLayer.getCell(column, row)?: continue + val isDoor: Boolean = cell.getTile().getProperties().get("isDoor", false, Boolean::class.java) + + val wallCollider = Rectangle( + column.toFloat() * wallsLayer.tileWidth, + row.toFloat() * wallsLayer.tileHeight, wallsLayer.tileWidth.toFloat(), + wallsLayer.tileHeight.toFloat() + ) + if (java.lang.Boolean.TRUE == isDoor) { + doors.add(Door(column, row, wallCollider, cell)) + } else { + walls.add(Wall(column, row, wallCollider, cell)) + } + } + } + } + +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/last/commit/map/Position.kt b/core/src/main/kotlin/com/last/commit/map/Position.kt index 7dd5014..864a16a 100644 --- a/core/src/main/kotlin/com/last/commit/map/Position.kt +++ b/core/src/main/kotlin/com/last/commit/map/Position.kt @@ -1,3 +1,5 @@ +package com.last.commit.map + import com.badlogic.gdx.math.Vector2 public data class Position( diff --git a/core/src/main/kotlin/com/last/commit/map/TimeMap.kt b/core/src/main/kotlin/com/last/commit/map/TimeMap.kt index 8dd9435..600df1b 100644 --- a/core/src/main/kotlin/com/last/commit/map/TimeMap.kt +++ b/core/src/main/kotlin/com/last/commit/map/TimeMap.kt @@ -1,7 +1,5 @@ package com.last.commit.map -import GameState -import Position import com.badlogic.gdx.Gdx import com.badlogic.gdx.graphics.OrthographicCamera import com.badlogic.gdx.graphics.g2d.SpriteBatch @@ -12,67 +10,75 @@ import com.badlogic.gdx.maps.tiled.TmxMapLoader import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer import com.badlogic.gdx.math.Rectangle import com.badlogic.gdx.math.Vector2 -import com.badlogic.gdx.scenes.scene2d.ui.Image import com.badlogic.gdx.utils.Array +import com.badlogic.gdx.scenes.scene2d.ui.Image import com.last.commit.Collidable import com.last.commit.Player import com.last.commit.Wall import com.last.commit.audio.GameSoundEffect import com.last.commit.inventory.InventoryItemTextureLoader +import GameState class TimeMap(fileName: String, val state: GameState) { private val CELL_SIZE = 64 val textureLoader = InventoryItemTextureLoader("sprites/genericItems_spritesheet_colored") - private val walls = Array() - private val doors = Array() - private val collectibles = Array() val mapLoader: TmxMapLoader = TmxMapLoader() - lateinit var mapRenderer: OrthogonalTiledMapRenderer - lateinit var map: TiledMap - var gridWidth = 0 - var gridHeight = 0 - var width = 0 - var height = 0 - var mapTileWidth = 0 - var mapTileHeight = 0 - var halfMapTileWidth = 0f - var halfMapTileHeight = 0f - var description: String = "2020" - private set + var mapRenderer: OrthogonalTiledMapRenderer + var mapState: MapState + val mapStates: HashMap = HashMap() + var map: TiledMap + val gridWidth: Int + get() = mapState.gridSize.x.toInt() - init { - loadMap(fileName) - loadDimensions() - loadWalls() - loadCollectibles() - this.textureLoader.parse() - } + val gridHeight: Int + get() = mapState.gridSize.y.toInt() + + val width: Int + get() = mapState.size.x.toInt() + + val height: Int + get() = mapState.size.y.toInt() - private fun loadMap(fileName: String) { - println("Loading map $fileName") + val mapTileWidth: Int + get() = mapState.tileSize.x.toInt() + + val mapTileHeight: Int + get() = mapState.tileSize.y.toInt() + + init { map = mapLoader.load(fileName) + mapState = MapState(map) + mapStates[fileName] = mapState mapRenderer = OrthogonalTiledMapRenderer(map) + this.textureLoader.parse() } + fun teleport(player: Player) { - val teleporters = map.layers["Teleporter"].objects - for (teleporter in teleporters) { - if (teleporter is RectangleMapObject) { - if (teleporter.rectangle.contains(player.getX(), player.getY())) { - state.soundEngine.play(GameSoundEffect.TIME_TRAVEL) - val targetMap = teleporter.properties.get("target", String::class.java) - System.out.println("Teleporting to targetMap $targetMap") - loadMap("tiled/$targetMap") - loadDimensions() - loadWalls() - loadCollectibles() - } - } else { - println("Found illegal teleporter. ${teleporter.properties.get("id")}") - } + val teleporter = mapState.teleporters.find { + it.rectangle.contains(player.getX(), player.getY()) + } + if (teleporter != null) { + state.soundEngine.play(GameSoundEffect.TIME_TRAVEL) + val targetMap = teleporter.properties.get("target", String::class.java) + System.out.println("Teleporting to targetMap $targetMap") + loadMap("tiled/$targetMap") + } + } + + private fun loadMap(name: String) { + val newState = this.mapStates.get(name) + if (newState != null) { + mapState = newState + mapRenderer.map = mapState.map + } else { + val map = mapLoader.load(name) + mapRenderer.map = map + mapState = MapState(map) + mapStates[name] = mapState } } @@ -95,87 +101,13 @@ class TimeMap(fileName: String, val state: GameState) { return Vector2.Zero } - private fun loadDimensions() { - val prop = map.properties - this.gridWidth = prop.get("width", Int::class.java) - this.gridHeight = prop.get("height", Int::class.java) - - if (prop.containsKey("description")) { - this.description = prop.get("description", String::class.java) - } else { - this.description = "Unknown time" - } - this.state.mapDescription = this.description - this.width = gridWidth * CELL_SIZE - this.height = gridHeight * CELL_SIZE - this.mapTileWidth = map.properties.get("tilewidth", Int::class.java) - this.mapTileHeight = map.properties.get("tileheight", Int::class.java) - this.halfMapTileWidth = mapTileWidth / 2f - this.halfMapTileHeight = mapTileHeight / 2f - } - - private fun loadWalls() { - walls.clear() - doors.clear() - val wallsLayer = map.layers["Walls"] as TiledMapTileLayer - - for (column in 0 until wallsLayer.width) { - for (row in 0 until wallsLayer.height) { - val cell: TiledMapTileLayer.Cell? = wallsLayer.getCell(column, row) - if (cell != null) { - val isDoor: Boolean = cell.getTile().getProperties().get("isDoor", false, Boolean::class.java) - val wallCollider = Rectangle( - column.toFloat() * wallsLayer.tileWidth, - row.toFloat() * wallsLayer.tileHeight, wallsLayer.tileWidth.toFloat(), - wallsLayer.tileHeight.toFloat() - ) - if (java.lang.Boolean.TRUE == isDoor) { - doors.add(Door(column, row, wallCollider, cell)) - } else { - walls.add(Wall(column, row, wallCollider, cell)) - } - } - } - } - } - - fun loadCollectibles() { - this.collectibles.clear() - val collectiableLayer = map.layers["Collectibles"] - if (collectiableLayer == null) { - println("Could not load collectibles layer. Check map.") - return - } - val collectibleMapObjects = collectiableLayer.objects - - for (mapObject in collectibleMapObjects) { - val mapObjectProperties = mapObject.properties - val x = mapObjectProperties.get("x", Float::class.java) - val gridX = Math.round(x / mapTileWidth) - val y = mapObjectProperties.get("y", Float::class.java) - val gridY = Math.round(y / mapTileHeight) - val width = mapObjectProperties.get("width", Float::class.java) - val height = mapObjectProperties.get("height", Float::class.java) - - if (mapObject is RectangleMapObject) { - val itemName = mapObjectProperties.get("item", String::class.java) - itemName?. let { - this.collectibles.add(Collectible(itemName, Position(x, y, gridX, gridY), width, height)) - } - } else { - println("Found non-rectangular map object at ${x}-${y} skipping it") - } - } - println("Loaded ${collectibles.size} collectibles") - } - private fun findInteractableAtPosition(gridX: Int, gridY: Int): Interactable? { - for (door in doors) { - if (door.gridX == gridX && door.gridY == gridY && door is Door) { + for (door in mapState.doors) { + if (door.gridX == gridX && door.gridY == gridY) { return door } } - for (collectible in collectibles) { + for (collectible in mapState.collectibles) { if (collectible.pos.gridX == gridX && collectible.pos.gridY == gridY) { return collectible } @@ -207,7 +139,7 @@ class TimeMap(fileName: String, val state: GameState) { fun render(batch: SpriteBatch, camera: OrthographicCamera, delta: Float) { mapRenderer.setView(camera) mapRenderer.render() - this.collectibles.forEach { coll -> + this.mapState.collectibles.forEach { coll -> val image = Image(textureLoader.getTexture(coll.name)) image.x = coll.pos.x + this.getTileWidth() * 0.1f image.y = coll.pos.y + this.getTileHeight() * 0.1f @@ -219,12 +151,12 @@ class TimeMap(fileName: String, val state: GameState) { fun isCollidingWith(collidable: Collidable): Boolean { - for (wall in walls) { + for (wall in mapState.walls) { if (wall.collidesWidth(collidable)) { return true } } - for (door in doors) { + for (door in mapState.doors) { if (door.collidesWidth(collidable)) { return true } @@ -234,9 +166,9 @@ class TimeMap(fileName: String, val state: GameState) { fun getInteractablesAt(absoluteDirection: Vector2): List { val interactables = ArrayList() - val c = collectibles.filter { it.getCollider().contains(absoluteDirection) } + val c = mapState.collectibles.filter { it.getCollider().contains(absoluteDirection) } interactables.addAll(c) - val w = doors.filter { it.getCollider().contains(absoluteDirection) } + val w = mapState.doors.filter { it.getCollider().contains(absoluteDirection) } interactables.addAll(w) return interactables