Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Character/CharacterVirtual.h
9912 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#pragma once
6
7
#include <Jolt/Physics/Character/CharacterBase.h>
8
#include <Jolt/Physics/Character/CharacterID.h>
9
#include <Jolt/Physics/Body/MotionType.h>
10
#include <Jolt/Physics/Body/BodyFilter.h>
11
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseLayer.h>
12
#include <Jolt/Physics/Collision/ObjectLayer.h>
13
#include <Jolt/Physics/Collision/TransformedShape.h>
14
#include <Jolt/Core/STLTempAllocator.h>
15
16
JPH_NAMESPACE_BEGIN
17
18
class CharacterVirtual;
19
class CollideShapeSettings;
20
21
/// Contains the configuration of a character
22
class JPH_EXPORT CharacterVirtualSettings : public CharacterBaseSettings
23
{
24
public:
25
JPH_OVERRIDE_NEW_DELETE
26
27
/// ID to give to this character. This is used for deterministically sorting and as an identifier to represent the character in the contact removal callback.
28
CharacterID mID = CharacterID::sNextCharacterID();
29
30
/// Character mass (kg). Used to push down objects with gravity when the character is standing on top.
31
float mMass = 70.0f;
32
33
/// Maximum force with which the character can push other bodies (N).
34
float mMaxStrength = 100.0f;
35
36
/// An extra offset applied to the shape in local space. This allows applying an extra offset to the shape in local space.
37
Vec3 mShapeOffset = Vec3::sZero();
38
39
///@name Movement settings
40
EBackFaceMode mBackFaceMode = EBackFaceMode::CollideWithBackFaces; ///< When colliding with back faces, the character will not be able to move through back facing triangles. Use this if you have triangles that need to collide on both sides.
41
float mPredictiveContactDistance = 0.1f; ///< How far to scan outside of the shape for predictive contacts. A value of 0 will most likely cause the character to get stuck as it cannot properly calculate a sliding direction anymore. A value that's too high will cause ghost collisions.
42
uint mMaxCollisionIterations = 5; ///< Max amount of collision loops
43
uint mMaxConstraintIterations = 15; ///< How often to try stepping in the constraint solving
44
float mMinTimeRemaining = 1.0e-4f; ///< Early out condition: If this much time is left to simulate we are done
45
float mCollisionTolerance = 1.0e-3f; ///< How far we're willing to penetrate geometry
46
float mCharacterPadding = 0.02f; ///< How far we try to stay away from the geometry, this ensures that the sweep will hit as little as possible lowering the collision cost and reducing the risk of getting stuck
47
uint mMaxNumHits = 256; ///< Max num hits to collect in order to avoid excess of contact points collection
48
float mHitReductionCosMaxAngle = 0.999f; ///< Cos(angle) where angle is the maximum angle between two hits contact normals that are allowed to be merged during hit reduction. Default is around 2.5 degrees. Set to -1 to turn off.
49
float mPenetrationRecoverySpeed = 1.0f; ///< This value governs how fast a penetration will be resolved, 0 = nothing is resolved, 1 = everything in one update
50
51
/// This character can optionally have an inner rigid body. This rigid body can be used to give the character presence in the world. When set it means that:
52
/// - Regular collision checks (e.g. NarrowPhaseQuery::CastRay) will collide with the rigid body (they cannot collide with CharacterVirtual since it is not added to the broad phase)
53
/// - Regular contact callbacks will be called through the ContactListener (next to the ones that will be passed to the CharacterContactListener)
54
/// - Fast moving objects of motion quality LinearCast will not be able to pass through the CharacterVirtual in 1 time step
55
RefConst<Shape> mInnerBodyShape;
56
57
/// For a deterministic simulation, it is important to have a deterministic body ID. When set and when mInnerBodyShape is specified,
58
/// the inner body will be created with this specified ID instead of a generated ID.
59
BodyID mInnerBodyIDOverride;
60
61
/// Layer that the inner rigid body will be added to
62
ObjectLayer mInnerBodyLayer = 0;
63
};
64
65
/// This class contains settings that allow you to override the behavior of a character's collision response
66
class CharacterContactSettings
67
{
68
public:
69
/// True when the object can push the virtual character.
70
bool mCanPushCharacter = true;
71
72
/// True when the virtual character can apply impulses (push) the body.
73
/// Note that this only works against rigid bodies. Other CharacterVirtual objects can only be moved in their own update,
74
/// so you must ensure that in their OnCharacterContactAdded mCanPushCharacter is true.
75
bool mCanReceiveImpulses = true;
76
};
77
78
/// This class receives callbacks when a virtual character hits something.
79
class JPH_EXPORT CharacterContactListener
80
{
81
public:
82
/// Destructor
83
virtual ~CharacterContactListener() = default;
84
85
/// Callback to adjust the velocity of a body as seen by the character. Can be adjusted to e.g. implement a conveyor belt or an inertial dampener system of a sci-fi space ship.
86
/// Note that inBody2 is locked during the callback so you can read its properties freely.
87
virtual void OnAdjustBodyVelocity(const CharacterVirtual *inCharacter, const Body &inBody2, Vec3 &ioLinearVelocity, Vec3 &ioAngularVelocity) { /* Do nothing, the linear and angular velocity are already filled in */ }
88
89
/// Checks if a character can collide with specified body. Return true if the contact is valid.
90
virtual bool OnContactValidate(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2) { return true; }
91
92
/// Same as OnContactValidate but when colliding with a CharacterVirtual
93
virtual bool OnCharacterContactValidate(const CharacterVirtual *inCharacter, const CharacterVirtual *inOtherCharacter, const SubShapeID &inSubShapeID2) { return true; }
94
95
/// Called whenever the character collides with a body for the first time.
96
/// @param inCharacter Character that is being solved
97
/// @param inBodyID2 Body ID of body that is being hit
98
/// @param inSubShapeID2 Sub shape ID of shape that is being hit
99
/// @param inContactPosition World space contact position
100
/// @param inContactNormal World space contact normal
101
/// @param ioSettings Settings returned by the contact callback to indicate how the character should behave
102
virtual void OnContactAdded(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, CharacterContactSettings &ioSettings) { /* Default do nothing */ }
103
104
/// Called whenever the character persists colliding with a body.
105
/// @param inCharacter Character that is being solved
106
/// @param inBodyID2 Body ID of body that is being hit
107
/// @param inSubShapeID2 Sub shape ID of shape that is being hit
108
/// @param inContactPosition World space contact position
109
/// @param inContactNormal World space contact normal
110
/// @param ioSettings Settings returned by the contact callback to indicate how the character should behave
111
virtual void OnContactPersisted(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, CharacterContactSettings &ioSettings) { /* Default do nothing */ }
112
113
/// Called whenever the character loses contact with a body.
114
/// Note that there is no guarantee that the body or its sub shape still exists at this point. The body may have been deleted since the last update.
115
/// @param inCharacter Character that is being solved
116
/// @param inBodyID2 Body ID of body that is being hit
117
/// @param inSubShapeID2 Sub shape ID of shape that is being hit
118
virtual void OnContactRemoved(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2) { /* Default do nothing */ }
119
120
/// Same as OnContactAdded but when colliding with a CharacterVirtual
121
virtual void OnCharacterContactAdded(const CharacterVirtual *inCharacter, const CharacterVirtual *inOtherCharacter, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, CharacterContactSettings &ioSettings) { /* Default do nothing */ }
122
123
/// Same as OnContactPersisted but when colliding with a CharacterVirtual
124
virtual void OnCharacterContactPersisted(const CharacterVirtual *inCharacter, const CharacterVirtual *inOtherCharacter, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, CharacterContactSettings &ioSettings) { /* Default do nothing */ }
125
126
/// Same as OnContactRemoved but when colliding with a CharacterVirtual
127
/// Note that inOtherCharacterID can be the ID of a character that has been deleted. This happens if the character was in contact with this character during the last update, but has been deleted since.
128
virtual void OnCharacterContactRemoved(const CharacterVirtual *inCharacter, const CharacterID &inOtherCharacterID, const SubShapeID &inSubShapeID2) { /* Default do nothing */ }
129
130
/// Called whenever a contact is being used by the solver. Allows the listener to override the resulting character velocity (e.g. by preventing sliding along certain surfaces).
131
/// @param inCharacter Character that is being solved
132
/// @param inBodyID2 Body ID of body that is being hit
133
/// @param inSubShapeID2 Sub shape ID of shape that is being hit
134
/// @param inContactPosition World space contact position
135
/// @param inContactNormal World space contact normal
136
/// @param inContactVelocity World space velocity of contact point (e.g. for a moving platform)
137
/// @param inContactMaterial Material of contact point
138
/// @param inCharacterVelocity World space velocity of the character prior to hitting this contact
139
/// @param ioNewCharacterVelocity Contains the calculated world space velocity of the character after hitting this contact, this velocity slides along the surface of the contact. Can be modified by the listener to provide an alternative velocity.
140
virtual void OnContactSolve(const CharacterVirtual *inCharacter, const BodyID &inBodyID2, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, Vec3Arg inContactVelocity, const PhysicsMaterial *inContactMaterial, Vec3Arg inCharacterVelocity, Vec3 &ioNewCharacterVelocity) { /* Default do nothing */ }
141
142
/// Same as OnContactSolve but when colliding with a CharacterVirtual
143
virtual void OnCharacterContactSolve(const CharacterVirtual *inCharacter, const CharacterVirtual *inOtherCharacter, const SubShapeID &inSubShapeID2, RVec3Arg inContactPosition, Vec3Arg inContactNormal, Vec3Arg inContactVelocity, const PhysicsMaterial *inContactMaterial, Vec3Arg inCharacterVelocity, Vec3 &ioNewCharacterVelocity) { /* Default do nothing */ }
144
};
145
146
/// Interface class that allows a CharacterVirtual to check collision with other CharacterVirtual instances.
147
/// Since CharacterVirtual instances are not registered anywhere, it is up to the application to test collision against relevant characters.
148
/// The characters could be stored in a tree structure to make this more efficient.
149
class JPH_EXPORT CharacterVsCharacterCollision : public NonCopyable
150
{
151
public:
152
virtual ~CharacterVsCharacterCollision() = default;
153
154
/// Collide a character against other CharacterVirtuals.
155
/// @param inCharacter The character to collide.
156
/// @param inCenterOfMassTransform Center of mass transform for this character.
157
/// @param inCollideShapeSettings Settings for the collision check.
158
/// @param inBaseOffset All hit results will be returned relative to this offset, can be zero to get results in world position, but when you're testing far from the origin you get better precision by picking a position that's closer e.g. GetPosition() since floats are most accurate near the origin
159
/// @param ioCollector Collision collector that receives the collision results.
160
virtual void CollideCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector) const = 0;
161
162
/// Cast a character against other CharacterVirtuals.
163
/// @param inCharacter The character to cast.
164
/// @param inCenterOfMassTransform Center of mass transform for this character.
165
/// @param inDirection Direction and length to cast in.
166
/// @param inShapeCastSettings Settings for the shape cast.
167
/// @param inBaseOffset All hit results will be returned relative to this offset, can be zero to get results in world position, but when you're testing far from the origin you get better precision by picking a position that's closer e.g. GetPosition() since floats are most accurate near the origin
168
/// @param ioCollector Collision collector that receives the collision results.
169
virtual void CastCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, Vec3Arg inDirection, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector) const = 0;
170
};
171
172
/// Simple collision checker that loops over all registered characters.
173
/// This is a brute force checking algorithm. If you have a lot of characters you may want to store your characters
174
/// in a hierarchical structure to make this more efficient.
175
/// Note that this is not thread safe, so make sure that only one CharacterVirtual is checking collision at a time.
176
class JPH_EXPORT CharacterVsCharacterCollisionSimple : public CharacterVsCharacterCollision
177
{
178
public:
179
/// Add a character to the list of characters to check collision against.
180
void Add(CharacterVirtual *inCharacter) { mCharacters.push_back(inCharacter); }
181
182
/// Remove a character from the list of characters to check collision against.
183
void Remove(const CharacterVirtual *inCharacter);
184
185
// See: CharacterVsCharacterCollision
186
virtual void CollideCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector) const override;
187
virtual void CastCharacter(const CharacterVirtual *inCharacter, RMat44Arg inCenterOfMassTransform, Vec3Arg inDirection, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector) const override;
188
189
Array<CharacterVirtual *> mCharacters; ///< The list of characters to check collision against
190
};
191
192
/// Runtime character object.
193
/// This object usually represents the player. Contrary to the Character class it doesn't use a rigid body but moves doing collision checks only (hence the name virtual).
194
/// The advantage of this is that you can determine when the character moves in the frame (usually this has to happen at a very particular point in the frame)
195
/// but the downside is that other objects don't see this virtual character. To make a CharacterVirtual visible to the simulation, you can optionally create an inner
196
/// rigid body through CharacterVirtualSettings::mInnerBodyShape. A CharacterVirtual is not tracked by the PhysicsSystem so you need to update it yourself. This also means
197
/// that a call to PhysicsSystem::SaveState will not save its state, you need to call CharacterVirtual::SaveState yourself.
198
class JPH_EXPORT CharacterVirtual : public CharacterBase
199
{
200
public:
201
JPH_OVERRIDE_NEW_DELETE
202
203
/// Constructor
204
/// @param inSettings The settings for the character
205
/// @param inPosition Initial position for the character
206
/// @param inRotation Initial rotation for the character (usually only around the up-axis)
207
/// @param inUserData Application specific value
208
/// @param inSystem Physics system that this character will be added to
209
CharacterVirtual(const CharacterVirtualSettings *inSettings, RVec3Arg inPosition, QuatArg inRotation, uint64 inUserData, PhysicsSystem *inSystem);
210
211
/// Constructor without user data
212
CharacterVirtual(const CharacterVirtualSettings *inSettings, RVec3Arg inPosition, QuatArg inRotation, PhysicsSystem *inSystem) : CharacterVirtual(inSettings, inPosition, inRotation, 0, inSystem) { }
213
214
/// Destructor
215
virtual ~CharacterVirtual() override;
216
217
/// The ID of this character
218
inline const CharacterID & GetID() const { return mID; }
219
220
/// Set the contact listener
221
void SetListener(CharacterContactListener *inListener) { mListener = inListener; }
222
223
/// Get the current contact listener
224
CharacterContactListener * GetListener() const { return mListener; }
225
226
/// Set the character vs character collision interface
227
void SetCharacterVsCharacterCollision(CharacterVsCharacterCollision *inCharacterVsCharacterCollision) { mCharacterVsCharacterCollision = inCharacterVsCharacterCollision; }
228
229
/// Get the linear velocity of the character (m / s)
230
Vec3 GetLinearVelocity() const { return mLinearVelocity; }
231
232
/// Set the linear velocity of the character (m / s)
233
void SetLinearVelocity(Vec3Arg inLinearVelocity) { mLinearVelocity = inLinearVelocity; }
234
235
/// Get the position of the character
236
RVec3 GetPosition() const { return mPosition; }
237
238
/// Set the position of the character
239
void SetPosition(RVec3Arg inPosition) { mPosition = inPosition; UpdateInnerBodyTransform(); }
240
241
/// Get the rotation of the character
242
Quat GetRotation() const { return mRotation; }
243
244
/// Set the rotation of the character
245
void SetRotation(QuatArg inRotation) { mRotation = inRotation; UpdateInnerBodyTransform(); }
246
247
// Get the center of mass position of the shape
248
inline RVec3 GetCenterOfMassPosition() const { return mPosition + (mRotation * (mShapeOffset + mShape->GetCenterOfMass()) + mCharacterPadding * mUp); }
249
250
/// Calculate the world transform of the character
251
RMat44 GetWorldTransform() const { return RMat44::sRotationTranslation(mRotation, mPosition); }
252
253
/// Calculates the transform for this character's center of mass
254
RMat44 GetCenterOfMassTransform() const { return GetCenterOfMassTransform(mPosition, mRotation, mShape); }
255
256
/// Character mass (kg)
257
float GetMass() const { return mMass; }
258
void SetMass(float inMass) { mMass = inMass; }
259
260
/// Maximum force with which the character can push other bodies (N)
261
float GetMaxStrength() const { return mMaxStrength; }
262
void SetMaxStrength(float inMaxStrength) { mMaxStrength = inMaxStrength; }
263
264
/// This value governs how fast a penetration will be resolved, 0 = nothing is resolved, 1 = everything in one update
265
float GetPenetrationRecoverySpeed() const { return mPenetrationRecoverySpeed; }
266
void SetPenetrationRecoverySpeed(float inSpeed) { mPenetrationRecoverySpeed = inSpeed; }
267
268
/// Set to indicate that extra effort should be made to try to remove ghost contacts (collisions with internal edges of a mesh). This is more expensive but makes bodies move smoother over a mesh with convex edges.
269
bool GetEnhancedInternalEdgeRemoval() const { return mEnhancedInternalEdgeRemoval; }
270
void SetEnhancedInternalEdgeRemoval(bool inApply) { mEnhancedInternalEdgeRemoval = inApply; }
271
272
/// Character padding
273
float GetCharacterPadding() const { return mCharacterPadding; }
274
275
/// Max num hits to collect in order to avoid excess of contact points collection
276
uint GetMaxNumHits() const { return mMaxNumHits; }
277
void SetMaxNumHits(uint inMaxHits) { mMaxNumHits = inMaxHits; }
278
279
/// Cos(angle) where angle is the maximum angle between two hits contact normals that are allowed to be merged during hit reduction. Default is around 2.5 degrees. Set to -1 to turn off.
280
float GetHitReductionCosMaxAngle() const { return mHitReductionCosMaxAngle; }
281
void SetHitReductionCosMaxAngle(float inCosMaxAngle) { mHitReductionCosMaxAngle = inCosMaxAngle; }
282
283
/// Returns if we exceeded the maximum number of hits during the last collision check and had to discard hits based on distance.
284
/// This can be used to find areas that have too complex geometry for the character to navigate properly.
285
/// To solve you can either increase the max number of hits or simplify the geometry. Note that the character simulation will
286
/// try to do its best to select the most relevant contacts to avoid the character from getting stuck.
287
bool GetMaxHitsExceeded() const { return mMaxHitsExceeded; }
288
289
/// An extra offset applied to the shape in local space. This allows applying an extra offset to the shape in local space. Note that setting it on the fly can cause the shape to teleport into collision.
290
Vec3 GetShapeOffset() const { return mShapeOffset; }
291
void SetShapeOffset(Vec3Arg inShapeOffset) { mShapeOffset = inShapeOffset; UpdateInnerBodyTransform(); }
292
293
/// Access to the user data, can be used for anything by the application
294
uint64 GetUserData() const { return mUserData; }
295
void SetUserData(uint64 inUserData);
296
297
/// Optional inner rigid body that proxies the character in the world. Can be used to update body properties.
298
BodyID GetInnerBodyID() const { return mInnerBodyID; }
299
300
/// This function can be called prior to calling Update() to convert a desired velocity into a velocity that won't make the character move further onto steep slopes.
301
/// This velocity can then be set on the character using SetLinearVelocity()
302
/// @param inDesiredVelocity Velocity to clamp against steep walls
303
/// @return A new velocity vector that won't make the character move up steep slopes
304
Vec3 CancelVelocityTowardsSteepSlopes(Vec3Arg inDesiredVelocity) const;
305
306
/// This function is internally called by Update, WalkStairs, StickToFloor and ExtendedUpdate and is responsible for tracking if contacts are added, persisted or removed.
307
/// If you want to do multiple operations on a character (e.g. first Update then WalkStairs), you can surround the code with a StartTrackingContactChanges and FinishTrackingContactChanges pair
308
/// to only receive a single callback per contact on the CharacterContactListener. If you don't do this then you could for example receive a contact added callback during the Update and a
309
/// contact persisted callback during WalkStairs.
310
void StartTrackingContactChanges();
311
312
/// This call triggers contact removal callbacks and is used in conjunction with StartTrackingContactChanges.
313
void FinishTrackingContactChanges();
314
315
/// This is the main update function. It moves the character according to its current velocity (the character is similar to a kinematic body in the sense
316
/// that you set the velocity and the character will follow unless collision is blocking the way). Note it's your own responsibility to apply gravity to the character velocity!
317
/// Different surface materials (like ice) can be emulated by getting the ground material and adjusting the velocity and/or the max slope angle accordingly every frame.
318
/// @param inDeltaTime Time step to simulate.
319
/// @param inGravity Gravity vector (m/s^2). This gravity vector is only used when the character is standing on top of another object to apply downward force.
320
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
321
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
322
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
323
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
324
/// @param inAllocator An allocator for temporary allocations. All memory will be freed by the time this function returns.
325
void Update(float inDeltaTime, Vec3Arg inGravity, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
326
327
/// This function will return true if the character has moved into a slope that is too steep (e.g. a vertical wall).
328
/// You would call WalkStairs to attempt to step up stairs.
329
/// @param inLinearVelocity The linear velocity that the player desired. This is used to determine if we're pushing into a step.
330
bool CanWalkStairs(Vec3Arg inLinearVelocity) const;
331
332
/// When stair walking is needed, you can call the WalkStairs function to cast up, forward and down again to try to find a valid position
333
/// @param inDeltaTime Time step to simulate.
334
/// @param inStepUp The direction and distance to step up (this corresponds to the max step height)
335
/// @param inStepForward The direction and distance to step forward after the step up
336
/// @param inStepForwardTest When running at a high frequency, inStepForward can be very small and it's likely that you hit the side of the stairs on the way down. This could produce a normal that violates the max slope angle. If this happens, we test again using this distance from the up position to see if we find a valid slope.
337
/// @param inStepDownExtra An additional translation that is added when stepping down at the end. Allows you to step further down than up. Set to zero if you don't want this. Should be in the opposite direction of up.
338
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
339
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
340
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
341
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
342
/// @param inAllocator An allocator for temporary allocations. All memory will be freed by the time this function returns.
343
/// @return true if the stair walk was successful
344
bool WalkStairs(float inDeltaTime, Vec3Arg inStepUp, Vec3Arg inStepForward, Vec3Arg inStepForwardTest, Vec3Arg inStepDownExtra, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
345
346
/// This function can be used to artificially keep the character to the floor. Normally when a character is on a small step and starts moving horizontally, the character will
347
/// lose contact with the floor because the initial vertical velocity is zero while the horizontal velocity is quite high. To prevent the character from losing contact with the floor,
348
/// we do an additional collision check downwards and if we find the floor within a certain distance, we project the character onto the floor.
349
/// @param inStepDown Max amount to project the character downwards (if no floor is found within this distance, the function will return false)
350
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
351
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
352
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
353
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
354
/// @param inAllocator An allocator for temporary allocations. All memory will be freed by the time this function returns.
355
/// @return True if the character was successfully projected onto the floor.
356
bool StickToFloor(Vec3Arg inStepDown, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
357
358
/// Settings struct with settings for ExtendedUpdate
359
struct ExtendedUpdateSettings
360
{
361
Vec3 mStickToFloorStepDown { 0, -0.5f, 0 }; ///< See StickToFloor inStepDown parameter. Can be zero to turn off.
362
Vec3 mWalkStairsStepUp { 0, 0.4f, 0 }; ///< See WalkStairs inStepUp parameter. Can be zero to turn off.
363
float mWalkStairsMinStepForward { 0.02f }; ///< See WalkStairs inStepForward parameter. Note that the parameter only indicates a magnitude, direction is taken from current velocity.
364
float mWalkStairsStepForwardTest { 0.15f }; ///< See WalkStairs inStepForwardTest parameter. Note that the parameter only indicates a magnitude, direction is taken from current velocity.
365
float mWalkStairsCosAngleForwardContact { Cos(DegreesToRadians(75.0f)) }; ///< Cos(angle) where angle is the maximum angle between the ground normal in the horizontal plane and the character forward vector where we're willing to adjust the step forward test towards the contact normal.
366
Vec3 mWalkStairsStepDownExtra { Vec3::sZero() }; ///< See WalkStairs inStepDownExtra
367
};
368
369
/// This function combines Update, StickToFloor and WalkStairs. This function serves as an example of how these functions could be combined.
370
/// Before calling, call SetLinearVelocity to update the horizontal/vertical speed of the character, typically this is:
371
/// - When on OnGround and not moving away from ground: velocity = GetGroundVelocity() + horizontal speed as input by player + optional vertical jump velocity + delta time * gravity
372
/// - Else: velocity = current vertical velocity + horizontal speed as input by player + delta time * gravity
373
/// @param inDeltaTime Time step to simulate.
374
/// @param inGravity Gravity vector (m/s^2). This gravity vector is only used when the character is standing on top of another object to apply downward force.
375
/// @param inSettings A structure containing settings for the algorithm.
376
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
377
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
378
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
379
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
380
/// @param inAllocator An allocator for temporary allocations. All memory will be freed by the time this function returns.
381
void ExtendedUpdate(float inDeltaTime, Vec3Arg inGravity, const ExtendedUpdateSettings &inSettings, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
382
383
/// This function can be used after a character has teleported to determine the new contacts with the world.
384
void RefreshContacts(const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
385
386
/// Use the ground body ID to get an updated estimate of the ground velocity. This function can be used if the ground body has moved / changed velocity and you want a new estimate of the ground velocity.
387
/// It will not perform collision detection, so is less accurate than RefreshContacts but a lot faster.
388
void UpdateGroundVelocity();
389
390
/// Switch the shape of the character (e.g. for stance).
391
/// @param inShape The shape to switch to.
392
/// @param inMaxPenetrationDepth When inMaxPenetrationDepth is not FLT_MAX, it checks if the new shape collides before switching shape. This is the max penetration we're willing to accept after the switch.
393
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
394
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
395
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
396
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
397
/// @param inAllocator An allocator for temporary allocations. All memory will be freed by the time this function returns.
398
/// @return Returns true if the switch succeeded.
399
bool SetShape(const Shape *inShape, float inMaxPenetrationDepth, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
400
401
/// Updates the shape of the inner rigid body. Should be called after a successful call to SetShape.
402
void SetInnerBodyShape(const Shape *inShape);
403
404
/// Get the transformed shape that represents the volume of the character, can be used for collision checks.
405
TransformedShape GetTransformedShape() const { return TransformedShape(GetCenterOfMassPosition(), mRotation, mShape, mInnerBodyID); }
406
407
/// @brief Get all contacts for the character at a particular location.
408
/// When colliding with another character virtual, this pointer will be provided through CollideShapeCollector::SetUserContext before adding a hit.
409
/// @param inPosition Position to test, note that this position will be corrected for the character padding.
410
/// @param inRotation Rotation at which to test the shape.
411
/// @param inMovementDirection A hint in which direction the character is moving, will be used to calculate a proper normal.
412
/// @param inMaxSeparationDistance How much distance around the character you want to report contacts in (can be 0 to match the character exactly).
413
/// @param inShape Shape to test collision with.
414
/// @param inBaseOffset All hit results will be returned relative to this offset, can be zero to get results in world position, but when you're testing far from the origin you get better precision by picking a position that's closer e.g. GetPosition() since floats are most accurate near the origin
415
/// @param ioCollector Collision collector that receives the collision results.
416
/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
417
/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
418
/// @param inBodyFilter Filter that is used to check if a character collides with a body.
419
/// @param inShapeFilter Filter that is used to check if a character collides with a subshape.
420
void CheckCollision(RVec3Arg inPosition, QuatArg inRotation, Vec3Arg inMovementDirection, float inMaxSeparationDistance, const Shape *inShape, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const;
421
422
// Saving / restoring state for replay
423
virtual void SaveState(StateRecorder &inStream) const override;
424
virtual void RestoreState(StateRecorder &inStream) override;
425
426
#ifdef JPH_DEBUG_RENDERER
427
static inline bool sDrawConstraints = false; ///< Draw the current state of the constraints for iteration 0 when creating them
428
static inline bool sDrawWalkStairs = false; ///< Draw the state of the walk stairs algorithm
429
static inline bool sDrawStickToFloor = false; ///< Draw the state of the stick to floor algorithm
430
#endif
431
432
/// Uniquely identifies a contact between a character and another body or character
433
class ContactKey
434
{
435
public:
436
/// Constructor
437
ContactKey() = default;
438
ContactKey(const ContactKey &inContact) = default;
439
ContactKey(const BodyID &inBodyB, const SubShapeID &inSubShapeID) : mBodyB(inBodyB), mSubShapeIDB(inSubShapeID) { }
440
ContactKey(const CharacterID &inCharacterIDB, const SubShapeID &inSubShapeID) : mCharacterIDB(inCharacterIDB), mSubShapeIDB(inSubShapeID) { }
441
ContactKey & operator = (const ContactKey &inContact) = default;
442
443
/// Checks if two contacts refer to the same body (or virtual character)
444
inline bool IsSameBody(const ContactKey &inOther) const { return mBodyB == inOther.mBodyB && mCharacterIDB == inOther.mCharacterIDB; }
445
446
/// Equality operator
447
bool operator == (const ContactKey &inRHS) const
448
{
449
return mBodyB == inRHS.mBodyB && mCharacterIDB == inRHS.mCharacterIDB && mSubShapeIDB == inRHS.mSubShapeIDB;
450
}
451
452
bool operator != (const ContactKey &inRHS) const
453
{
454
return !(*this == inRHS);
455
}
456
457
/// Hash of this structure
458
uint64 GetHash() const
459
{
460
static_assert(sizeof(BodyID) + sizeof(CharacterID) + sizeof(SubShapeID) == sizeof(ContactKey), "No padding expected");
461
return HashBytes(this, sizeof(ContactKey));
462
}
463
464
// Saving / restoring state for replay
465
void SaveState(StateRecorder &inStream) const;
466
void RestoreState(StateRecorder &inStream);
467
468
BodyID mBodyB; ///< ID of body we're colliding with (if not invalid)
469
CharacterID mCharacterIDB; ///< Character we're colliding with (if not invalid)
470
SubShapeID mSubShapeIDB; ///< Sub shape ID of body or character we're colliding with
471
};
472
473
/// Encapsulates a collision contact
474
struct Contact : public ContactKey
475
{
476
// Saving / restoring state for replay
477
void SaveState(StateRecorder &inStream) const;
478
void RestoreState(StateRecorder &inStream);
479
480
RVec3 mPosition; ///< Position where the character makes contact
481
Vec3 mLinearVelocity; ///< Velocity of the contact point
482
Vec3 mContactNormal; ///< Contact normal, pointing towards the character
483
Vec3 mSurfaceNormal; ///< Surface normal of the contact
484
float mDistance; ///< Distance to the contact <= 0 means that it is an actual contact, > 0 means predictive
485
float mFraction; ///< Fraction along the path where this contact takes place
486
EMotionType mMotionTypeB; ///< Motion type of B, used to determine the priority of the contact
487
bool mIsSensorB; ///< If B is a sensor
488
const CharacterVirtual * mCharacterB = nullptr; ///< Character we're colliding with (if not nullptr). Note that this may be a dangling pointer when accessed through GetActiveContacts(), use mCharacterIDB instead.
489
uint64 mUserData; ///< User data of B
490
const PhysicsMaterial * mMaterial; ///< Material of B
491
bool mHadCollision = false; ///< If the character actually collided with the contact (can be false if a predictive contact never becomes a real one)
492
bool mWasDiscarded = false; ///< If the contact validate callback chose to discard this contact or when the body is a sensor
493
bool mCanPushCharacter = true; ///< When true, the velocity of the contact point can push the character
494
};
495
496
using TempContactList = Array<Contact, STLTempAllocator<Contact>>;
497
using ContactList = Array<Contact>;
498
499
/// Access to the internal list of contacts that the character has found.
500
/// Note that only contacts that have their mHadCollision flag set are actual contacts.
501
const ContactList & GetActiveContacts() const { return mActiveContacts; }
502
503
/// Check if the character is currently in contact with or has collided with another body in the last operation (e.g. Update or WalkStairs)
504
bool HasCollidedWith(const BodyID &inBody) const
505
{
506
for (const CharacterVirtual::Contact &c : mActiveContacts)
507
if (c.mHadCollision && c.mBodyB == inBody)
508
return true;
509
return false;
510
}
511
512
/// Check if the character is currently in contact with or has collided with another character in the last time step (e.g. Update or WalkStairs)
513
bool HasCollidedWith(const CharacterID &inCharacterID) const
514
{
515
for (const CharacterVirtual::Contact &c : mActiveContacts)
516
if (c.mHadCollision && c.mCharacterIDB == inCharacterID)
517
return true;
518
return false;
519
}
520
521
/// Check if the character is currently in contact with or has collided with another character in the last time step (e.g. Update or WalkStairs)
522
bool HasCollidedWith(const CharacterVirtual *inCharacter) const
523
{
524
return HasCollidedWith(inCharacter->GetID());
525
}
526
527
private:
528
// Sorting predicate for making contact order deterministic
529
struct ContactOrderingPredicate
530
{
531
inline bool operator () (const Contact &inLHS, const Contact &inRHS) const
532
{
533
if (inLHS.mBodyB != inRHS.mBodyB)
534
return inLHS.mBodyB < inRHS.mBodyB;
535
536
if (inLHS.mCharacterIDB != inRHS.mCharacterIDB)
537
return inLHS.mCharacterIDB < inRHS.mCharacterIDB;
538
539
return inLHS.mSubShapeIDB.GetValue() < inRHS.mSubShapeIDB.GetValue();
540
}
541
};
542
543
using IgnoredContactList = Array<ContactKey, STLTempAllocator<ContactKey>>;
544
545
// A constraint that limits the movement of the character
546
struct Constraint
547
{
548
Contact * mContact; ///< Contact that this constraint was generated from
549
float mTOI; ///< Calculated time of impact (can be negative if penetrating)
550
float mProjectedVelocity; ///< Velocity of the contact projected on the contact normal (negative if separating)
551
Vec3 mLinearVelocity; ///< Velocity of the contact (can contain a corrective velocity to resolve penetration)
552
Plane mPlane; ///< Plane around the origin that describes how far we can displace (from the origin)
553
bool mIsSteepSlope = false; ///< If this constraint belongs to a steep slope
554
};
555
556
using ConstraintList = Array<Constraint, STLTempAllocator<Constraint>>;
557
558
// Collision collector that collects hits for CollideShape
559
class ContactCollector : public CollideShapeCollector
560
{
561
public:
562
ContactCollector(PhysicsSystem *inSystem, const CharacterVirtual *inCharacter, uint inMaxHits, float inHitReductionCosMaxAngle, Vec3Arg inUp, RVec3Arg inBaseOffset, TempContactList &outContacts) : mBaseOffset(inBaseOffset), mUp(inUp), mSystem(inSystem), mCharacter(inCharacter), mContacts(outContacts), mMaxHits(inMaxHits), mHitReductionCosMaxAngle(inHitReductionCosMaxAngle) { }
563
564
virtual void SetUserData(uint64 inUserData) override { mOtherCharacter = reinterpret_cast<CharacterVirtual *>(inUserData); }
565
566
virtual void AddHit(const CollideShapeResult &inResult) override;
567
568
RVec3 mBaseOffset;
569
Vec3 mUp;
570
PhysicsSystem * mSystem;
571
const CharacterVirtual * mCharacter;
572
CharacterVirtual * mOtherCharacter = nullptr;
573
TempContactList & mContacts;
574
uint mMaxHits;
575
float mHitReductionCosMaxAngle;
576
bool mMaxHitsExceeded = false;
577
};
578
579
// A collision collector that collects hits for CastShape
580
class ContactCastCollector : public CastShapeCollector
581
{
582
public:
583
ContactCastCollector(PhysicsSystem *inSystem, const CharacterVirtual *inCharacter, Vec3Arg inDisplacement, Vec3Arg inUp, const IgnoredContactList &inIgnoredContacts, RVec3Arg inBaseOffset, Contact &outContact) : mBaseOffset(inBaseOffset), mDisplacement(inDisplacement), mUp(inUp), mSystem(inSystem), mCharacter(inCharacter), mIgnoredContacts(inIgnoredContacts), mContact(outContact) { }
584
585
virtual void SetUserData(uint64 inUserData) override { mOtherCharacter = reinterpret_cast<CharacterVirtual *>(inUserData); }
586
587
virtual void AddHit(const ShapeCastResult &inResult) override;
588
589
RVec3 mBaseOffset;
590
Vec3 mDisplacement;
591
Vec3 mUp;
592
PhysicsSystem * mSystem;
593
const CharacterVirtual * mCharacter;
594
CharacterVirtual * mOtherCharacter = nullptr;
595
const IgnoredContactList & mIgnoredContacts;
596
Contact & mContact;
597
};
598
599
// Helper function to convert a Jolt collision result into a contact
600
template <class taCollector>
601
inline static void sFillContactProperties(const CharacterVirtual *inCharacter, Contact &outContact, const Body &inBody, Vec3Arg inUp, RVec3Arg inBaseOffset, const taCollector &inCollector, const CollideShapeResult &inResult);
602
inline static void sFillCharacterContactProperties(Contact &outContact, const CharacterVirtual *inOtherCharacter, RVec3Arg inBaseOffset, const CollideShapeResult &inResult);
603
604
// Move the shape from ioPosition and try to displace it by inVelocity * inDeltaTime, this will try to slide the shape along the world geometry
605
void MoveShape(RVec3 &ioPosition, Vec3Arg inVelocity, float inDeltaTime, ContactList *outActiveContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator
606
#ifdef JPH_DEBUG_RENDERER
607
, bool inDrawConstraints = false
608
#endif // JPH_DEBUG_RENDERER
609
);
610
611
// Ask the callback if inContact is a valid contact point
612
bool ValidateContact(const Contact &inContact) const;
613
614
// Trigger the contact callback for inContact and get the contact settings
615
void ContactAdded(const Contact &inContact, CharacterContactSettings &ioSettings);
616
617
// Tests the shape for collision around inPosition
618
void GetContactsAtPosition(RVec3Arg inPosition, Vec3Arg inMovementDirection, const Shape *inShape, TempContactList &outContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const;
619
620
// Remove penetrating contacts with the same body that have conflicting normals, leaving these will make the character mover get stuck
621
void RemoveConflictingContacts(TempContactList &ioContacts, IgnoredContactList &outIgnoredContacts) const;
622
623
// Convert contacts into constraints. The character is assumed to start at the origin and the constraints are planes around the origin that confine the movement of the character.
624
void DetermineConstraints(TempContactList &inContacts, float inDeltaTime, ConstraintList &outConstraints) const;
625
626
// Use the constraints to solve the displacement of the character. This will slide the character on the planes around the origin for as far as possible.
627
void SolveConstraints(Vec3Arg inVelocity, float inDeltaTime, float inTimeRemaining, ConstraintList &ioConstraints, IgnoredContactList &ioIgnoredContacts, float &outTimeSimulated, Vec3 &outDisplacement, TempAllocator &inAllocator
628
#ifdef JPH_DEBUG_RENDERER
629
, bool inDrawConstraints = false
630
#endif // JPH_DEBUG_RENDERER
631
);
632
633
// Get the velocity of a body adjusted by the contact listener
634
void GetAdjustedBodyVelocity(const Body& inBody, Vec3 &outLinearVelocity, Vec3 &outAngularVelocity) const;
635
636
// Calculate the ground velocity of the character assuming it's standing on an object with specified linear and angular velocity and with specified center of mass.
637
// Note that we don't just take the point velocity because a point on an object with angular velocity traces an arc,
638
// so if you just take point velocity * delta time you get an error that accumulates over time
639
Vec3 CalculateCharacterGroundVelocity(RVec3Arg inCenterOfMass, Vec3Arg inLinearVelocity, Vec3Arg inAngularVelocity, float inDeltaTime) const;
640
641
// Handle contact with physics object that we're colliding against
642
bool HandleContact(Vec3Arg inVelocity, Constraint &ioConstraint, float inDeltaTime);
643
644
// Does a swept test of the shape from inPosition with displacement inDisplacement, returns true if there was a collision
645
bool GetFirstContactForSweep(RVec3Arg inPosition, Vec3Arg inDisplacement, Contact &outContact, const IgnoredContactList &inIgnoredContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const;
646
647
// Store contacts so that we have proper ground information
648
void StoreActiveContacts(const TempContactList &inContacts, TempAllocator &inAllocator);
649
650
// This function will determine which contacts are touching the character and will calculate the one that is supporting us
651
void UpdateSupportingContact(bool inSkipContactVelocityCheck, TempAllocator &inAllocator);
652
653
/// This function can be called after moving the character to a new colliding position
654
void MoveToContact(RVec3Arg inPosition, const Contact &inContact, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter, TempAllocator &inAllocator);
655
656
// This function returns the actual center of mass of the shape, not corrected for the character padding
657
inline RMat44 GetCenterOfMassTransform(RVec3Arg inPosition, QuatArg inRotation, const Shape *inShape) const
658
{
659
return RMat44::sRotationTranslation(inRotation, inPosition).PreTranslated(mShapeOffset + inShape->GetCenterOfMass()).PostTranslated(mCharacterPadding * mUp);
660
}
661
662
// This function returns the position of the inner rigid body
663
inline RVec3 GetInnerBodyPosition() const
664
{
665
return mPosition + (mRotation * mShapeOffset + mCharacterPadding * mUp);
666
}
667
668
// Move the inner rigid body to the current position
669
void UpdateInnerBodyTransform();
670
671
// ID
672
CharacterID mID;
673
674
// Our main listener for contacts
675
CharacterContactListener * mListener = nullptr;
676
677
// Interface to detect collision between characters
678
CharacterVsCharacterCollision * mCharacterVsCharacterCollision = nullptr;
679
680
// Movement settings
681
EBackFaceMode mBackFaceMode; // When colliding with back faces, the character will not be able to move through back facing triangles. Use this if you have triangles that need to collide on both sides.
682
float mPredictiveContactDistance; // How far to scan outside of the shape for predictive contacts. A value of 0 will most likely cause the character to get stuck as it cannot properly calculate a sliding direction anymore. A value that's too high will cause ghost collisions.
683
uint mMaxCollisionIterations; // Max amount of collision loops
684
uint mMaxConstraintIterations; // How often to try stepping in the constraint solving
685
float mMinTimeRemaining; // Early out condition: If this much time is left to simulate we are done
686
float mCollisionTolerance; // How far we're willing to penetrate geometry
687
float mCharacterPadding; // How far we try to stay away from the geometry, this ensures that the sweep will hit as little as possible lowering the collision cost and reducing the risk of getting stuck
688
uint mMaxNumHits; // Max num hits to collect in order to avoid excess of contact points collection
689
float mHitReductionCosMaxAngle; // Cos(angle) where angle is the maximum angle between two hits contact normals that are allowed to be merged during hit reduction. Default is around 2.5 degrees. Set to -1 to turn off.
690
float mPenetrationRecoverySpeed; // This value governs how fast a penetration will be resolved, 0 = nothing is resolved, 1 = everything in one update
691
bool mEnhancedInternalEdgeRemoval; // Set to indicate that extra effort should be made to try to remove ghost contacts (collisions with internal edges of a mesh). This is more expensive but makes bodies move smoother over a mesh with convex edges.
692
693
// Character mass (kg)
694
float mMass;
695
696
// Maximum force with which the character can push other bodies (N)
697
float mMaxStrength;
698
699
// An extra offset applied to the shape in local space. This allows applying an extra offset to the shape in local space.
700
Vec3 mShapeOffset = Vec3::sZero();
701
702
// Current position (of the base, not the center of mass)
703
RVec3 mPosition = RVec3::sZero();
704
705
// Current rotation (of the base, not of the center of mass)
706
Quat mRotation = Quat::sIdentity();
707
708
// Current linear velocity
709
Vec3 mLinearVelocity = Vec3::sZero();
710
711
// List of contacts that were active in the last frame
712
ContactList mActiveContacts;
713
714
// Remembers how often we called StartTrackingContactChanges
715
int mTrackingContactChanges = 0;
716
717
// View from a contact listener perspective on which contacts have been added/removed
718
struct ListenerContactValue
719
{
720
ListenerContactValue() = default;
721
explicit ListenerContactValue(const CharacterContactSettings &inSettings) : mSettings(inSettings) { }
722
723
CharacterContactSettings mSettings;
724
int mCount = 0;
725
};
726
727
using ListenerContacts = UnorderedMap<ContactKey, ListenerContactValue>;
728
ListenerContacts mListenerContacts;
729
730
// Remembers the delta time of the last update
731
float mLastDeltaTime = 1.0f / 60.0f;
732
733
// Remember if we exceeded the maximum number of hits and had to remove similar contacts
734
mutable bool mMaxHitsExceeded = false;
735
736
// User data, can be used for anything by the application
737
uint64 mUserData = 0;
738
739
// The inner rigid body that proxies the character in the world
740
BodyID mInnerBodyID;
741
};
742
743
JPH_NAMESPACE_END
744
745