Skip to main content

LevelBoundsBehaviorSystem.ixx File

System for handling entity behavior at level boundaries. More...

Included Headers

#include <cassert> #include <helios.engine.runtime.world.UpdateContext> #include <helios.engine.runtime.spawn.commands.DespawnCommand> #include <helios.engine.ecs.View> #include <helios.engine.modules.scene.components.SceneNodeComponent> #include <helios.engine.modules.spatial.transform.components.RotationStateComponent> #include <helios.engine.modules.rendering.model.components.ModelAabbComponent> #include <helios.engine.mechanics.spawn.components.SpawnedByProfileComponent> #include <helios.engine.modules.physics.collision.components.AabbColliderComponent> #include <helios.engine.ecs.System> #include <helios.math> #include <helios.engine.runtime.messaging.command.CommandBuffer> #include <helios.engine.mechanics.lifecycle.components.Active> #include <helios.engine.modules.physics.collision.types.CollisionBehavior> #include <helios.engine.modules.physics.motion.components.Move2DComponent> #include <helios.engine.modules.physics.motion.components.DirectionComponent> #include <helios.engine.modules.physics.collision.types.CollisionResponse> #include <helios.engine.ecs.GameObject> #include <helios.engine.runtime.world.GameWorld> #include <helios.scene.SceneNode> #include <helios.engine.modules.spatial.transform.components.ComposeTransformComponent> #include <helios.engine.modules.spatial.transform.components.TranslationStateComponent> #include <helios.engine.modules.physics.motion.components.SteeringComponent> #include <helios.engine.mechanics.bounds.components.LevelBoundsBehaviorComponent>

Namespaces Index

namespacehelios
namespaceengine

Main engine module aggregating core infrastructure and game systems. More...

namespacemechanics

High-level gameplay systems and components for game logic. More...

namespacebounds
namespacesystems

Boundary detection and response systems. More...

Classes Index

classLevelBoundsBehaviorSystem

System that handles entity behavior when colliding with level boundaries. More...

structBounceResult

Result of a bounce calculation against level bounds. More...

Description

