Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qcharactercontroller.cpp
Go to the documentation of this file.
1
// Copyright (C) 2022 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
// Qt-Security score:significant reason:default
4
5
#
include
"qcharactercontroller_p.h"
6
#
include
"qphysicsutils_p.h"
7
8
#
include
"physxnode/qphysxcharactercontroller_p.h"
9
10
QT_BEGIN_NAMESPACE
11
12
/*!
13
\qmltype CharacterController
14
\inqmlmodule QtQuick3D.Physics
15
\inherits PhysicsBody
16
\since 6.4
17
\brief Controls the motion of a character.
18
19
The CharacterController type controls the motion of a character.
20
21
A character is an entity that moves under external control, but is still constrained
22
by physical barriers and (optionally) subject to gravity. This is in contrast to
23
\l{DynamicRigidBody}{dynamic rigid bodies} which are either completely controlled by
24
the physics simulation (for non-kinematic bodies); or move exactly where placed,
25
regardless of barriers (for kinematic objects).
26
27
To control the motion of a character controller, set \l movement to the desired velocity.
28
29
For a first-person view, the camera is typically placed inside a character controller.
30
31
\note \l {PhysicsNode::collisionShapes}{collisionShapes} must be set to
32
a single \l {CapsuleShape}. No other shapes are supported.
33
34
\note The character controller is able to scale obstacles that are lower than one fourth of
35
the capsule shape's height.
36
37
\sa {Qt Quick 3D Physics Shapes, Bodies and Joints}
38
*/
39
40
/*!
41
\qmlproperty vector3d CharacterController::movement
42
43
This property defines the controlled motion of the character. This is the velocity the character
44
would move in the absence of gravity and without interacting with other physics objects.
45
46
This property does not reflect the actual velocity of the character. If the character is stuck
47
against terrain, the character can move slower than the speed defined by \c movement. Conversely, if the
48
character is in free fall, it may move much faster.
49
50
Default value: \c{(0, 0, 0)}
51
*/
52
53
/*!
54
\qmlproperty vector3d CharacterController::gravity
55
56
This property defines the gravitational acceleration that applies to the character.
57
For a character that walks on the ground, it should typically be set to
58
\l{PhysicsWorld::gravity}{PhysicsWorld.gravity}. A floating character that has movement
59
controls in three dimensions will normally have gravity \c{(0, 0, 0)}.
60
61
Default value: \c{(0, 0, 0)}.
62
*/
63
64
/*!
65
\qmlproperty bool CharacterController::midAirControl
66
67
This property defines whether the \l movement property has effect when the character is in free
68
fall. This is only relevant if \l gravity in not null. A value of \c true means that the
69
character will change direction in mid-air when \c movement changes. A value of \c false means that
70
the character will continue on its current trajectory until it hits another object.
71
72
Default value: \c true
73
*/
74
75
/*!
76
\qmlproperty Collisions CharacterController::collisions
77
\readonly
78
79
This property holds the current collision state of the character. It is either \c None for no
80
collision, or an OR combination of \c Side, \c Up, and \c Down:
81
82
\value CharacterController.None
83
The character is not touching anything. If gravity is non-null, this means that the
84
character is in free fall.
85
\value CharacterController.Side
86
The character is touching something on its side.
87
\value CharacterController.Up
88
The character is touching something above it.
89
\value CharacterController.Down
90
The character is touching something below it. In standard gravity, this means
91
that the character is on the ground.
92
93
\note The directions are defined relative to standard gravity: \c Up is always along the
94
positive y-axis, regardless of the value of \l {gravity}{CharacterController.gravity}
95
or \l{PhysicsWorld::gravity}{PhysicsWorld.gravity}
96
*/
97
98
/*!
99
\qmlproperty bool CharacterController::enableShapeHitCallback
100
\since 6.6
101
102
This property enables/disables the \l {CharacterController::shapeHit} callback for this
103
character controller.
104
105
Default value: \c{false}
106
*/
107
108
/*!
109
\qmlmethod void CharacterController::teleport(vector3d position)
110
Immediately move the character to \a position without checking for collisions.
111
The caller is responsible for avoiding overlap with static objects.
112
*/
113
114
/*!
115
\qmlsignal CharacterController::shapeHit(PhysicsNode *body, vector3D position, vector3D impulse,
116
vector3D normal)
117
\since 6.6
118
119
This signal is emitted when \l {CharacterController::}{movement} has been
120
called and it would result
121
in a collision with a \l {DynamicRigidBody} or a \l {StaticRigidBody} and
122
\l {CharacterController::} {enableShapeHitCallback} is set to \c true.
123
The parameters \a body, \a position, \a impulse and \a normal contain the body, position,
124
impulse force and normal for the contact point.
125
*/
126
127
QCharacterController::QCharacterController() =
default
;
128
129
const
QVector3D &QCharacterController::movement()
const
130
{
131
return
m_movement;
132
}
133
134
void
QCharacterController::setMovement(
const
QVector3D &newMovement)
135
{
136
if
(!QPhysicsUtils::isFinite(newMovement)) {
137
qWarning() <<
"CharacterController: movement must be finite, ignoring"
<< newMovement;
138
return
;
139
}
140
141
if
(m_movement == newMovement)
142
return
;
143
m_movement = newMovement;
144
emit movementChanged();
145
}
146
147
const
QVector3D &QCharacterController::gravity()
const
148
{
149
return
m_gravity;
150
}
151
152
void
QCharacterController::setGravity(
const
QVector3D &newGravity)
153
{
154
if
(!QPhysicsUtils::isFinite(newGravity)) {
155
qWarning() <<
"CharacterController: gravity must be finite, ignoring"
<< newGravity;
156
return
;
157
}
158
159
if
(m_gravity == newGravity)
160
return
;
161
m_gravity = newGravity;
162
emit gravityChanged();
163
}
164
165
// Calculate move based on movement/gravity
166
167
QVector3D QCharacterController::getDisplacement(
float
deltaTime)
168
{
169
// Start with basic movement, assuming no other factors
170
QVector3D displacement = sceneRotation() * m_movement * deltaTime;
171
172
// modified based on gravity
173
const
auto
g = m_gravity;
174
if
(!g.isNull()) {
175
176
// Avoid "spider mode": we are also supposed to be in free fall if gravity
177
// is pointing away from a surface we are touching. I.e. we are NOT in free
178
// fall only if gravity has a component in the direction of one of the collisions.
179
// Also: if we have "upwards" free fall velocity, that motion needs to stop
180
// when we hit the "ceiling"; i.e we are not in free fall at the moment of impact.
181
auto
isGrounded = [
this
](){
182
if
(m_collisions == Collision::None)
183
return
false
;
184
185
// Standard gravity case first
186
if
(m_gravity.y() < 0) {
187
if
(m_collisions & Collision::Down)
188
return
true
;
// We land on the ground
189
if
((m_collisions & Collision::Up) && m_freeFallVelocity.y() > 0)
190
return
true
;
// We bump our head on the way up
191
}
192
193
// Inverse gravity next: exactly the opposite
194
if
(m_gravity.y() > 0) {
195
if
(m_collisions & Collision::Up)
196
return
true
;
197
if
((m_collisions & Collision::Down) && m_freeFallVelocity.y() < 0)
198
return
true
;
199
}
200
201
// The sideways gravity case can't be perfectly handled since we don't
202
// know the direction of sideway contacts. We could in theory inspect
203
// the mesh, but that is far too complex for an extremely marginal use case.
204
205
if
((m_gravity.x() != 0 || m_gravity.z() != 0) && m_collisions & Collision::Side)
206
return
true
;
207
208
return
false
;
209
};
210
211
bool
freeFalling = !isGrounded();
212
if
(freeFalling) {
213
if
(!m_midAirControl)
214
displacement = {};
// Ignore the movement() controls in true free fall
215
216
displacement += m_freeFallVelocity * deltaTime;
217
m_freeFallVelocity += g * deltaTime;
218
}
else
{
219
m_freeFallVelocity = displacement / deltaTime + g * deltaTime;
220
if
(m_midAirControl)
// free fall only straight down
221
m_freeFallVelocity =
222
QVector3D::dotProduct(m_freeFallVelocity, g.normalized()) * g.normalized();
223
}
224
const
QVector3D gravityAcceleration = 0.5 * deltaTime * deltaTime * g;
225
displacement += gravityAcceleration;
// always add gravitational acceleration, in case we start
226
// to fall. If we don't, PhysX will move us back to the ground.
227
}
228
229
return
displacement;
230
}
231
232
bool
QCharacterController::midAirControl()
const
233
{
234
return
m_midAirControl;
235
}
236
237
void
QCharacterController::setMidAirControl(
bool
newMidAirControl)
238
{
239
if
(m_midAirControl == newMidAirControl)
240
return
;
241
m_midAirControl = newMidAirControl;
242
emit midAirControlChanged();
243
}
244
245
void
QCharacterController::teleport(
const
QVector3D &position)
246
{
247
if
(!QPhysicsUtils::isFinite(position)) {
248
qWarning() <<
"CharacterController: teleport() position must be finite, ignoring"
249
<< position;
250
return
;
251
}
252
253
m_teleport =
true
;
254
m_teleportPosition = position;
255
m_freeFallVelocity = {};
256
}
257
258
bool
QCharacterController::getTeleport(QVector3D &position)
259
{
260
if
(m_teleport) {
261
position = m_teleportPosition;
262
m_teleport =
false
;
263
return
true
;
264
}
265
return
false
;
266
}
267
268
const
QCharacterController::Collisions &QCharacterController::collisions()
const
269
{
270
return
m_collisions;
271
}
272
273
void
QCharacterController::setCollisions(
const
Collisions &newCollisions)
274
{
275
if
(m_collisions == newCollisions)
276
return
;
277
m_collisions = newCollisions;
278
emit collisionsChanged();
279
}
280
281
bool
QCharacterController::enableShapeHitCallback()
const
282
{
283
return
m_enableShapeHitCallback;
284
}
285
286
QAbstractPhysXNode *QCharacterController::createPhysXBackend()
287
{
288
return
new
QPhysXCharacterController(
this
);
289
}
290
291
void
QCharacterController::setEnableShapeHitCallback(
bool
newEnableShapeHitCallback)
292
{
293
if
(m_enableShapeHitCallback == newEnableShapeHitCallback)
294
return
;
295
m_enableShapeHitCallback = newEnableShapeHitCallback;
296
emit enableShapeHitCallbackChanged();
297
}
298
299
QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
#define QT_BEGIN_NAMESPACE
Definition
qtconfigmacros.h:161
QT_END_NAMESPACE
#define QT_END_NAMESPACE
Definition
qtconfigmacros.h:162
qtquick3dphysics
src
quick3dphysics
qcharactercontroller.cpp
Generated on
for Qt by
1.18.0