Revision control
++ // Copyright (C) 2023 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ // A scene with a character controller getting resized until it triggers
++ // boxes and can move over an obstacle.
++
++ import QtCore
++ import QtQuick
++ import QtTest
++ import QtQuick3D
++ import QtQuick3D.Helpers
++ import QtQuick3D.Physics
++ import QtQuick3D.Physics.TestUtils
++
++ Item {
++ width: 640
++ height: 480
++ visible: true
++
++ PhysicsWorld {
++ id: world
++ gravity: Qt.vector3d(0, -9.82, 0)
++ running: true
++ forceDebugDraw: true
++ typicalLength: 1
++ typicalSpeed: 10
++ scene: viewport.scene
++ }
++
++ View3D {
++ id: viewport
++ anchors.fill: parent
++
++ environment: SceneEnvironment {
++ clearColor: "#151a3f"
++ backgroundMode: SceneEnvironment.Color
++ }
++
++ PerspectiveCamera {
++ id: camera1
++ position: Qt.vector3d(0, 5, 10)
++ eulerRotation: Qt.vector3d(-20, 0, 0)
++ clipFar: 50
++ clipNear: 0.01
++ }
++
++ DirectionalLight {
++ eulerRotation.x: -45
++ eulerRotation.y: 45
++ }
++
++ StaticRigidBody {
++ collisionShapes: BoxShape {
++ extents: Qt.vector3d(8, 2, 4)
++ }
++ }
++
++ StaticRigidBody {
++ collisionShapes: BoxShape {
++ extents: Qt.vector3d(2, 1, 4)
++ }
++ position: Qt.vector3d(0, 2, 0)
++ }
++
++ TriggerBody {
++ id: triggerBoxUp
++ position: Qt.vector3d(2, 5, 0)
++ collisionShapes: BoxShape {
++ extents: Qt.vector3d(2, 1, 2)
++ }
++ receiveTriggerReports: true
++ property bool entered: false
++ onBodyEntered: function(body) {
++ entered = true
++ }
++ }
++
++ TriggerBody {
++ id: triggerBoxSide
++ position: Qt.vector3d(3.5, 2, 0)
++ collisionShapes: BoxShape {
++ extents: Qt.vector3d(1, 1, 1)
++ }
++ receiveTriggerReports: true
++ property bool entered: false
++ onBodyEntered: function(body) {
++ entered = true
++ }
++ }
++
++ TriggerBody {
++ id: triggerBoxStep
++ position: Qt.vector3d(-6, 3, 0)
++ collisionShapes: BoxShape {
++ extents: Qt.vector3d(2, 1, 2)
++ }
++ receiveTriggerReports: true
++ property bool entered: false
++ onBodyEntered: function(body) {
++ entered = true
++ }
++ }
++
++ CharacterController {
++ id: character
++ property bool collided: false
++ position: Qt.vector3d(2, 2, 0)
++
++ gravity: world.gravity
++ onCollisionsChanged: {
++ collided = true;
++ }
++
++ sendTriggerReports: true
++
++ Connections {
++ target: world
++ property real totalAnimationTime: 5000
++ function onFrameDone(timeStep) {
++ let progressStep = timeStep / totalAnimationTime
++ animationController.progress += progressStep
++ if (animationController.progress >= 1) {
++ animationController.completeToEnd()
++ }
++ }
++ }
++
++ AnimationController {
++ id: animationController
++ animation: ParallelAnimation {
++ NumberAnimation {
++ target: capsuleShape
++ property: "height"
++ to: 2
++ from: 1
++ duration: 5000
++ }
++ NumberAnimation {
++ target: capsuleShape
++ property: "diameter"
++ to: 3
++ from: 1
++ duration: 3000
++ }
++ }
++ }
++
++ collisionShapes: CapsuleShape {
++ id: capsuleShape
++ height: 1
++ diameter: 1
++ }
++
++ movement.x: -1;
++
++ Model {
++ eulerRotation.z: 90
++ //scale: Qt.vector3d(0.01, 0.01, 0.01)
++ geometry: CapsuleGeometry {
++ height: capsuleShape.height
++ diameter: capsuleShape.diameter
++ }
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ }
++
++ PhysicsTestCase {
++ name: "character up"
++ goalReached: character.collisions === CharacterController.Down
++ }
++
++ PhysicsTestCase {
++ name: "trigger box up"
++ goalReached: triggerBoxUp.entered
++ }
++
++ PhysicsTestCase {
++ name: "trigger box side"
++ goalReached: triggerBoxSide.entered
++ }
++
++ PhysicsTestCase {
++ name: "trigger box step"
++ goalReached: triggerBoxStep.entered
++ }
++ }
++ }