Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Quillraven committed Mar 26, 2024
2 parents 39259d1 + 4fc4133 commit 298e0ba
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 107 deletions.
4 changes: 2 additions & 2 deletions assets/maps/objects.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
<grid orientation="orthogonal" width="1" height="1"/>
<tile id="0" type="EntityDef">
<properties>
<property name="GameObject" propertytype="GameObject" value="FROG"/>
<property name="entityTags" propertytype="EntityTag" value="PLAYER,CAMERA_FOCUS"/>
<property name="gameObject" propertytype="GameObject" value="FROG"/>
<property name="hasAnimation" type="bool" value="true"/>
<property name="hasState" type="bool" value="true"/>
<property name="jumpHeight" type="float" value="3.2"/>
Expand Down Expand Up @@ -42,10 +42,10 @@
</tile>
<tile id="1" type="EntityDef">
<properties>
<property name="GameObject" propertytype="GameObject" value="SAW"/>
<property name="bodyType" propertytype="BodyType" value="KinematicBody"/>
<property name="damage" type="int" value="1"/>
<property name="entityTags" propertytype="EntityTag" value=""/>
<property name="gameObject" propertytype="GameObject" value="SAW"/>
<property name="hasAnimation" type="bool" value="true"/>
<property name="hasTrack" type="bool" value="true"/>
<property name="speed" type="float" value="3"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ data class Track(
val trackPoints: List<Vector2>,
val closedTrack: Boolean,
var currentIdx: Int = -1,
var direction: Int = 1,
var moveX: Float = 0f,
var moveY: Float = 0f,
var angleRad: Float = 0f,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ class LoadingScreen(
gdxError("No collision shapes defined for tile ${tile.id}")
}

val gameObjectStr = tile.propertyOrNull<String>("GameObject")
?: gdxError("Missing property 'GameObject' on tile ${tile.id}")
val gameObjectStr = tile.propertyOrNull<String>("gameObject")
?: gdxError("Missing property 'gameObject' on tile ${tile.id}")
OBJECT_FIXTURES[GameObject.valueOf(gameObjectStr)] = objectFixtureDefs
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ import com.quillraven.github.quillyjumper.component.Move
import com.quillraven.github.quillyjumper.component.Track
import com.quillraven.github.quillyjumper.system.MoveSystem.Companion.MIN_SPEED
import com.quillraven.github.quillyjumper.system.MoveSystem.Companion.MOVE_INTERPOLATION
import ktx.log.logger

class TrackSystem : IteratingSystem(World.family { all(Move, Track, Graphic) }) {

override fun onTickEntity(entity: Entity) {
val trackCmp = entity[Track]
val (trackVertices, _, currentIdx) = trackCmp
val (trackVertices, closedTrack, currentIdx, direction) = trackCmp
val moveCmp = entity[Move]
val (_, _, max, timer, timeToMax) = moveCmp
val (sprite) = entity[Graphic]
Expand All @@ -30,7 +29,18 @@ class TrackSystem : IteratingSystem(World.family { all(Move, Track, Graphic) })
val currentY = sprite.y + sprite.height * 0.5f
if (currentIdx == -1 || trackVertices[currentIdx].inRange(currentX, currentY, 0.1f)) {
// entity reached current track point -> go to next track point
trackCmp.currentIdx = (currentIdx + 1) % trackVertices.size
trackCmp.currentIdx = currentIdx + direction
if (trackCmp.currentIdx >= trackVertices.size) {
if (closedTrack) {
trackCmp.currentIdx = 0
} else {
trackCmp.direction *= -1
trackCmp.currentIdx = trackVertices.size - 1
}
} else if (!closedTrack && trackCmp.currentIdx < 0) {
trackCmp.direction *= -1
trackCmp.currentIdx = 0
}
val nextTrackPoint = trackVertices[trackCmp.currentIdx]
trackCmp.angleRad = atan2(nextTrackPoint.y - currentY, nextTrackPoint.x - currentX)
}
Expand All @@ -45,8 +55,4 @@ class TrackSystem : IteratingSystem(World.family { all(Move, Track, Graphic) })
private fun Vector2.inRange(otherX: Float, otherY: Float, tolerance: Float): Boolean =
isEqual(x, otherX, tolerance) && isEqual(y, otherY, tolerance)

companion object {
private val log = logger<TrackSystem>()
}

}
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 @@ -78,49 +78,19 @@ 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")
}

// spawn physic body
val tile = mapObject.tile
val bodyType = BodyType.valueOf(tile.property<String>("bodyType", BodyType.DynamicBody.name))
val gameObjectStr = tile.property<String>("GameObject")
val gameObjectStr = tile.property<String>("gameObject")
val gameObject = GameObject.valueOf(gameObjectStr)
val fixtureDefs = OBJECT_FIXTURES[gameObject]
?: gdxError("No fixture definitions for $gameObjectStr")
Expand All @@ -145,63 +115,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 @@ -361,5 +288,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}")
}
12 changes: 6 additions & 6 deletions tiled-project.tiled-project
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,6 @@
"drawFill": true,
"id": 3,
"members": [
{
"name": "GameObject",
"propertyType": "GameObject",
"type": "string",
"value": "FROG"
},
{
"name": "bodyType",
"propertyType": "BodyType",
Expand All @@ -50,6 +44,12 @@
"type": "string",
"value": ""
},
{
"name": "gameObject",
"propertyType": "GameObject",
"type": "string",
"value": "FROG"
},
{
"name": "hasAnimation",
"type": "bool",
Expand Down

0 comments on commit 298e0ba

Please sign in to comment.