Skip to content

Files

Latest commit

dc3b14b · Jan 31, 2025

History

History

artemis

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Jan 31, 2025
Dec 2, 2022
Dec 2, 2022
Dec 2, 2022

Artemis-odb Maven Central

KTX: Artemis-odb ECS utilities

Utilities and type-safe builders for the Artemis-odb entity-component-system.

Why?

Artemis-odb does not target Kotlin out of the box. Kotlin can provide a highly readable DSL via inlined methods with 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.

Guide

ktx-artemis provides the following extensions and utilities:

  • ArchetypeBuilder.add adds components to an ArchetypeBuilder.
  • ArchetypeBuilder.remove removes component from an ArchetypeBuilder.
  • Aspect.Builder has extension functions to use KClass instances: oneOf, allOf, exclude.
  • oneOf, allOf, exclude are also available as standalone Aspect builder functions.
  • EntityEdit.plusAssign adds components to an entity with a += operator function.
  • EntityEdit.with adds or replaces a component of an entity.
  • EntityEdit.remove removes a component from the entity.
  • EntityTransmuterFactory.add adds a component to an EntityTransmuterFactory.
  • EntityTransmuterFactory.remove removes a component from an EntityTransmuterFactory.
  • ComponentMapper.contains checks if an entity has a component with the in operator function.
  • World.edit edits an entity by its id with a type-safe builder DSL.
  • World.entity creates and adds an entity to the world with a type-safe builder DSL.
  • World.get retrieves a system from the world with get ([] operator).
  • World.getSystem retrieves a system from the world with a type-safe builder DSL.
  • World.mapperFor retrieves a ComponentMapper instance.

Usage examples

Creating a new Entity:

import com.artemis.Component
import com.artemis.World
import ktx.artemis.entity

val world = World()

class Texture : Component()
class Transform(var x: Float = 0f, var y: Float = 0f) : Component()

val entity = world.entity {
    with<Texture>()
    with<Transform> {
        x = 1f
        y = 1f
    }
}

Adding new components to an existing entity with World.edit:

import com.artemis.Component
import com.artemis.World
import ktx.artemis.edit
import ktx.artemis.entity
import ktx.artemis.with

val world = World()

class Transform(var x: Float = 0f, var y: Float = 0f) : Component()

val entityId = world.entity()

fun editWorld() {
  world.edit(entityId) {
    with<Transform> {
      x = 1f
      y = 1f
    }
  }
}

Getting a BaseSystem from the World:

import com.artemis.*
import ktx.artemis.*

class MoveSystem : BaseSystem() {
  override fun processSystem() = Unit
}
class RenderSystem : BaseSystem() {
  override fun processSystem() = Unit
}

val world = World(
  WorldConfigurationBuilder()
    .with(MoveSystem(), RenderSystem())
    .build()
)

fun getSystem() {
  // Non-nullable variant - throws an exception if the system is missing:
  val moveSystem = world.getSystem<MoveSystem>()
  // Nullable variant - returns null if the system is missing:
  val renderSystem = world[RenderSystem::class]
}

Creating a ComponentMapper:

import com.artemis.Component
import com.artemis.World
import ktx.artemis.mapperFor

class Transform : Component()

val world = World()
val transformMapper = world.mapperFor<Transform>()

Adding a Component to an existing Entity:

import com.artemis.Component
import com.artemis.World
import ktx.artemis.*

class Transform(var x: Float = 0f, var y: Float = 0f) : Component()

fun addComponentToEntity(entityId: Int, world: World) {
  // Creating and adding a component:
  val entityEdit = world.edit(entityId) {
    with<Transform> {
      x = 2.5f
      y = 5f
    }
  }

  // Or you can add a component with the += operator:
  entityEdit += Transform(x = 1f, y = 2f)
}

Removing a Component from an Entity:

import com.artemis.Component
import com.artemis.World
import ktx.artemis.*

class Transform : Component()

val world = World()
val entityId = world.entity {
  with<Transform>()
}

fun removeTransform() {
  world.edit(entityId).remove<Transform>()
}

Getting a Component from an Entity with a ComponentMapper:

import com.artemis.Component
import com.artemis.World
import ktx.artemis.*

class Transform : Component()

val world = World()
val transformMapper = world.mapperFor<Transform>()
val entityId = world.entity {
  with<Transform>()
}
val transformComponent: Transform = transformMapper[entityId]

Checking if an Entity has a Component with a mapper:

import com.artemis.Component
import com.artemis.World
import ktx.artemis.*

class Transform : Component()

val world = World()
val transformMapper = world.mapperFor<Transform>()
val entityId = world.entity {
  with<Transform>()
}
val hasTransform: Boolean = entityId in transformMapper

Creating a component Aspect that matches all entities with the selected Component types with an exclusion:

import com.artemis.*
import com.artemis.systems.IteratingSystem
import ktx.artemis.*

class Texture : Component()
class Transform : Component()
class RigidBody : Component()

val world = World()
val aspectBuilder = allOf(Texture::class, Transform::class).exclude(RigidBody::class)

// The AspectBuilder can be added to a system for example
class ExampleIteratingSystem : IteratingSystem(aspectBuilder) {
  override fun process(entityId: Int) = Unit
}

Adding and removing components from an Archetype:

import com.artemis.ArchetypeBuilder
import com.artemis.Component
import ktx.artemis.*

class Texture : Component()
class Transform : Component()
class RigidBody : Component()

fun createArchetype() {
  val archetypeBuilder = ArchetypeBuilder()
    .add(Transform::class, Texture::class)

  // You can also add components one by one with generic type:
  archetypeBuilder.add<RigidBody>()

  // You can just as easily remove components:
  archetypeBuilder.remove<RigidBody>()
}

Adding and removing a component from an EntityTransmuterFactory:

import com.artemis.Component
import com.artemis.EntityTransmuterFactory
import com.artemis.World
import ktx.artemis.*

val world = World()

class Texture : Component()
class Transform : Component()

val transmuterFactory = EntityTransmuterFactory(world)
  .add<Transform>()
  .remove<Texture>()

Alternatives

  • Fleks is a high performance Kotlin ECS library. Written with a Kotlin DSL from day one, it does not require similar utilities to the Java ECS frameworks.
  • Ashley is a Java ECS library maintained the libGDX organization. KTX provides utilities for Ashley via the ktx-ashley module.

Additional documentation