Skip to content

Commit

Permalink
refactor entity Tiled configuration (components)
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Klausner committed Mar 25, 2024
1 parent 86abaf1 commit 4fc4133
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 89 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import com.badlogic.gdx.maps.tiled.TiledMap
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer.Cell
import com.badlogic.gdx.maps.tiled.objects.TiledMapTileMapObject
import com.badlogic.gdx.math.Intersector
import com.badlogic.gdx.math.MathUtils
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType
Expand All @@ -26,9 +25,10 @@ import com.quillraven.github.quillyjumper.PhysicWorld
import com.quillraven.github.quillyjumper.Quillyjumper.Companion.OBJECT_FIXTURES
import com.quillraven.github.quillyjumper.Quillyjumper.Companion.UNIT_SCALE
import com.quillraven.github.quillyjumper.TextureAtlasAsset
import com.quillraven.github.quillyjumper.ai.AiEntity
import com.quillraven.github.quillyjumper.ai.GameObjectStateIdle
import com.quillraven.github.quillyjumper.component.*
import com.quillraven.github.quillyjumper.component.AnimationType
import com.quillraven.github.quillyjumper.component.Graphic
import com.quillraven.github.quillyjumper.component.Physic
import com.quillraven.github.quillyjumper.component.Tiled
import com.quillraven.github.quillyjumper.event.GameEvent
import com.quillraven.github.quillyjumper.event.GameEventListener
import com.quillraven.github.quillyjumper.event.MapChangeEvent
Expand Down Expand Up @@ -82,41 +82,11 @@ class TiledService(
}

// 2) spawn dynamic/kinematic game object bodies
map.layer("objects").objects.forEach { spawnGameObjectEntity(map, it) }
val trackLayer = map.layer("tracks")
map.layer("objects").objects.forEach { spawnGameObjectEntity(it, trackLayer) }
}

private fun MapLayer.trackCmpOfBoundary(mapObject: MapObject): Track {
objects.forEach { layerObject ->
val lineVertices = when (layerObject) {
is PolylineMapObject -> GdxFloatArray(layerObject.polyline.transformedVertices)
is PolygonMapObject -> GdxFloatArray(layerObject.polygon.transformedVertices)
else -> gdxError("Only Polyline and Polygon map objects are supported for tracks: $layerObject")
}
val rectVertices = GdxFloatArray(
floatArrayOf(
mapObject.x, mapObject.y,
mapObject.x + mapObject.width, mapObject.y,
mapObject.x + mapObject.width, mapObject.y + mapObject.height,
mapObject.x, mapObject.y + mapObject.height
)
)

if (Intersector.intersectPolygons(lineVertices, rectVertices)) {
// found related track -> convert track vertices to world unit vertices
val trackPoints = mutableListOf<Vector2>()
for (i in 0 until lineVertices.size step 2) {
val vertexX = lineVertices[i] * UNIT_SCALE
val vertexY = lineVertices[i + 1] * UNIT_SCALE
trackPoints += vec2(vertexX, vertexY)
}
return Track(trackPoints, closedTrack = layerObject is PolygonMapObject)
}
}

gdxError("There is no related track for MapObject ${mapObject.id}")
}