System for handling entity behavior at level boundaries.

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file LevelBoundsBehaviorSystem.ixx
3 * @brief System for handling entity behavior at level boundaries.
4 */
5module;
6
7#include <cassert>
8
9export module helios.engine.mechanics.bounds.systems.LevelBoundsBehaviorSystem;
10
11
12import helios.engine.ecs.System;
13import helios.math;
14
15import helios.engine.runtime.messaging.command.CommandBuffer;
16
17import helios.engine.modules.physics.collision.types.CollisionBehavior;
18import helios.engine.modules.physics.collision.types.CollisionResponse;
19
20import helios.engine.ecs.GameObject;
21import helios.engine.runtime.world.GameWorld;
22import helios.engine.modules.physics.motion.components.Move2DComponent;
23import helios.engine.modules.physics.motion.components.SteeringComponent;
24import helios.engine.modules.spatial.transform.components.ComposeTransformComponent;
25import helios.engine.modules.spatial.transform.components.TranslationStateComponent;
26import helios.engine.modules.physics.motion.components.DirectionComponent;
27import helios.engine.mechanics.bounds.components.LevelBoundsBehaviorComponent;
28import helios.engine.modules.physics.collision.components.AabbColliderComponent;
29import helios.engine.modules.spatial.transform.components.RotationStateComponent;
30import helios.engine.modules.rendering.model.components.ModelAabbComponent;
31import helios.engine.modules.spatial.transform.components.RotationStateComponent;
32import helios.scene.SceneNode;
33import helios.engine.modules.scene.components.SceneNodeComponent;
34
35import helios.engine.ecs.View;
36
37import helios.engine.runtime.world.UpdateContext;
38
39import helios.engine.runtime.spawn.commands.DespawnCommand;
40
41import helios.engine.mechanics.spawn.components.SpawnedByProfileComponent;
42
43import helios.engine.mechanics.lifecycle.components.Active;
44
45
47
48 /**
49 * @brief System that handles entity behavior when colliding with level boundaries.
50 *
51 * @details
52 * This system checks if entities with movement components have exceeded the level bounds.
53 * When an entity leaves the bounds, it applies bounce behavior based on the
54 * LevelBoundsBehaviorComponent's restitution coefficient.
55 */
57
58 /**
59 * @brief Result of a bounce calculation against level bounds.
60 */
61 struct BounceResult {
62 /** @brief True if the X-axis boundary was hit. */
63 bool hitX;
64 /** @brief True if the Y-axis boundary was hit. */
65 bool hitY;
66 /** @brief The corrected world position. */
67 helios::math::vec3f translation;
68 /** @brief The new velocity after bounce. */
69 helios::math::vec3f velocity;
70 /** @brief The new direction vector. */
71 helios::math::vec3f direction;
72 };
73
74 public:
75
76 /**
77 * @brief Updates all entities that may have left level bounds.
78 *
79 * @details
80 * For each entity with the required components, checks if its world-space
81 * AABB is within level bounds. If not, applies bounce behavior.
82 *
83 * @param updateContext Context containing deltaTime and other frame data.
84 */
85 void update(helios::engine::runtime::world::UpdateContext& updateContext) noexcept override {
86
88
89 for (auto [entity, m2d, ab, sc, dc, tsc, bc, bbc, active] : gameWorld_->view<
98 >().whereEnabled()) {
99
100
101 auto& objectBounds = bc->bounds();
102 auto levelBounds = gameWorld_->level()->bounds();
103
104 if (!levelBounds.contains(objectBounds)) {
105
106 helios::math::mat4f parentWorldTransform = sc->sceneNode()->parent()->worldTransform();
107 helios::math::vec4f childWorldTranslation = parentWorldTransform * tsc->translation().toVec4(1.0f);
108
109 helios::math::vec3f bouncedWorldTranslation;
110
111 BounceResult bounceResult{};
112
113 if (bbc->collisionBehavior() == CollisionBehavior::Reflect || bbc->collisionBehavior() == CollisionBehavior::Bounce) {
114
115 bounceResult = bounce(
116 childWorldTranslation.toVec3(), objectBounds, levelBounds,
117 bbc->collisionBehavior() == CollisionBehavior::Reflect ? 1.0f : bbc->restitution(),
118 *m2d, *dc
119 );
120
121 bouncedWorldTranslation = bounceResult.translation;
122 updateCollisionResponse(entity, bounceResult, bbc->collisionResponse());
123
124 } else if (bbc->collisionBehavior() == CollisionBehavior::Despawn) {
125 /**
126 * @todo optimize
127 */
129 assert(sbp && "Unexpected missing SpawnProfile");
130
131 updateContext.commandBuffer().add<helios::engine::runtime::spawn::commands::DespawnCommand>(
132 entity.entityHandle(), sbp->spawnProfileId()
133 );
134
135 }
136
137
138 if (bounceResult.hitX || bounceResult.hitY) {
139 m2d->setVelocity(bounceResult.velocity);
140 dc->setDirection(bounceResult.direction);
141 }
142
143 auto parentTransform_inverse = parentWorldTransform.inverse();
144 auto childLocalTranslation = parentTransform_inverse * bouncedWorldTranslation.toVec4(1.0f);
145
146 tsc->setTranslation(childLocalTranslation.toVec3());
147 bc->setBounds(ab->aabb().applyTransform(
148 parentWorldTransform.withTranslation(bouncedWorldTranslation)
149 ));
150
151 }
152 }
153 }
154
155 private:
156
157 /**
158 * @brief Updates the entity's state based on the configured collision response.
159 *
160 * @details
161 * If the response is set to AlignHeadingToDirection, this method updates the
162 * SteeringComponent to match the new bounce direction.
163 *
164 * @param go Pointer to the GameObject to update.
165 * @param bounceResult The result data from the bounce calculation.
166 * @param collisionResponse The type of response to apply.
167 */
168 void updateCollisionResponse(
170 BounceResult bounceResult,
172
175
176 const auto direction = bounceResult.direction;
177
178 if (psc) {
179 psc->setSteeringIntent(
180 bounceResult.direction, 1.0f
181 );
182 }
183 }
184 }
185
186 /**
187 * @brief Applies bounce behavior to an entity that has left level bounds.
188 *
189 * @details
190 * Calculates the corrected position and reflected velocity when an entity
191 * collides with level boundaries. The restitution coefficient determines
192 * how much velocity is preserved after the bounce. The DirectionComponent
193 * will be updated with the new direction.
194 *
195 * @param worldTranslation Current world position of the entity.
196 * @param objectBounds World-space AABB of the entity.
197 * @param levelBounds World-space AABB of the level.
198 * @param restitution
199 * @param m2d Reference to the Move2DComponent for velocity modification.
200 * @param dc Reference to the DirectionComponent for direction update.
201 *
202 * @return Corrected world position after bounce.
203 */
204 [[nodiscard]] BounceResult bounce(
205 helios::math::vec3f worldTranslation,
206 helios::math::aabbf objectBounds,
207 helios::math::aabbf levelBounds,
208 const float restitution,
211 ) noexcept {
212
213
214 auto velocity = m2d.velocity();
215 bool hitX = false;
216 bool hitY = false;
217 auto translation = worldTranslation;
218
219 // Check left boundary collision
220 if (objectBounds.min()[0] < levelBounds.min()[0]) {
221 translation[0] += (levelBounds.min()[0] - objectBounds.min()[0]);
222 if (velocity[0] < 0) {
223 velocity = (velocity.withX(restitution * -velocity[0]));
224 }
225 hitX = true;
226 // Check right boundary collision
227 } else if (objectBounds.max()[0] > levelBounds.max()[0]) {
228 translation[0] -= (objectBounds.max()[0] - levelBounds.max()[0]) ;
229 if (velocity[0] > 0) {
230 velocity = (velocity.withX(restitution * -velocity[0]));
231 }
232 hitX = true;
233 }
234
235 objectBounds = objectBounds + (translation - worldTranslation);
236
237 // Check bottom boundary collision
238 if (objectBounds.min()[1] < levelBounds.min()[1]) {
239 translation[1] += (levelBounds.min()[1] - objectBounds.min()[1]);
240 if (velocity[1] < 0) {
241 velocity = velocity.withY(restitution * -velocity[1]);
242 }
243 hitY = true;
244 // Check top boundary collision
245 } else if (objectBounds.max()[1] > levelBounds.max()[1]) {
246 translation[1] -= (objectBounds.max()[1] - levelBounds.max()[1]);
247 if (velocity[1] > 0) {
248 velocity = velocity.withY(restitution * -velocity[1]);
249 }
250 hitY = true;
251 }
252
253
254 return {
255 hitX, hitY, translation, velocity, velocity.normalize()
256 };
257 }
258
259 };
260
261};

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.