Family (old) - Quillraven/Fleks GitHub Wiki

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:

JVM snippet

// 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)
}

KMP snippet

// 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)
}
⚠️ **GitHub.com Fallback** ⚠️