private fun spawnGameObjectEntity(map: TiledMap, mapObject: MapObject) {
private fun spawnGameObjectEntity(mapObject: MapObject, trackLayer: MapLayer) {
if (mapObject !is TiledMapTileMapObject) {
gdxError("Unsupported mapObject $mapObject")
}
Expand Down Expand Up @@ -149,63 +119,20 @@ class TiledService(
// Since the AnimationSystem is updating the region of the sprite and is also
// restoring the flip information, we should set the Sprite region already at this point.
it += Graphic(sprite(gameObject, AnimationType.IDLE.atlasKey, body.position))

// EntityTags
val tagsStr = tile.property<String>("entityTags", "")
if (tagsStr.isNotBlank()) {
val tags = tagsStr.split(",").map(EntityTag::valueOf)
it += tags
}
// Animation
val hasAnimation = tile.property<Boolean>("hasAnimation", false)
if (hasAnimation) {
it += Animation(gdxAnimation(world, gameObject, AnimationType.IDLE))
}
// State
val hasState = tile.property<Boolean>("hasState", false)
if (hasState) {
it += State(AiEntity(it, world), GameObjectStateIdle)
}
// Jump
val jumpHeight = tile.property<Float>("jumpHeight", 0f)
if (jumpHeight > 0f) {
it += Jump(maxHeight = jumpHeight)
}
// Life
val life = tile.property<Int>("life", 0)
if (life > 0) {
it += Life(max = life)
}
// Move
val speed = tile.property<Float>("speed", 0f)
if (speed > 0f) {
val timeToMaxSpeed = tile.property<Float>("timeToMaxSpeed", 0f)
it += Move(max = speed, timeToMax = timeToMaxSpeed.coerceAtLeast(0.1f))
}
// Damage
val damage = tile.property<Int>("damage", 0)
if (damage > 0) {
it += Damage(damage)
}
// Track
val hasTrack = mapObject.propertyOrNull<Boolean>("hasTrack") ?: tile.property<Boolean>("hasTrack", false)
if (hasTrack) {
val trackCmp = map.layer("tracks").trackCmpOfBoundary(mapObject)
it += trackCmp
}
configureEntityTags(it, tile)
configureAnimation(it, tile, world, gameObject)
configureState(it, tile, world)
configureJump(it, tile)
configureLife(it, tile)
configureMove(it, tile)
configureDamage(it, tile)
configureTrack(it, mapObject, trackLayer)

log.debug {
"""Spawning entity with:
| MapObjectId: ${mapObject.id}
| TileId: ${tile.id}
| GameObject: $gameObject
| Tags: $tagsStr
| hasAnimation: $hasAnimation
| hasState: $hasState
| Jump: $jumpHeight
| Life: $life
| Move: $speed
| Damage: $damage
""".trimMargin().replace(Regex("(\n*)\n"), "$1")
}
}
Expand Down Expand Up @@ -365,5 +292,4 @@ class TiledService(
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package com.quillraven.github.quillyjumper.tiled

import com.badlogic.gdx.maps.MapLayer
import com.badlogic.gdx.maps.MapObject
import com.badlogic.gdx.maps.objects.PolygonMapObject
import com.badlogic.gdx.maps.objects.PolylineMapObject
import com.badlogic.gdx.maps.tiled.TiledMapTile
import com.badlogic.gdx.maps.tiled.objects.TiledMapTileMapObject
import com.badlogic.gdx.math.Intersector
import com.badlogic.gdx.math.Vector2
import com.github.quillraven.fleks.Entity
import com.github.quillraven.fleks.EntityCreateContext
import com.github.quillraven.fleks.World
import com.quillraven.github.quillyjumper.GameObject
import com.quillraven.github.quillyjumper.Quillyjumper.Companion.UNIT_SCALE
import com.quillraven.github.quillyjumper.ai.AiEntity
import com.quillraven.github.quillyjumper.ai.GameObjectStateIdle
import com.quillraven.github.quillyjumper.component.*
import ktx.app.gdxError
import ktx.math.vec2
import ktx.tiled.*

fun EntityCreateContext.configureEntityTags(entity: Entity, tile: TiledMapTile) {
val tagsStr = tile.property<String>("entityTags", "")
if (tagsStr.isNotBlank()) {
val tags = tagsStr.split(",").map(EntityTag::valueOf)
entity += tags
}
}

fun EntityCreateContext.configureAnimation(entity: Entity, tile: TiledMapTile, world: World, gameObject: GameObject) {
val hasAnimation = tile.property<Boolean>("hasAnimation", false)
if (hasAnimation) {
entity += Animation(gdxAnimation(world, gameObject, AnimationType.IDLE))
}
}

fun EntityCreateContext.configureState(entity: Entity, tile: TiledMapTile, world: World) {
val hasState = tile.property<Boolean>("hasState", false)
if (hasState) {
entity += State(AiEntity(entity, world), GameObjectStateIdle)
}
}

fun EntityCreateContext.configureJump(entity: Entity, tile: TiledMapTile) {
val jumpHeight = tile.property<Float>("jumpHeight", 0f)
if (jumpHeight > 0f) {
entity += Jump(maxHeight = jumpHeight)
}
}

fun EntityCreateContext.configureLife(entity: Entity, tile: TiledMapTile) {
val life = tile.property<Int>("life", 0)
if (life > 0) {
entity += Life(max = life)
}
}

fun EntityCreateContext.configureMove(entity: Entity, tile: TiledMapTile) {
val speed = tile.property<Float>("speed", 0f)
if (speed > 0f) {
val timeToMaxSpeed = tile.property<Float>("timeToMaxSpeed", 0f)
entity += Move(max = speed, timeToMax = timeToMaxSpeed.coerceAtLeast(0.1f))
}
}

fun EntityCreateContext.configureDamage(entity: Entity, tile: TiledMapTile) {
val damage = tile.property<Int>("damage", 0)
if (damage > 0) {
entity += Damage(damage)
}
}

fun EntityCreateContext.configureTrack(entity: Entity, mapObject: TiledMapTileMapObject, trackLayer: MapLayer) {
val hasTrack = mapObject.propertyOrNull<Boolean>("hasTrack") ?: mapObject.tile.property<Boolean>("hasTrack", false)
if (hasTrack) {
entity += trackLayer.trackCmpOf(mapObject)
}
}

private fun MapLayer.trackCmpOf(mapObject: MapObject): Track {
objects.forEach { layerObject ->
val lineVertices = when (layerObject) {
is PolylineMapObject -> GdxFloatArray(layerObject.polyline.transformedVertices)
is PolygonMapObject -> GdxFloatArray(layerObject.polygon.transformedVertices)
else -> gdxError("Only Polyline and Polygon map objects are supported for tracks: $layerObject")
}
val rectVertices = GdxFloatArray(
floatArrayOf(
mapObject.x, mapObject.y,
mapObject.x + mapObject.width, mapObject.y,
mapObject.x + mapObject.width, mapObject.y + mapObject.height,
mapObject.x, mapObject.y + mapObject.height
)
)

if (Intersector.intersectPolygons(lineVertices, rectVertices)) {
// found related track -> convert track vertices to world unit vertices
val trackPoints = mutableListOf<Vector2>()
for (i in 0 until lineVertices.size step 2) {
val vertexX = lineVertices[i] * UNIT_SCALE
val vertexY = lineVertices[i + 1] * UNIT_SCALE
trackPoints += vec2(vertexX, vertexY)
}
return Track(trackPoints, closedTrack = layerObject is PolygonMapObject)
}
}

gdxError("There is no related track for MapObject ${mapObject.id}")
}

0 comments on commit 4fc4133

Please sign in to comment.