73 Q_ASSERT(!controller);
75 auto *characterController =
static_cast<QCharacterController *>(frontendNode);
77 auto shapes = characterController->getCollisionShapesList();
78 if (shapes.length() != 1) {
79 qWarning() <<
"CharacterController: invalid collision shapes list.";
82 auto *capsule = qobject_cast<QCapsuleShape *>(shapes.first());
84 qWarning() <<
"CharacterController: collision shape is not a capsule.";
87 auto *mgr = world->controllerManager();
89 qWarning() <<
"QtQuick3DPhysics internal error: missing controller manager.";
95 const QVector3D scale = characterController->sceneScale();
96 const qreal heightScale = scale.y();
97 const qreal radiusScale = scale.x();
98 physx::PxCapsuleControllerDesc desc;
99 reportCallback =
new ControllerCallback(world);
100 desc.reportCallback = reportCallback;
101 desc.radius = 0.5f * radiusScale * capsule->diameter();
102 desc.height = heightScale * capsule->height();
103 desc.stepOffset = 0.25f * desc.height;
105 desc.material = material;
106 const QVector3D pos = characterController->scenePosition();
107 desc.position = { pos.x(), pos.y(), pos.z() };
110 controller =
static_cast<
physx::PxCapsuleController *>(mgr->createController(desc));
113 qWarning() <<
"QtQuick3DPhysics internal error: could not create controller.";
117 controller->setUserData(
static_cast<
void *>(frontendNode));
119 auto *actor = controller->getActor();
121 actor->userData = characterController;
123 qWarning() <<
"QtQuick3DPhysics internal error: CharacterController created without actor.";
127 QHash<QQuick3DNode *, QMatrix4x4> & )
129 if (controller ==
nullptr)
132 auto *characterController =
static_cast<QCharacterController *>(frontendNode);
135 const auto &shapes = characterController->getCollisionShapesList();
136 auto capsule = shapes.length() == 1 ? qobject_cast<QCapsuleShape *>(shapes.front()) :
nullptr;
138 if (shapes.length() != 1) {
139 qWarning() <<
"CharacterController: invalid collision shapes list.";
140 }
else if (!capsule) {
141 qWarning() <<
"CharacterController: collision shape is not a capsule.";
143 const QVector3D sceneScale = characterController->sceneScale();
144 const qreal heightScale = sceneScale.y();
145 const qreal radiusScale = sceneScale.x();
148 const float heightNew = heightScale * capsule->height();
150 const float radiusNew = 0.5f * radiusScale * capsule->diameter();
152 if (!qIsFinite(heightNew) || heightNew <= 0.f || !qIsFinite(radiusNew)
153 || radiusNew <= 0.f) {
154 qWarning() <<
"CharacterController: scaled capsule height/radius must be finite "
155 "and positive, ignoring.";
157 if (!qFuzzyCompare(controller->getHeight(), heightNew))
158 controller->resize(heightNew);
159 if (!qFuzzyCompare(controller->getRadius(), radiusNew))
160 controller->setRadius(radiusNew);
163 const float stepOffsetNew = 0.25f * heightNew;
164 if (!qFuzzyCompare(controller->getStepOffset(), stepOffsetNew))
165 controller->setStepOffset(stepOffsetNew);
169 QVector3D position = QPhysicsUtils::toQtType(physx::toVec3(controller->getPosition()));
170 const QQuick3DNode *parentNode =
static_cast<QQuick3DNode *>(characterController->parentItem());
173 characterController->setPosition(position);
175 characterController->setPosition(parentNode->mapPositionFromScene(position));
178 QVector3D teleportPos;
179 bool teleport = characterController->getTeleport(teleportPos);
181 controller->setPosition({ teleportPos.x(), teleportPos.y(), teleportPos.z() });
182 }
else if (deltaTime > 0) {
183 const auto displacement =
184 QPhysicsUtils::toPhysXType(characterController->getDisplacement(deltaTime));
186 controller->move(displacement, displacement.magnitude() / 100, deltaTime, {});
187 characterController->setCollisions(QCharacterController::Collisions(uint(collisions)));
192 if (updateMaterial() && material) {
193 physx::PxShape *shape =
nullptr;
194 auto *actor = controller->getActor();
196 if (actor && actor->getShapes(&shape, 1) == 1)
197 shape->setMaterials(&material, 1);