Utilities and type-safe builders for the Ashley entity component system.
Since Ashley contains many generic methods consuming Class
instances, Kotlin can
provide a pleasant DSL via inlined methods reified generic types. Additionally, creating Entities
and their respective
Components
can result in a lot of declarative-style code which is greatly improved by an easily readable type-safe
builder DSL.
ktx-ashley
provides the following extensions and utilities:
Engine.add
andEngine.entity
extension methods provide type-safe building DSL for creatingEntities
.Engine.getSystem
andEngine.get
([]
operator) ease access to registeredEntitySystem
instances of the engine.Engine.getSystem
throws aMissingEntitySystemException
in case the system is not part of theEngine
.Engine.get
returnsnull
in such cases.EngineEntity
is anEntity
wrapper that allows to createComponent
instances using using theEngine
viawith
method. It is available when callingEngine.entity
orEngine.configureEntity
.Engine.configureEntity
extension method allows to add components to an existing entity.mapperFor
factory method allows to createComponentMapper
instances.- Accessors for
Entity
objects usingComponentMappers
:get
([]
operator),has
,hasNot
,contains
(in
operator),remove
. Entity.addComponent
extension method allows to create and add a singleComponent
to an existingEntity
.Entity.plusAssign
(+=
) operator allows to add aComponent
to an existingEntity
.- Top-level and
Builder
extension DSL methods for constructingFamily
builders withKClass
instances:oneOf
,allOf
,exclude
.
Creating a new pooled Entity
:
import com.badlogic.ashley.core.Component
import com.badlogic.ashley.core.PooledEngine
import ktx.ashley.*
val engine = PooledEngine()
class Texture: Component
class Transform(var x: Float = 0f, var y: Float = 0f) : Component
val entity = engine.entity {
with<Texture>()
with<Transform> {
x = 1f
y = 1f
}
}
Creating multiple new entities:
import com.badlogic.ashley.core.Component
import com.badlogic.ashley.core.PooledEngine
import ktx.ashley.*
val engine = PooledEngine()
class Transform(var x: Float = 0f, var y: Float = 0f) : Component
fun setupEngine() = engine.add {
entity {
with<Transform> {
x = 1f
y = 1f
}
}
entity {
with<Transform> {
x = 2f
y = 2f
}
}
}
Adding new components to an existing entity with Engine.configureEntity
:
import com.badlogic.ashley.core.Component
import com.badlogic.ashley.core.Entity
import com.badlogic.ashley.core.PooledEngine
import ktx.ashley.*
val engine = PooledEngine()
val entity = Entity()
class Transform(var x: Float = 0f, var y: Float = 0f) : Component
fun extendEntity(){
engine.configureEntity(entity) {
with<Transform> {
x = 1f
y = 1f
}
}
}
Getting an EntitySystem
from an Engine
:
import com.badlogic.ashley.core.EntitySystem
import com.badlogic.ashley.core.PooledEngine
import ktx.ashley.get
import ktx.ashley.getSystem
class MoveSystem : EntitySystem()
class RenderSystem : EntitySystem()
val engine = PooledEngine()
fun getSystem() {
engine.addSystem(MoveSystem())
engine.addSystem(RenderSystem())
// Non-nullable variant - throws an exception if the system is missing:
val moveSystem = engine.getSystem<MoveSystem>()
// Nullable variant - returns null if the system is missing:
val renderSystem = engine[RenderSystem::class]
}
Creating a ComponentMapper
:
import com.badlogic.ashley.core.Component
import ktx.ashley.mapperFor
class Transform: Component
val transformMapper = mapperFor<Transform>()
Adding a Component
to an existing Entity
:
import com.badlogic.ashley.core.Component
import com.badlogic.ashley.core.Engine
import com.badlogic.ashley.core.Entity
import ktx.ashley.addComponent
import ktx.ashley.plusAssign
class Transform(var x: Float = 0f, var y: Float = 0f) : Component
fun addComponentToEntity(entity: Entity, engine: Engine) {
// Creating and adding a component:
entity.addComponent<Transform>(engine) {
x = 2.5f
y = 5f
}
// Or alternatively, if you already have a constructed component:
entity += Transform(x = 1f, y = 2f)
}
Getting a Component
from an Entity
:
import com.badlogic.ashley.core.Component
import com.badlogic.ashley.core.PooledEngine
import ktx.ashley.*
class Transform: Component
val engine = PooledEngine()
val transform = mapperFor<Transform>()
val entity = engine.entity {
with<Transform>()
}
val component: Transform = entity[transform]
Checking if an Entity
has a Component
:
import com.badlogic.ashley.core.Component
import com.badlogic.ashley.core.PooledEngine
import ktx.ashley.*
class Transform: Component
val engine = PooledEngine()
val transform = mapperFor<Transform>()
val entity = engine.entity {
with<Transform>()
}
val hasTransform: Boolean = entity.has(transform)
// Or alternatively:
val containsTransform: Boolean = transform in entity
Removing a Component
from an Entity
:
import com.badlogic.ashley.core.Component
import com.badlogic.ashley.core.PooledEngine
import ktx.ashley.*
class Transform: Component
val engine = PooledEngine()
val entity = engine.entity {
with<Transform>()
}
fun removeTransform() {
entity.remove<Transform>()
}
Creating a component Family
that matches all entities with the selected Component
types with an exclusion:
import com.badlogic.ashley.core.Component
import ktx.ashley.*
class Texture: Component
class Transform: Component
class RigidBody: Component
var family = allOf(Texture::class, Transform::class).exclude(RigidBody::class)