-
Notifications
You must be signed in to change notification settings - Fork 20
Family (old)
In case you need to iterate over entities with a specific component configuration
that is not part of a system then this is possible via the family
function
of a world
.
A family
keeps track of entities with a specific config and allows sorting
and iteration over these entities. Family
is used internally
by an IteratingSystem
. You can access it via the family
property.
The following example shows how to
get a family
for entities with a MoveComponent but without a DeadComponent:
fun main() {
val world = world {}
val e1 = w.entity {
add<MoveComponent> { speed = 70f }
}
val e2 = w.entity {
add<MoveComponent> { speed = 50f }
add<DeadComponent>()
}
val e3 = w.entity {
add<MoveComponent> { speed = 30f }
}
// get family for entities with a MoveComponent
// and without a DeadComponent
val family = world.family(
allOf = arrayOf(MoveComponent::class),
noneOf = arrayOf(DeadComponent::class),
)
// you can sort entities of a family
val moves = world.mapper<MoveComponent>()
family.sort(compareEntity { entity1, entity2 -> moves[entity1].speed.compareTo(moves[entity2].speed) })
// And you can iterate over entities of a family.
// In this example it will iterate in following order:
// 1) e3
// 2) e1
family.forEach { entity ->
// family also supports the configureEntity function
configureEntity(entity) {
// update entity components
}
}
}
Families also support FamilyListener
that allow you to react when an entity
gets added to, or removed from a family
. Such listeners can be created in a similar
way you can create ComponentListener
via the world's configuration, or you can register them manually to any existing family via the addFamilyListener
function of a family
.
Here is an example of a FamilyListener
that gets created via the world. In this case it must define its component configuration like you'd define it for an IteratingSystem
. Also, the normal dependency injection logic applies during this process:
// listener that reacts on entities that have a MoveComponent and do not have a DeadComponent
@AllOf([MoveComponent::class])
@NoneOf([DeadComponent::class])
class MyFamiliyListener : FamilyListener {
override fun onEntityAdded(entity: Entity) {
// ...
}
override fun onEntityRemoved(entity: Entity) {
// ...
}
}
fun main() {
val world = world {
families {
add<MyFamiliyListener>()
}
}
// this will notify the listener via its onEntityAdded function
val entity = world.entity {
add<MoveComponent>()
}
// this will notify the listener via its onEntityRemoved function
world.remove(entity)
// this will NOT notify the listener because the entity is never part of the listener's family
val entity = world.entity {
add<MoveComponent>()
add<DeadComponent>() // <-- that's the reason
}
world.remove(entity)
}
// listener that reacts on entities that have a MoveComponent and do not have a DeadComponent
class MyFamiliyListener : FamilyListener(
allOfComponents = arrayOf(MoveComponent::class),
noneOfComponents = arrayOf(DeadComponent::class)
) {
override fun onEntityAdded(entity: Entity) {
// ...
}
override fun onEntityRemoved(entity: Entity) {
// ...
}
}
fun main() {
val world = world {
components {
add(::MoveComponent)
add(::DeadComponent)
}
families {
add(::MyFamiliyListener)
}
}
// this will notify the listener via its onEntityAdded function
val entity = world.entity {
add<MoveComponent>()
}
// this will notify the listener via its onEntityRemoved function
world.remove(entity)
// this will NOT notify the listener because the entity is never part of the listener's family
val entity = world.entity {
add<MoveComponent>()
add<DeadComponent>() // <-- that's the reason
}
world.remove(entity)
}