Skip to main content

SteeringSystem.ixx File

System for updating entity heading and rotation. More...

Included Headers

Namespaces Index

namespacehelios
namespaceengine

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

namespacemodules

Domain-specific components and systems. More...

namespacephysics

Physics simulation and collision detection subsystem for the game engine. More...

namespacemotion

Motion physics components and systems. More...

namespacesystems

Classes Index

classSteeringSystem

System that processes heading and rotation physics. More...

Description

System for updating entity heading and rotation.

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file SteeringSystem.ixx
3 * @brief System for updating entity heading and rotation.
4 */
5module;
6
7
8#include <algorithm>
9#include <cassert>
10#include <cmath>
11
12export module helios.engine.modules.physics.motion.systems.SteeringSystem;
13
14
15
16import helios.math;
17
18import helios.engine.runtime.world.GameWorld;
19import helios.engine.modules.physics.motion.components.SteeringComponent;
20import helios.engine.modules.spatial.transform.components.ComposeTransformComponent;
21import helios.engine.modules.physics.motion.components.DirectionComponent;
22import helios.engine.modules.spatial.transform.components.RotationStateComponent;
23
24import helios.engine.runtime.world.UpdateContext;
25
26import helios.engine.mechanics.lifecycle.components.Active;
27
28import helios.engine.common.tags.SystemRole;
29
31
32 /**
33 * @brief System that processes heading and rotation physics.
34 *
35 * @details
36 * This system updates the rotation state of entities based on their SteeringComponent.
37 * It calculates the target rotation from input, applies rotation speed and dampening,
38 * and updates the RotationStateComponent and DirectionComponent.
39 */
41
42 private:
43
44 /**
45 * @brief Performs the rotation physics update for a SteeringComponent.
46 *
47 * @details Applies dampening when input is inactive, calculates rotation steps,
48 * and snaps to target when within threshold.
49 *
50 * @param cmp The SteeringComponent to update. Must not be nullptr.
51 * @param deltaTime Time elapsed since last frame in seconds.
52 */
53 void updateHeading(
55 float deltaTime
56 ) noexcept {
57
58 assert(cmp != nullptr && "Unexpected invalid SteeringComponent passed");
59 assert(deltaTime >= 0 && "Unexpected negative value for deltaTime");
60
61 if (deltaTime == 0) {
62 return;
63 }
64
65 float currentRotationSpeed = cmp->currentRotationSpeed();
66 float currentRotationAngle = cmp->currentRotationAngle();
67 float rotationAngleDelta = cmp->rotationAngleDelta();
68 bool headingStateChanged = cmp->stateChanged();
69
70 // Apply rotation dampening when input is inactive
71 if (!headingStateChanged) {
72 currentRotationSpeed *= std::pow(cmp->rotationDampening(), deltaTime);
73
74 if (currentRotationSpeed < cmp->rotationSpeedThreshold()) {
75 currentRotationSpeed = 0.0f;
76 }
77
78 cmp->setCurrentRotationSpeed(currentRotationSpeed);
79 }
80
81 // Apply rotation step towards target angle
82 if (currentRotationSpeed > 0.0f) {
83
84 if (cmp->useInstantRotation()) {
85 currentRotationAngle = cmp->targetRotationAngle();
86
87 } else {
88 float rotationStep = std::copysign(
89 std::min(
90 std::abs(rotationAngleDelta),
91 currentRotationSpeed * deltaTime
92 ),
93 rotationAngleDelta
94 );
95 currentRotationAngle = currentRotationAngle + rotationStep;
96 }
97
98 rotationAngleDelta = std::fmod((cmp->targetRotationAngle() - currentRotationAngle) + 540.0f, 360.0f) - 180.0f;
99
100 // Snap to target when close enough
101 if (std::abs(rotationAngleDelta) <= 0.5f) {
102 currentRotationAngle = cmp->targetRotationAngle();
103 rotationAngleDelta = 0.0f;
104 currentRotationSpeed = 0.0f;
105 }
106
107 cmp->setCurrentRotationAngle(currentRotationAngle);
108 cmp->setRotationAngleDelta(rotationAngleDelta);
109 cmp->setCurrentRotationSpeed(currentRotationSpeed);
110 }
111
112 }
113
114
115
116 public:
117
119 /**
120 * @brief Updates the heading of entities.
121 *
122 * @param updateContext Context containing frame timing and game state.
123 */
125
126
127 for (auto [entity, hc, rsc, dc, active] : updateContext.view<
132 >().whereEnabled()) {
133
134
135 if (hc->stateChanged()) {
136 auto direction = hc->steeringInput();
137 auto targetRotationAngle = helios::math::degrees(std::atan2(direction[1], direction[0]));
138 auto rotationAngleDelta = std::fmod((targetRotationAngle - hc->currentRotationAngle()) + 540.0f, 360.0f) - 180.0f;
139
140 float turnBoostFactor = 0.5f;
141 float turnBoost = 1.0f + turnBoostFactor * std::clamp((abs(rotationAngleDelta))/180.f, 0.0f, 1.0f);
142 float currentRotationSpeed = turnBoost * hc->rotationSpeed() * hc->turnIntensity();
143
144 hc->setTargetRotationAngle(targetRotationAngle);
145 hc->setRotationAngleDelta(rotationAngleDelta);
146 hc->setCurrentRotationSpeed(currentRotationSpeed);
147
148 }
149
150 updateHeading(hc, updateContext.deltaTime());
151
152 float rotationAngle = hc->currentRotationAngle();
153 rsc->setHeadingRotationAngle(rotationAngle);
154 rsc->setHeadingRotationAxis(hc->rotationAxis());
155
156 float rad = helios::math::radians(rotationAngle);
157
158 if (hc->directionFromSteering()) {
159 dc->setDirection(helios::math::vec3f{cos(rad), sin(rad), 0.0f});
160 }
161
162
163 }
164
165 }
166
167 };
168
169};

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.