Vulkan Schnee 0.0.1
High-performance rendering engine
Loading...
Searching...
No Matches
VrGliderComponent.h
Go to the documentation of this file.
1#pragma once
5
6#include <glm/glm.hpp>
7#include <glm/gtc/quaternion.hpp>
8
9namespace EngineCore
10{
11 class Headset;
12} // namespace EngineCore
13
14namespace Input
15{
16 class XrInputHandler;
17 enum class Hand;
18} // namespace Input
19
20namespace Engine
21{
22 namespace Rendering
23 {
24 class Headset;
25 } // namespace Rendering
26
30 enum class GliderState
31 {
32 FALLING, // Normal gravity
33 GLIDING, // Arms spread - velocity control
34 STALLED, // Arms spread but too little momentum / too much climb
35 WALKING // On ground - thumbstick locomotion
36 };
37
42 {
44 float armSpreadHysteresis = 0.08f;
45 float tuckDistance = 0.45f;
46
47 float gravity = 3.0f;
49
50 float momentumDrag = 0.12f;
51 float highSpeedDrag = 0.005f;
52 float minGlideSink = 0.65f;
53 float maxClimbRate = 6.0f;
54 float climbMomentumCost = 0.48f;
55 float diveSinkRate = 7.0f;
56 float diveMomentumGain = 0.72f;
57 float windMomentumGain = 0.72f;
58 float windDiminishingSpeed = 12.0f;
59 float windAlignmentPower = 1.6f;
60 float crosswindTurnRate = 0.06f;
61 float headwindPenalty = 0.55f;
62 float glideTurnRate = 7.0f;
63 float stallSpeed = 3.5f;
64 float stallRecoverySpeed = 4.7f;
65 float stallSinkSpeed = 6.0f;
66 float stallDiveSinkScale = 0.35f;
67 float stallExtraDrag = 0.12f;
68 float stallRecoveryDelay = 0.18f;
69 float emergencyMaxSpeed = 80.0f;
70
71 float snapTurnDegrees = 30.0f;
72 float snapTurnThreshold = 0.7f;
73 float stickDeadzone = 0.15f;
74
75 glm::vec3 spawnPosition{ 0.0f, 10.0f, 0.0f };
76
77 float walkSpeed = 2.5f;
78 float groundRayLength = 1.5f;
79 float groundSmoothSpeed = 12.0f;
80 float maxStepHeight = 0.3f;
81 float maxWalkableSlope = 0.7f;
82 float groundHoverOffset = 0.01f;
84 float walkTakeoffMomentum = 4.0f;
87 float fallResetY = -350.0f;
89 float respawnHeightOffset = 1.0f;
90 };
91
92 namespace Components
93 {
94 class PhysicsBody;
95
99 class VrGlider : public Logic
100 {
101 public:
102 static constexpr bool IsUnique = true;
103 static constexpr const char* ComponentName = "VrGlider";
104 static constexpr float CAPSULE_RADIUS = 0.3f; // Must match GliderPlayerActor capsule
105 static constexpr float CAPSULE_HALF_HEIGHT = 0.7f; // Half of cylinder portion (1.4/2)
106 static constexpr float CAPSULE_TOTAL_HALF = 1.0f; // CAPSULE_RADIUS + CAPSULE_HALF_HEIGHT
107
112 {
113 bool tickSkipped = false;
114 bool missingHeadset = false;
116 bool missingPhysicsBody = false;
117
118 bool enabled = true;
119 bool frozen = true;
120 bool debugLogging = true;
123
124 float leftGrip = 0.0f;
125 float rightGrip = 0.0f;
126 bool bothGripsPressed = false;
128
129 float leftTrigger = 0.0f;
130 float rightTrigger = 0.0f;
131 bool leftTriggerPressed = false;
133 glm::vec2 rightThumbstick{ 0.0f };
134 bool snapTurnArmed = true;
135 bool snapTurnTriggered = false;
137
138 bool leftHandValid = false;
139 bool rightHandValid = false;
140 float leftHandDistance = 0.0f;
141 float rightHandDistance = 0.0f;
144 bool armsSpread = false;
146 bool handsTucked = false;
147
148 bool groundDetected = false;
149 bool isNearGround = false;
150 bool groundIsWalkable = false;
151 bool groundYInitialized = false;
152 float groundDistance = 9999.0f;
153 float groundHitFraction = 1.0f;
154 glm::vec3 groundHitPoint{ 0.0f };
155 glm::vec3 groundHitNormal{ 0.0f, 1.0f, 0.0f };
156 float smoothedGroundY = 0.0f;
157
158 glm::vec3 playerPosition{ 0.0f };
159 glm::vec3 headLocalPosition{ 0.0f };
160 glm::vec3 headWorldPosition{ 0.0f };
161 glm::vec3 headForward{ 0.0f, 0.0f, -1.0f };
162 glm::vec3 bodyForward{ 0.0f, 0.0f, -1.0f };
163 glm::vec3 horizontalAim{ 0.0f, 0.0f, -1.0f };
164
165 glm::vec3 velocityBeforeUpdate{ 0.0f };
166 glm::vec3 targetVelocity{ 0.0f };
167 glm::vec3 velocityAfterUpdate{ 0.0f };
168 glm::vec3 desiredPosition{ 0.0f };
169 glm::vec3 physicsBodyVelocity{ 0.0f };
170
171 float playerYawRadians = 0.0f;
172 float palmTilt = 0.0f;
173 float forwardAmount = 0.0f;
174 float rightAmount = 0.0f;
175 float momentum = 0.0f;
176 float verticalVelocity = 0.0f;
177 float climbDemand = 0.0f;
178 float diveDemand = 0.0f;
179 float windAlignment = 0.0f;
180 float windMomentumDelta = 0.0f;
181 float dragDelta = 0.0f;
182 float climbMomentumDelta = 0.0f;
183 float stallRecoveryTimer = 0.0f;
184 bool isBraking = false;
185 bool isClimbing = false;
186 bool isDiving = false;
187 bool isStalled = false;
188 bool enteredStall = false;
189 bool recoveredStall = false;
190
192 glm::vec3 windContribution{ 0.0f };
193
194 bool collisionTested = false;
195 bool collisionImpact = false;
196 bool collisionReset = false;
197 bool takeoffArmed = true;
198 bool takeoffRequested = false;
199 bool takeoffBlocked = false;
200 bool hasLastSafeLanding = false;
201 bool respawnTriggered = false;
202 glm::vec3 takeoffTestPosition{ 0.0f };
203 glm::vec3 lastSafeLandingPosition{ 0.0f };
204 glm::vec3 collisionTestPosition{ 0.0f };
205 glm::vec3 collisionPushOut{ 0.0f };
206 glm::vec3 collisionGroundNormal{ 0.0f };
209
213 };
214
223 Entities::Scene * owningScene,
224 Rendering::Headset * headset,
225 Input::XrInputHandler * inputHandler,
226 PhysicsBody * physicsBody
227 );
228
229 ~VrGlider() override = default;
230
231 [[nodiscard]] std::string getComponentName() const override { return ComponentName; }
232
233 void beginPlay() override;
234 void tick( double deltaTime ) override;
235 void endPlay() override;
236 bool drawImGui() override;
237
241 [[nodiscard]] GliderState getState() const
242 {
243 return currentState_;
244 }
245
249 [[nodiscard]] glm::vec3 getVelocity() const
250 {
251 return velocity_;
252 }
253
257 [[nodiscard]] float getSpeed() const
258 {
259 return glm::length( velocity_ );
260 }
261
265 [[nodiscard]] const GliderConfig & getConfig() const
266 {
267 return config_;
268 }
269
274 {
275 return config_;
276 }
277
281 void setConfig( const GliderConfig & config )
282 {
283 config_ = config;
284 }
285
289 void setEnabled( bool enabled )
290 {
291 enabled_ = enabled;
292 }
293
297 [[nodiscard]] bool isEnabled() const
298 {
299 return enabled_;
300 }
301
305 void setFrozen( bool frozen );
306
308
309 [[nodiscard]] PhysicsBody * getPhysicsBody() const { return physicsBody_; }
310
311 [[nodiscard]] const DebugSnapshot & getDebugSnapshot() const { return debugSnapshot_; }
312
316 [[nodiscard]] bool isFrozen() const
317 {
318 return frozen_;
319 }
320
324 void setDebugLogging( bool enabled )
325 {
326 debugLogging_ = enabled;
327 }
328
332 [[nodiscard]] bool isDebugLogging() const
333 {
334 return debugLogging_;
335 }
336
340 [[nodiscard]] static const char * stateToString( GliderState state );
341
342 private:
346 struct HandData
347 {
348 glm::vec3 position{ 0.0f };
349 glm::vec3 relativePosition{ 0.0f };
350 glm::quat orientation{ 1.0f, 0.0f, 0.0f, 0.0f };
351 glm::vec3 palmNormal{ 0.0f, -1.0f, 0.0f };
352 glm::vec3 fingerDirection{ 0.0f, 0.0f, -1.0f };
353 glm::vec3 thumbDirection{ 0.0f, 1.0f, 0.0f };
354 float distanceFromHead = 0.0f;
355 bool isValid = false;
356 };
357
358 [[nodiscard]] HandData getHandData( Input::Hand hand ) const;
359
360 [[nodiscard]] bool areArmsSpread(
361 const HandData & leftHand,
362 const HandData & rightHand,
363 float hysteresis = 0.0f
364 ) const;
365
366 [[nodiscard]] bool areHandsTucked( const HandData & leftHand, const HandData & rightHand ) const;
367
368 void updateGlidingVelocity( const HandData & leftHand, const HandData & rightHand, float dt );
369
371
372 [[nodiscard]] glm::vec3 buildGlideDirection(
373 const HandData & leftHand,
374 const HandData & rightHand,
375 glm::vec3 & outBodyForward,
376 float & outForwardAmount,
377 float & outRightAmount
378 ) const;
379
383 [[nodiscard]] glm::vec3 getHeadWorldPosition() const;
384
388 [[nodiscard]] glm::quat getHeadOrientation() const;
389
393 [[nodiscard]] glm::vec3 getHeadForward() const;
394
395 bool canStartGlidingFromWalking( const glm::vec3 & currentPos, glm::vec3 & outTakeoffPos ) const;
396
397 bool handleFlightCollision( const glm::vec3 & currentPos, glm::vec3 & desiredPos );
398
400 const glm::vec3 & origin,
401 glm::vec3 & outHitPoint,
402 glm::vec3 & outHitNormal,
403 float & outHitFraction
404 ) const;
405
406 void updateWalkingInput( float dt );
407
408 glm::vec3 collideAndSlide( const glm::vec3 & startPos, const glm::vec3 & displacement );
409
410 void updateLastSafeLanding( const glm::vec3 & position, bool stableWalkableGround, float dt );
411
412 void teleportPlayer( const glm::vec3 & position );
413
415
417
421
424 bool takeoffArmed_ = true;
425
426 glm::vec3 velocity_{ 0.0f };
427 bool enabled_ = true;
428 bool frozen_ = true; // Start frozen so user can put on headset
429 bool debugLogging_ = true; // Enabled to diagnose flight tuning issues.
430 float debugLogTimer_ = 0.0f;
431 static constexpr float DEBUG_LOG_INTERVAL = 0.5f; // Log every 0.5 seconds
432
433 // Grip toggle detection (freeze/unfreeze)
435 static constexpr float GRIP_THRESHOLD = 0.8f; // Grip/trigger must be >80% to count as pressed
436
440 glm::vec3 lastSafeLandingPosition_{ 0.0f, 10.0f, 0.0f };
443
444 // Player yaw for right-stick snap turning (radians, applied to body forward)
445 float playerYaw_ = 0.0f;
447
448 // Walking state
449 float smoothedGroundY_ = 0.0f; // Lerp-smoothed ground height to prevent jitter
450 bool groundYInitialized_ = false; // Whether smoothedGroundY_ has been set from a sweep yet
451
452 // Sweep test constants
453 static constexpr float SKIN_WIDTH = 0.02f; // Small gap to prevent direct surface contact
454 static constexpr int MAX_SLIDE_ITERATIONS = 3; // Max collide-and-slide recursions
455 };
456 } // namespace Components
457
458} // namespace Engine
Logic(Entities::Scene *owningScene)
Component that manages a physics rigid body for an entity.
bool areArmsSpread(const HandData &leftHand, const HandData &rightHand, float hysteresis=0.0f) const
static constexpr float DEBUG_LOG_INTERVAL
glm::vec3 collideAndSlide(const glm::vec3 &startPos, const glm::vec3 &displacement)
void resetGliderStateTo(GliderState state)
static constexpr float GRIP_THRESHOLD
void updateWalkingInput(float dt)
void tick(double deltaTime) override
Called every frame if ticking is enabled.
void beginPlay() override
Called when the component is added to the scene or the game starts.
glm::vec3 getHeadForward() const
Getter.
const GliderConfig & getConfig() const
Getter.
bool sweepGround(const glm::vec3 &origin, glm::vec3 &outHitPoint, glm::vec3 &outHitNormal, float &outHitFraction) const
bool drawImGui() override
Draws component-specific ImGui inspector controls.
bool handleFlightCollision(const glm::vec3 &currentPos, glm::vec3 &desiredPos)
glm::vec3 buildGlideDirection(const HandData &leftHand, const HandData &rightHand, glm::vec3 &outBodyForward, float &outForwardAmount, float &outRightAmount) const
glm::vec3 getHeadWorldPosition() const
Getter.
static constexpr float CAPSULE_TOTAL_HALF
static constexpr int MAX_SLIDE_ITERATIONS
static constexpr float SKIN_WIDTH
static constexpr bool IsUnique
GliderState getState() const
Getter.
std::string getComponentName() const override
Gets the component type name for debugging/UI.
void setDebugLogging(bool enabled)
Setter.
bool isDebugLogging() const
Getter.
static const char * stateToString(GliderState state)
Returns string representation of a glider state.
PhysicsBody * getPhysicsBody() const
void updateLastSafeLanding(const glm::vec3 &position, bool stableWalkableGround, float dt)
Input::XrInputHandler * inputHandler_
bool areHandsTucked(const HandData &leftHand, const HandData &rightHand) const
void setConfig(const GliderConfig &config)
Setter.
const DebugSnapshot & getDebugSnapshot() const
void endPlay() override
Called when the component is removed or the game ends.
void setFrozen(bool frozen)
Pauses/unpauses physics integration.
void updateGlidingVelocity(const HandData &leftHand, const HandData &rightHand, float dt)
HandData getHandData(Input::Hand hand) const
static constexpr const char * ComponentName
glm::vec3 getVelocity() const
Getter.
static constexpr float CAPSULE_HALF_HEIGHT
void setEnabled(bool enabled)
Setter.
void teleportPlayer(const glm::vec3 &position)
VrGlider(Entities::Scene *owningScene, Rendering::Headset *headset, Input::XrInputHandler *inputHandler, PhysicsBody *physicsBody)
Constructs the VR glider component.
static constexpr float CAPSULE_RADIUS
~VrGlider() override=default
bool canStartGlidingFromWalking(const glm::vec3 &currentPos, glm::vec3 &outTakeoffPos) const
ArcadeGliderTuning makeFlightTuning() const
glm::quat getHeadOrientation() const
Getter.
GliderConfig & getConfig()
Getter.
A scene is the overarching structure which can spawn, contain and destroy actors or entities.
Definition Scene.h:62
Handles OpenXR input actions and controller state.
GliderState
Glider movement states.
Persistent state carried between arcade glider simulation steps.
Stores the config values for the glider. Can be used to change the flight behavior of the glider move...
Debug state captured from the most recent VR glider tick.
Hand position and orientation data relative to head.
Configuration parameters for the VR glider system (distances in meters, speeds in m/s,...
A wind sample is the wind force at one point in the wind field.
Definition WindField.h:46