Qt Quick 3D Physics - CharacterController Example
// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause import QtQuick import QtQuick3D Item { id: root property real xSpeed: 0.1 property real ySpeed: 0.1 property bool xInvert: false property bool yInvert: true property bool mouseEnabled: true property bool keysEnabled: true readonly property bool inputsNeedProcessing: status.useMouse property alias acceptedButtons: dragHandler.acceptedButtons implicitWidth: parent.width implicitHeight: parent.height focus: keysEnabled property bool moveForwards: false property bool moveBackwards: false property bool moveLeft: false property bool moveRight: false property bool moveUp: false property bool moveDown: false property vector2d cameraRotation: Qt.vector2d(0, 0) property bool sprintActive: false property bool crouchActive: false DragHandler { id: dragHandler target: null enabled: mouseEnabled onCentroidChanged: { mouseMoved(Qt.vector2d(centroid.position.x, centroid.position.y)) } onActiveChanged: { if (active) mousePressed(Qt.vector2d(centroid.position.x, centroid.position.y)) else mouseReleased(Qt.vector2d(centroid.position.x, centroid.position.y)) } } TapHandler { onTapped: root.forceActiveFocus() } Keys.onPressed: (event) => { if (keysEnabled) handleKeyPress(event) } Keys.onReleased: (event) => { if (keysEnabled) handleKeyRelease(event) } function mousePressed(newPos) { root.forceActiveFocus() status.currentPos = newPos status.lastPos = newPos status.useMouse = true } function mouseReleased(newPos) { status.useMouse = false } function mouseMoved(newPos) { status.currentPos = newPos } function forwardPressed() { moveForwards = true moveBackwards = false } function forwardReleased() { moveForwards = false } function backPressed() { moveBackwards = true moveForwards = false } function backReleased() { moveBackwards = false } function rightPressed() { moveRight = true moveLeft = false } function rightReleased() { moveRight = false } function leftPressed() { moveLeft = true moveRight = false } function leftReleased() { moveLeft = false } function upPressed() { moveUp = true moveDown = false } function upReleased() { moveUp = false } function downPressed() { moveDown = true moveUp = false } function downReleased() { moveDown = false } function sprintPressed() { sprintActive = true crouchActive = false } function sprintReleased() { sprintActive = false } function sneakPressed() { crouchActive = true sprintActive = false } function sneakReleased() { crouchActive = false } function handleKeyPress(event) { switch (event.key) { case Qt.Key_W: case Qt.Key_Up: forwardPressed() break case Qt.Key_S: case Qt.Key_Down: backPressed() break case Qt.Key_A: case Qt.Key_Left: leftPressed() break case Qt.Key_D: case Qt.Key_Right: rightPressed() break case Qt.Key_R: case Qt.Key_PageUp: upPressed() break case Qt.Key_F: case Qt.Key_PageDown: downPressed() break case Qt.Key_Shift: sprintPressed() break case Qt.Key_Control: sneakPressed() break } } function handleKeyRelease(event) { switch (event.key) { case Qt.Key_W: case Qt.Key_Up: forwardReleased() break case Qt.Key_S: case Qt.Key_Down: backReleased() break case Qt.Key_A: case Qt.Key_Left: leftReleased() break case Qt.Key_D: case Qt.Key_Right: rightReleased() break case Qt.Key_R: case Qt.Key_PageUp: upReleased() break case Qt.Key_F: case Qt.Key_PageDown: downReleased() break case Qt.Key_Shift: sprintReleased() break case Qt.Key_Control: sneakReleased() break } } Timer { id: updateTimer interval: 16 repeat: true running: root.inputsNeedProcessing onTriggered: { processInputs() } } function processInputs() { if (root.inputsNeedProcessing) status.processInput() } QtObject { id: status property bool useMouse: false property vector2d lastPos: Qt.vector2d(0, 0) property vector2d currentPos: Qt.vector2d(0, 0) function processInput() { if (useMouse) { // Get the delta var delta = Qt.vector2d(lastPos.x - currentPos.x, lastPos.y - currentPos.y) // rotate x var rotateX = delta.x * xSpeed if (xInvert) rotateX = -rotateX cameraRotation.x += rotateX // rotate y var rotateY = delta.y * -ySpeed if (yInvert) rotateY = -rotateY cameraRotation.y += rotateY lastPos = currentPos } } } }