Quick Summary
- π‘ Status: planned, ready to start. Depends on
#117 β Rapier cluster physics: minimum integration.
- Add a sibling trait
RapierClusterSimulation (in arcane-infra::rapier_cluster) that takes an extended context with contact events, plus a per-entity collider shape declaration.
- Without these two, Rapier integration is "all entities are uniform spheres with invisible collisions" β fine for tech demo, useless for real games.
- Single PR; tests for each new capability.
Why This Matters
- Contact events make Rapier physics observable to game code β collision damage, item pickup, area triggers, hit detection.
- Per-entity collider shapes make Rapier physics real β capsules for humans, boxes for crates, rather than uniform
0.5-radius spheres.
- Together these are the minimum surface to make Rapier-backed nodes usable for typical action games. Either alone is half-built: contact events without varied shapes give artificial sphere-on-sphere contacts; varied shapes without events leave the game blind to what physics produced.
Scope
- In:
- New trait
RapierClusterSimulation (sibling to ClusterSimulation) with extended context.
RapierClusterTickContext<'a> β ClusterTickContext fields plus contact_events: &[ContactEvent].
- Enum
RapierColliderShape β Ball(f32) | Capsule { half_height, radius } | Cuboid([f32; 3]).
- Method
RapierClusterSimulation::collider_for(&self, entry: &EntityStateEntry) -> RapierColliderShape with default impl returning Ball(config.default_body_radius).
- Constructor
RapierClusterSim::with_rapier_sim(...) accepting the new trait.
- Rapier
ChannelEventCollector wired into step_with_accumulator; contacts mapped from ColliderHandle pairs back to entity_id pairs via the existing handle map.
- Out (each its own follow-up issue):
- Physics commands (impulses, forces, teleports).
- Raycasts.
- Joints.
- Kinematic neighbor proxies (cross-cluster physics visibility).
- World-bounds policy / boundary colliders.
Action Items
Design notes
Why a sibling trait, not extending ClusterSimulation
ClusterSimulation and ClusterTickContext live in arcane-core, which can't depend on Rapier. Extending the existing trait would either pull Rapier into core (no) or make new fields conditional with feature gymnastics that leak into core (no). Sibling trait in arcane-infra::rapier_cluster is clean β the wrapper accepts either trait via separate constructors; users opt in by implementing the richer trait.
Why collider shape is a method, not user_data schema
A method gives full programmatic control (per-entity, per-class, per-state) with zero schema overhead. A schema-driven version remains possible later but isn't needed for this surface.
Why first-sight-only for shape
Same reason as V1's first-sight-only spawn position: changing collider shape mid-life requires destroying and re-creating the body in Rapier. Users who need that go through despawn/respawn β same escape hatch as V1's teleport story.
Industry terms
- Physics tick lifecycle hooks β Unreal
PrePhysicsTick / PostPhysicsTick, Bevy PhysicsSet::*.
- Contact event listener / observer β Box2D
b2ContactListener, PhysX PxSimulationEventCallback. Standard names; we use them.
Reference
- Parent EPIC:
#8 β Cluster physics backends β Unreal (Chaos) first, multi-engine path
- Strategic context:
#33 β Engine-specific node types β heterogeneous physics tiers
- Depends on:
#117 β Rapier cluster physics: minimum integration
- Architecture doc:
docs/architecture/physics-backends-and-unreal.md β Β§6 entity/body mapping, Β§9 testing expectations
Quick Summary
#117β Rapier cluster physics: minimum integration.RapierClusterSimulation(inarcane-infra::rapier_cluster) that takes an extended context with contact events, plus a per-entity collider shape declaration.Why This Matters
0.5-radius spheres.Scope
RapierClusterSimulation(sibling toClusterSimulation) with extended context.RapierClusterTickContext<'a>βClusterTickContextfields pluscontact_events: &[ContactEvent].RapierColliderShapeβBall(f32) | Capsule { half_height, radius } | Cuboid([f32; 3]).RapierClusterSimulation::collider_for(&self, entry: &EntityStateEntry) -> RapierColliderShapewith default impl returningBall(config.default_body_radius).RapierClusterSim::with_rapier_sim(...)accepting the new trait.ChannelEventCollectorwired intostep_with_accumulator; contacts mapped fromColliderHandlepairs back toentity_idpairs via the existing handle map.Action Items
RapierClusterSimulationtrait +RapierClusterTickContextinarcane-infra::rapier_cluster.RapierColliderShapeenum + private conversion toColliderBuilder.collider_fortrait method with default impl.RapierClusterSim::with_rapier_simconstructor; preserve V1newconstructor.(Uuid, Uuid)per tick.started: true.collider_foris honored at first-sight spawn.started/stopped.Design notes
Why a sibling trait, not extending
ClusterSimulationClusterSimulationandClusterTickContextlive inarcane-core, which can't depend on Rapier. Extending the existing trait would either pull Rapier into core (no) or make new fields conditional with feature gymnastics that leak into core (no). Sibling trait inarcane-infra::rapier_clusteris clean β the wrapper accepts either trait via separate constructors; users opt in by implementing the richer trait.Why collider shape is a method, not
user_dataschemaA method gives full programmatic control (per-entity, per-class, per-state) with zero schema overhead. A schema-driven version remains possible later but isn't needed for this surface.
Why first-sight-only for shape
Same reason as V1's first-sight-only spawn position: changing collider shape mid-life requires destroying and re-creating the body in Rapier. Users who need that go through despawn/respawn β same escape hatch as V1's teleport story.
Industry terms
PrePhysicsTick/PostPhysicsTick, BevyPhysicsSet::*.b2ContactListener, PhysXPxSimulationEventCallback. Standard names; we use them.Reference
#8β Cluster physics backends β Unreal (Chaos) first, multi-engine path#33β Engine-specific node types β heterogeneous physics tiers#117β Rapier cluster physics: minimum integrationdocs/architecture/physics-backends-and-unreal.mdβ Β§6 entity/body mapping, Β§9 testing expectations