Skip to content
This repository was archived by the owner on Jul 29, 2026. It is now read-only.
This repository was archived by the owner on Jul 29, 2026. It is now read-only.

refactor!: decouple ChaseComponent from EntityHandle via BeaconComponent #255

Description

@ThorstenSuckow

Summary

ChaseComponent currently stores a direct EntityHandle to its chase target. This creates a tight coupling between the chasing entity and a specific entity instance. Instead, ChaseComponent should depend on a new BeaconComponent — a tag/marker component attached to the entity that should be chased. The ChaseSystem would then query for the beacon rather than resolving a stored handle.

Current Design

ChaseComponent holds a direct EntityHandle to the target:

class ChaseComponent {
    EntityHandle target_{};   // ← direct coupling to a specific entity
public:
    void setTarget(const EntityHandle& entityHandle) noexcept;
    EntityHandle target() const noexcept;
};

ChaseSystem resolves this handle every frame:

const auto entityHandle = cc->target();
auto go = updateContext.find(entityHandle);

The builder DSL also wires the target via EntityHandle:

.withAi([&](auto& aib) {
    aib.chasing()
       .target(shipGameObject.entityHandle())  // ← EntityHandle passed at config time
       .seekInterval(0.05f);
})

Problems

  1. Tight coupling: The chasing entity must know the exact EntityHandle of its target at configuration time.
  2. Fragile on respawn: If the player entity is destroyed and re-created (e.g., from a pool), the stored handle becomes stale. Every chasing entity would need to be updated.
  3. Inflexible: Cannot easily switch chase targets at runtime or have multiple entities act as beacons.

Proposed Design

1. Introduce BeaconComponent

A lightweight marker component attached to the entity that should be chased:

// helios/engine/modules/ai/components/BeaconComponent.ixx
class BeaconComponent {
    // Tag component — no data needed initially.
    // Could later carry a beacon type/channel ID for selective chasing.
};

2. Modify ChaseComponent

Remove the EntityHandle target_ field. The chase target is no longer stored; it is discovered at runtime via BeaconComponent:

class ChaseComponent {
    float cooldown_ = 0.0f;
    float cooldownTimer_ = 0.0f;
    bool isEnabled_ = true;
    // EntityHandle target_ removed
};

3. Modify ChaseSystem

Query for the beacon entity via View instead of resolving a stored handle:

void update(UpdateContext& ctx) noexcept {
    // Find beacon entity (e.g., the player)
    auto beaconView = ctx.view<BeaconComponent, TranslationStateComponent, Active>().whereEnabled();
    // ...use beacon position for all chasing entities
}

4. Update Builder DSL

Replace .target(entityHandle) with beacon attachment on the target entity:

// On the player (target):
playerPrefab.add<BeaconComponent>();

// On enemies (chasers) — no target handle needed:
.withAi([](auto& aib) {
    aib.chasing()
       .seekInterval(0.05f);
})

Affected Files

New

File Description
include/helios/engine/modules/ai/components/BeaconComponent.ixx New beacon marker component

Modified

File Change
include/helios/engine/modules/ai/components/ChaseComponent.ixx Remove EntityHandle target_, setTarget(), target()
include/helios/engine/modules/ai/systems/ChaseSystem.ixx Query BeaconComponent via View instead of resolving stored handle
include/helios/engine/modules/ai/components/_module.ixx Export new BeaconComponent
include/helios/engine/modules/ai/registry.ixx Register BeaconComponent with ComponentReflector
include/helios/engine/builder/gameObject/builders/configs/ChaseConfig.ixx Remove .target(EntityHandle) method
include/helios/engine/builder/gameObject/builders/AiBuilder.ixx Update builder API
examples/collision_detection/main.cpp Replace .target(handle) with BeaconComponent on player

Documentation

File Change
include/helios/engine/modules/ai/README.md Update API examples
include/helios/engine/modules/ai/components/README.md Document BeaconComponent, remove setTarget() reference
CHANGELOG.md Breaking change entry

Breaking Change

This removes ChaseComponent::setTarget() / ChaseComponent::target() and the .target(EntityHandle) builder method. Mark as breaking in CHANGELOG.

Checklist

  • Create BeaconComponent
  • Register in ai/registry.ixx
  • Export in ai/components/_module.ixx
  • Remove EntityHandle target_ from ChaseComponent
  • Update ChaseSystem to query BeaconComponent
  • Update ChaseConfig builder (remove .target())
  • Update collision_detection example
  • Update READMEs
  • Add CHANGELOG entry (breaking)
  • Build passes (Debug + Release)
  • Tests pass

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions