Revision control
++ // Copyright (C) 2023 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ // Tests the callback methods.
++ //
++ // 00) dynamic vs static
++ // 01) dynamic vs kinematic
++ // 02) dynamic vs character
++ // 03) dynamic vs dynamic
++ //
++ // 10) character vs dynamic (no callback)
++ // 11) character vs static (no callback)
++ // 12) character vs kinematic (no callback)
++ // 13) character vs character (no callback)
++ //
++ // 20) character vs dynamic (onShapeHit)
++ // 21) character vs static (onShapeHit)
++ // 22) character vs kinematic (onShapeHit)
++ // 23) character vs character (onShapeHit no callback)
++ //
++ // 30) kinematic vs static (no callback)
++ // 31) kinematic vs kinematic (no callback)
++ // 32) kinematic vs character (no callback)
++ // 33) kinematic vs dynamic
++
++ import QtCore
++ import QtQuick
++ import QtTest
++ import QtQuick3D
++ import QtQuick3D.Helpers
++ import QtQuick3D.Physics
++ import QtQuick3D.Physics.TestUtils
++
++ Item {
++ id: testItem
++ property real sceneWidth: 200
++ property real sceneHeight: 200
++
++ function xy(i, j) {
++ return [j*testItem.sceneWidth, i*testItem.sceneHeight]
++ }
++ width: sceneWidth*4
++ height: sceneHeight*4
++ visible: true
++
++ //////////////////////////////////////////////////
++ // 00 dynamic vs static
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(0, 0)[0]
++ y: xy(0, 0)[1]
++ id: scene00
++ property bool contact: false
++
++ DynamicRigidBody {
++ position: Qt.vector3d(0, 600, 0)
++ collisionShapes: SphereShape {}
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene00.contact = true
++ }
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ }
++
++ StaticRigidBody {
++ position: Qt.vector3d(0, 0, 0)
++ collisionShapes: SphereShape {}
++ sendContactReports: true
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ }
++ }
++
++ PhysicsTestCase {
++ name: "dynamic vs static"
++ goalReached: scene00.contact
++ }
++
++ //////////////////////////////////////////////////
++ // 01 dynamic vs kinematic
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(0, 1)[0]
++ y: xy(0, 1)[1]
++ id: scene01
++ property bool contact: false
++
++ DynamicRigidBody {
++ position: Qt.vector3d(0, 600, 0)
++ collisionShapes: SphereShape {}
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene01.contact = true
++ }
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ }
++
++ DynamicRigidBody {
++ isKinematic: true
++ position: Qt.vector3d(0, 100, 0)
++ collisionShapes: SphereShape {}
++ sendContactReports: true
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ }
++ }
++
++ PhysicsTestCase {
++ name: "dynamic vs kinematic"
++ goalReached: scene01.contact
++ }
++
++ //////////////////////////////////////////////////
++ // 02 dynamic vs character
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(0, 2)[0]
++ y: xy(0, 2)[1]
++ id: scene02
++ property bool contact: false
++
++ DynamicRigidBody {
++ position: Qt.vector3d(0, 600, 0)
++ collisionShapes: SphereShape {}
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene02.contact = true
++ }
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ }
++
++ CharacterController {
++ position: Qt.vector3d(0, 50, 0)
++ sendContactReports: true
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ collisionShapes: CapsuleShape {}
++ }
++ }
++
++ PhysicsTestCase {
++ name: "dynamic vs character"
++ goalReached: scene02.contact
++ }
++
++
++ //////////////////////////////////////////////////
++ // 03 dynamic vs dynamic
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(0, 3)[0]
++ y: xy(0, 3)[1]
++ id: scene03
++ property bool contact: false
++
++ DynamicRigidBody {
++ position: Qt.vector3d(0, 600, 0)
++ collisionShapes: SphereShape {}
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene03.contact = true
++ }
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ }
++
++ DynamicRigidBody {
++ position: Qt.vector3d(0, 100, 0)
++ collisionShapes: SphereShape {}
++ sendContactReports: true
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ }
++ }
++
++ PhysicsTestCase {
++ name: "dynamic vs dynamic"
++ goalReached: scene03.contact
++ }
++
++ //////////////////////////////////////////////////
++ // 10 character vs dynamic (no callback)
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(1, 0)[0]
++ y: xy(1, 0)[1]
++ id: scene10
++ property bool contact: false
++
++ DynamicRigidBody {
++ position: Qt.vector3d(0, 0, 0)
++ collisionShapes: SphereShape {}
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene10.contact = true
++ }
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ }
++
++ CharacterController {
++ position: Qt.vector3d(0, 1000, 0)
++ sendContactReports: true
++ gravity: Qt.vector3d(0, -982, 0)
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ collisionShapes: CapsuleShape {}
++ }
++ }
++
++ PhysicsTestCase {
++ name: "character vs dynamic (no callback)"
++ goalReached: scene10.elapsedTime > 2000 && !scene10.contact
++ }
++
++ //////////////////////////////////////////////////
++ // 11 character vs static (no callback)
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(1, 1)[0]
++ y: xy(1, 1)[1]
++ id: scene11
++ property bool contact: false
++
++ StaticRigidBody {
++ position: Qt.vector3d(0, 0, 0)
++ collisionShapes: SphereShape {}
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene11.contact = true
++ }
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ }
++
++ CharacterController {
++ position: Qt.vector3d(0, 1000, 0)
++ sendContactReports: true
++ gravity: Qt.vector3d(0, -982, 0)
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ collisionShapes: CapsuleShape {}
++ }
++ }
++
++ PhysicsTestCase {
++ name: "character controller vs static (no callback)"
++ goalReached: scene11.elapsedTime > 2000 && !scene11.contact
++ }
++
++ //////////////////////////////////////////////////
++ // 12 character vs kinematic (no callback)
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(1, 2)[0]
++ y: xy(1, 2)[1]
++ id: scene12
++ property bool contact: false
++
++ DynamicRigidBody {
++ isKinematic: true
++ position: Qt.vector3d(0, 0, 0)
++ collisionShapes: SphereShape {}
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene12.contact = true
++ }
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ }
++
++ CharacterController {
++ position: Qt.vector3d(0, 1000, 0)
++ sendContactReports: true
++ gravity: Qt.vector3d(0, -982, 0)
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ collisionShapes: CapsuleShape {}
++ }
++ }
++
++ PhysicsTestCase {
++ name: "character vs kinematic (no callback)"
++ goalReached: scene12.elapsedTime > 2000 && !scene12.contact
++ }
++
++
++ //////////////////////////////////////////////////
++ // 13 character vs character (no callback)
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(1, 3)[0]
++ y: xy(1, 3)[1]
++ id: scene13
++ property bool contact: false
++
++ CharacterController {
++ position: Qt.vector3d(0, 0, 0)
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene13.contact = true
++ }
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ collisionShapes: CapsuleShape {}
++ }
++
++ CharacterController {
++ position: Qt.vector3d(0, 1000, 0)
++ sendContactReports: true
++ gravity: Qt.vector3d(0, -982, 0)
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ collisionShapes: CapsuleShape {}
++ }
++ }
++
++ PhysicsTestCase {
++ name: "character vs character (no callback)"
++ goalReached: scene13.elapsedTime > 2000 && !scene13.contact
++ }
++
++ //////////////////////////////////////////////////
++ // 20 character vs dynamic (onShapeHit)
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(2, 0)[0]
++ y: xy(2, 0)[1]
++ id: scene20
++ property bool contact: false
++
++ DynamicRigidBody {
++ position: Qt.vector3d(0, 0, 0)
++ collisionShapes: SphereShape {}
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ }
++
++ CharacterController {
++ position: Qt.vector3d(0, 1000, 0)
++ gravity: Qt.vector3d(0, -982, 0)
++ onShapeHit: () => {
++ scene20.contact = true
++ }
++ enableShapeHitCallback: true
++
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ collisionShapes: CapsuleShape {}
++ }
++ }
++
++ PhysicsTestCase {
++ name: "character vs dynamic (onShapeHit)"
++ goalReached: scene20.contact
++ }
++
++ //////////////////////////////////////////////////
++ // 21 character vs static (onShapeHit)
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(2, 1)[0]
++ y: xy(2, 1)[1]
++ id: scene21
++ property bool contact: false
++
++ StaticRigidBody {
++ position: Qt.vector3d(0, 0, 0)
++ collisionShapes: SphereShape {}
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ }
++
++ CharacterController {
++ position: Qt.vector3d(0, 1000, 0)
++ sendContactReports: true
++ gravity: Qt.vector3d(0, -982, 0)
++ onShapeHit: () => {
++ scene21.contact = true
++ }
++ enableShapeHitCallback: true
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ collisionShapes: CapsuleShape {}
++ }
++ }
++
++ PhysicsTestCase {
++ name: "character controller vs static (onShapeHit)"
++ goalReached: scene21.contact
++ }
++
++ //////////////////////////////////////////////////
++ // 22 character vs kinematic (onShapeHit)
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(2, 2)[0]
++ y: xy(2, 2)[1]
++ id: scene22
++ property bool contact: false
++
++ DynamicRigidBody {
++ isKinematic: true
++ position: Qt.vector3d(0, 0, 0)
++ collisionShapes: SphereShape {}
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ }
++
++ CharacterController {
++ position: Qt.vector3d(0, 1000, 0)
++ gravity: Qt.vector3d(0, -982, 0)
++ onShapeHit: () => {
++ scene22.contact = true
++ }
++ enableShapeHitCallback: true
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ collisionShapes: CapsuleShape {}
++ }
++ }
++
++ PhysicsTestCase {
++ name: "character vs kinematic (onShapeHit)"
++ goalReached: scene22.contact
++ }
++
++
++ //////////////////////////////////////////////////
++ // 23 character vs character (onShapeHit no callback)
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(2, 3)[0]
++ y: xy(2, 3)[1]
++ id: scene23
++ property bool contact: false
++
++ CharacterController {
++ position: Qt.vector3d(0, 0, 0)
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ collisionShapes: CapsuleShape {}
++ }
++
++ CharacterController {
++ position: Qt.vector3d(0, 1000, 0)
++ gravity: Qt.vector3d(0, -982, 0)
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ onShapeHit: () => {
++ scene23.contact = true
++ }
++ enableShapeHitCallback: true
++ collisionShapes: CapsuleShape {}
++ }
++ }
++
++ PhysicsTestCase {
++ name: "character vs character (onShapeHit no callback)"
++ goalReached: scene23.elapsedTime > 2000 && !scene23.contact
++ }
++
++
++ //////////////////////////////////////////////////
++ // 30 kinematic vs static (no callback)
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(3, 0)[0]
++ y: xy(3, 0)[1]
++ id: scene30
++ property bool contact: false
++
++ DynamicRigidBody {
++ id: scene30Sphere
++ position: Qt.vector3d(0, 600, 0)
++ collisionShapes: SphereShape {}
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene30.contact = true
++ }
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++
++ isKinematic: true
++ kinematicPosition: Qt.vector3d(0, Math.max(600 - scene30.elapsedTime, 0), 0)
++ }
++
++ StaticRigidBody {
++ position: Qt.vector3d(0, 0, 0)
++ collisionShapes: SphereShape {}
++ sendContactReports: true
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ }
++ }
++
++ PhysicsTestCase {
++ name: "kinematic vs static (no callback)"
++ goalReached: !scene30.contact && scene30.elapsedTime > 2000
++ }
++
++ //////////////////////////////////////////////////
++ // 31 kinematic vs kinematic (no callback)
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(3, 1)[0]
++ y: xy(3, 1)[1]
++ id: scene31
++ property bool contact: false
++
++ DynamicRigidBody {
++ position: Qt.vector3d(0, 600, 0)
++ collisionShapes: SphereShape {}
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene31.contact = true
++ }
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++
++ isKinematic: true
++ kinematicPosition: Qt.vector3d(0, Math.max(600 - scene30.elapsedTime, 0), 0)
++ }
++
++ DynamicRigidBody {
++ isKinematic: true
++ position: Qt.vector3d(0, 100, 0)
++ collisionShapes: SphereShape {}
++ sendContactReports: true
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ }
++ }
++
++ PhysicsTestCase {
++ name: "kinematic vs kinematic (no callback)"
++ goalReached: !scene31.contact && scene31.elapsedTime > 2000
++ }
++
++ //////////////////////////////////////////////////
++ // 32 kinematic vs character (no callback)
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(3, 2)[0]
++ y: xy(3, 2)[1]
++ id: scene32
++ property bool contact: false
++
++ DynamicRigidBody {
++ position: Qt.vector3d(0, 600, 0)
++ collisionShapes: SphereShape {}
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene32.contact = true
++ }
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++
++ isKinematic: true
++ kinematicPosition: Qt.vector3d(0, Math.max(600 - scene30.elapsedTime, 0), 0)
++ }
++
++ CharacterController {
++ position: Qt.vector3d(0, 50, 0)
++ sendContactReports: true
++ Model {
++ eulerRotation.z: 90
++ geometry: CapsuleGeometry {}
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ collisionShapes: CapsuleShape {}
++ }
++ }
++
++ PhysicsTestCase {
++ name: "kinematic vs character (no callback)"
++ goalReached: !scene32.contact && scene32.elapsedTime > 2000
++ }
++
++
++ //////////////////////////////////////////////////
++ // 33 kinematic vs dynamic
++
++ PlaneScene {
++ width: parent.sceneWidth
++ height: parent.sceneHeight
++ x: xy(3, 3)[0]
++ y: xy(3, 3)[1]
++ id: scene33
++ property bool contact: false
++
++ DynamicRigidBody {
++ position: Qt.vector3d(0, 600, 0)
++ collisionShapes: SphereShape {}
++ receiveContactReports: true
++ onBodyContact: () => {
++ scene33.contact = true
++ }
++
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "red"
++ }
++ }
++ }
++
++ DynamicRigidBody {
++ position: Qt.vector3d(0, 100, 0)
++ collisionShapes: SphereShape {}
++ sendContactReports: true
++ Model {
++ source: "#Sphere"
++ materials: PrincipledMaterial {
++ baseColor: "blue"
++ }
++ }
++ }
++ }
++
++ PhysicsTestCase {
++ name: "kinematic vs dynamic"
++ goalReached: scene33.contact
++ }
++
++ //////////////////////////////////////////////////
++ }
++