Skip to content
Adrian Papari edited this page Aug 16, 2016 · 30 revisions

About

An optional system tracking relationships between entities. Components with fields referencing other entities are automatically registered and tracked; per-field listeners can supplement the system with additional logic.

For release builds, it is recommended to build the project with the artemis-odb-plugin (maven) configured, as it optimizes away the reflection-based overhead from reading and writing to entity fields.

Uses/Examples

  • Delete component when referenced entity dies
  • Change state of old/new entity when referenced entity changes
  • Perform clean-up on child entities when link with parent entity expires

Usage

Register EntityLinkManager.class with the World/WorldConfiguration. The EntityLinkManager only exposes two methods:

    /**
     * <p>Injects and associates the listener with the component. This method
     * is only recommended if only a single field references entities, or if all entity
     * fields are of the same type.</p>
     *
     * <p>Each <code>ComponentType::Field</code> pair can only have one {@link LinkListener}</p>
     *
     * @param component component type associated with listener
     * @param listener link listener
     */
    public void register(Class<? extends Component> component, LinkListener listener)

    /**
     * <p>Injects and associates the listener with a specific field for a given
     * component type.</p>
     *
     * <p>Each <code>ComponentType::Field</code> pair can only have one {@link LinkListener}</p>
     *
     * @param component component type associated with listener
     * @param field target field for listener
     * @param listener link listener
     */
    public void register(Class<? extends Component> component, String field, LinkListener listener)

Example: remove component when target dies

Consider our component:

@PooledWeaver
public class InheritScale extends Component {
    @EntityId public int target = -1;
}

Bind an entity to another, using the component.

world.edit(entityId).create(InheritScale.class).target = targetId;

Per default, if the targetId is killed, the targetId value above will be set to -1, alternatively null - if the field is of type Entity. Oftentimes, if the component's only data is a reference to another entity, we probably want to remove it from the entity completely. This can be achieved with a simple LinkListener:

// retrieving the manager
EntityLinkManager elm = world.getSystem(EntityLinkManager.class);
// register the LinkAdapter - LinkAdapter provides stubs for the LinkListener
elm.register(InheritScale.class, new LinkAdapter() {
    // LinkListeners are subject to dependency injection upon registration
    private ComponentMapper<InheritScale> mapper;

    @Override
    public void onTargetDead(int sourceId, int deadTargetId) {
        // target is dead - better remove the component
        mapper.remove(sourceId);
    }
});

world.delete(targetId); // targetId from snippet above
world.process(); // fires onTargetDead

Default link behavior and Tuning with @LinkPolicy

default policy note
@EntityId int CHECK_SOURCE_AND_TARGETS
Entity CHECK_SOURCE_AND_TARGETS
@EntityId IntBag CHECK_SOURCE Even with CHECK_SOURCE_AND_TARGETS, never calls #onTargetChanged
Bag<Entity> CHECK_SOURCE Even with, CHECK_SOURCE_AND_TARGETS, never calls #onTargetChanged

Skip link creation for a specific field

public class Affix extends Component {
    @EntityId @LinkPolicy(SKIP)
    public int target;

    public Vector2 anchor = new Vector2();
}

Assert entity references in containers are alive

public class ChildRenderable extends PooledComponent {
    @EntityId @LinkPolicy(CHECK_SOURCE_AND_TARGETS)
    public IntBag children = new IntBag();

    @Override
    protected void reset() {
        children.setSize(0);
    }
}
Clone this wiki locally