Revision control

Copy as Markdown

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtCore
import QtQuick
import QtTest
import QtQuick3D
import QtQuick3D.Physics
import QtQuick3D.Physics.TestUtils
Item {
width: 640
height: 480
visible: true
PhysicsWorld {
id: world
gravity: Qt.vector3d(0, -9.81, 0)
running: true
forceDebugDraw: true
typicalLength: 1
typicalSpeed: 10
minimumTimestep: 15
maximumTimestep: 15
scene: viewport.scene
property real elapsedTime: 0
}
Connections {
target: world
function onFrameDone(timeStep) {
world.elapsedTime += timeStep
}
}
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
}
Node {
x: -5
TriggerBody {
position: Qt.vector3d(0, 3, 0)
collisionShapes: BoxShape {
extents: Qt.vector3d(1, 2, 1)
}
onBodyEntered: (body) => {
body.triggered = true;
boxCentre.simulationEnabled = false;
boxCentreLow.simulationEnabled = true;
collisionSphereLeft.simulationEnabled = false;
boxRight.simulationEnabled = true;
}
}
DynamicRigidBody {
id: collisionSphereLeft
massMode: DynamicRigidBody.CustomDensity
density: 1000
position: Qt.vector3d(0, 6, 0)
sendTriggerReports: true
simulationEnabled: false
property bool triggered: false
collisionShapes: SphereShape {
diameter: 1
}
Model {
source: "#Sphere"
materials: PrincipledMaterial {
baseColor: collisionSphereLeft.triggered ? "yellow" : "red"
}
scale: Qt.vector3d(0.01, 0.01, 0.01)
}
}
}
Node {
x: 0
DynamicRigidBody {
id: boxCentreLow
isKinematic: true
simulationEnabled: false
position: Qt.vector3d(0, -1, 0)
kinematicPosition: position
collisionShapes: BoxShape {
extents: Qt.vector3d(2,1,2)
}
Model {
source: "#Cube"
scale: Qt.vector3d(2, 1, 2).times(0.01)
eulerRotation: Qt.vector3d(0, 90, 0)
materials: PrincipledMaterial {
baseColor: "green"
}
}
receiveContactReports: true
sendContactReports: true
property bool hasCollided: false
onBodyContact: (body, positions, impulses, normals) => {
hasCollided = true
}
}
TriggerBody {
position: Qt.vector3d(0, 3, 0)
collisionShapes: BoxShape {
extents: Qt.vector3d(1, 2, 1)
}
onBodyEntered: (body) => {
body.triggered = true;
collisionSphereRight.simulationEnabled = true;
}
}
StaticRigidBody {
id: boxCentre
position: Qt.vector3d(0, 4.5, 0)
collisionShapes: BoxShape {
extents: Qt.vector3d(2,1,2)
}
Model {
source: "#Cube"
scale: Qt.vector3d(2, 1, 2).times(0.01)
eulerRotation: Qt.vector3d(0, 90, 0)
materials: PrincipledMaterial {
baseColor: "blue"
}
}
}
DynamicRigidBody {
id: collisionSphereCenter
massMode: DynamicRigidBody.CustomDensity
density: 1000
position: Qt.vector3d(0, 6, 0)
sendTriggerReports: true
sendContactReports: true
property bool triggered: false
collisionShapes: SphereShape {
diameter: 1
}
Model {
source: "#Sphere"
materials: PrincipledMaterial {
baseColor: collisionSphereCenter.triggered ? "yellow" : "red"
}
scale: Qt.vector3d(0.01, 0.01, 0.01)
}
}
}
Node {
id: triggerNode
x: 5
TriggerBody {
id: triggerBox
position: Qt.vector3d(0, 3, 0)
collisionShapes: BoxShape {
extents: Qt.vector3d(1, 2, 1)
}
onBodyEntered: (body) => {
body.triggered = true;
collisionSphereLeft.simulationEnabled = true;
collisionSphereRight.simulationEnabled = false;
}
}
DynamicRigidBody {
id: collisionSphereRight
massMode: DynamicRigidBody.CustomDensity
density: 1000
position: Qt.vector3d(0, 6, 0)
sendTriggerReports: true
property bool triggered: false
collisionShapes: SphereShape {
id: sphereShape
diameter: 1
}
Model {
source: "#Sphere"
materials: PrincipledMaterial {
baseColor: collisionSphereRight.triggered ? "yellow" : "red"
}
scale: Qt.vector3d(0.01, 0.01, 0.01)
}
}
StaticRigidBody {
id: boxRight
simulationEnabled: false
position: Qt.vector3d(0, 0, 0)
collisionShapes: BoxShape {
extents: Qt.vector3d(2,1,2)
}
Model {
source: "#Cube"
scale: Qt.vector3d(2, 1, 2).times(0.01)
eulerRotation: Qt.vector3d(0, 90, 0)
materials: PrincipledMaterial {
baseColor: "blue"
}
}
}
}
Node {
id: disabledNode
x: 10
// PhysX only rejects forces and impulses on a body with its simulation disabled
// in checked builds, and dereferences the simulation object such a body does not
// have in release ones, so make sure we never pass them on.
DynamicRigidBody {
id: disabledBody
simulationEnabled: false
position: Qt.vector3d(0, 6, 0)
collisionShapes: SphereShape {
diameter: 1
}
property bool commandsSent: false
function sendCommands() {
applyCentralForce(Qt.vector3d(0, 1000, 0));
applyForce(Qt.vector3d(0, 1000, 0), Qt.vector3d(0.1, 0, 0));
applyTorque(Qt.vector3d(0, 1000, 0));
applyCentralImpulse(Qt.vector3d(0, 1000, 0));
applyImpulse(Qt.vector3d(0, 1000, 0), Qt.vector3d(0.1, 0, 0));
applyTorqueImpulse(Qt.vector3d(0, 1000, 0));
commandsSent = true;
}
}
}
}
PhysicsTestCase {
name: "trigger right"
goalReached: collisionSphereRight.triggered
}
PhysicsTestCase {
name: "trigger left"
goalReached: collisionSphereLeft.triggered
}
PhysicsTestCase {
name: "trigger center"
goalReached: collisionSphereCenter.triggered
}
PhysicsTestCase {
name: "trigger right box"
goalReached: collisionSphereCenter.triggered
}
PhysicsTestCase {
name: "trigger center low box"
goalReached: boxCentreLow.hasCollided
}
Timer {
interval: 100
running: true
onTriggered: disabledBody.sendCommands()
}
PhysicsTestCase {
name: "disabled body ignores commands"
// The body must still be where it started: not simulated, and not moved by any of
// the forces and impulses applied to it.
goalReached: disabledBody.commandsSent && world.elapsedTime > 500
&& disabledBody.position.y === 6
}
}