Revision control

Copy as Markdown

// Copyright (C) 2026 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QtQuick
import QtQuick3D
import QtQuick3D.Helpers
import QtQuick3D.Physics
// A CharacterController falls onto a static floor while a batch of unrelated static
// obstacles is repeatedly added and removed elsewhere in the scene, simulating runtime
// chunk streaming. CharacterController's ground detection is implemented internally by
// PhysX as a scene overlap query against static geometry, so this is the actual code path
// PhysicsWorld.staticQueryStructure and PhysicsWorld.dynamicQueryStructure affects (it has no effect on rigid-body
// contact/collision detection during simulation).
View3D {
id: viewport
property alias staticQueryStructure: world.staticQueryStructure
property alias dynamicQueryStructure: world.dynamicQueryStructure
property alias collisions: character.collisions
environment: SceneEnvironment {
clearColor: "#d6dbdf"
backgroundMode: SceneEnvironment.Color
}
PerspectiveCamera {
position: Qt.vector3d(0, 5, 15)
eulerRotation: Qt.vector3d(-20, 0, 0)
clipFar: 100
clipNear: 0.01
}
DirectionalLight {
eulerRotation.x: -45
eulerRotation.y: 45
castsShadow: false
brightness: 1
}
PhysicsWorld {
id: world
scene: viewport.scene
gravity: Qt.vector3d(0, -9.81, 0)
running: true
typicalLength: 1
typicalSpeed: 10
}
StaticRigidBody {
position: Qt.vector3d(0, -1, 0)
collisionShapes: BoxShape { extents: Qt.vector3d(20, 1, 20) }
Model {
source: "#Cube"
scale: Qt.vector3d(0.2, 0.01, 0.2)
materials: PrincipledMaterial { baseColor: "green" }
}
}
CharacterController {
id: character
position: Qt.vector3d(0, 5, 0)
gravity: world.gravity
collisionShapes: CapsuleShape {
height: 1
diameter: 1
}
Model {
eulerRotation.z: 90
scale: Qt.vector3d(0.01, 0.01, 0.01)
geometry: CapsuleGeometry {}
materials: PrincipledMaterial { baseColor: "blue" }
}
}
Node { id: obstacleRoot }
Component {
id: staticObstacleComponent
StaticRigidBody {
collisionShapes: BoxShape { extents: Qt.vector3d(1, 1, 1) }
Model {
source: "#Cube"
scale: Qt.vector3d(0.01, 0.01, 0.01)
materials: PrincipledMaterial { baseColor: "gray" }
}
}
}
Component {
id: dynamicObstacleComponent
DynamicRigidBody {
collisionShapes: BoxShape { extents: Qt.vector3d(1, 1, 1) }
Model {
source: "#Cube"
scale: Qt.vector3d(0.01, 0.01, 0.01)
materials: PrincipledMaterial { baseColor: "red" }
}
}
}
// Periodically spawns and destroys a batch of static obstacles so that static
// actors keep getting added and removed at runtime while the ground-detection
// check above is being exercised.
Timer {
interval: 100
running: true
repeat: true
property var obstacles: []
onTriggered: {
obstacles.forEach(o => o.destroy())
obstacles = []
for (let i = 0; i < 20; ++i) {
const obj = staticObstacleComponent.createObject(obstacleRoot, {
position: Qt.vector3d(Math.floor((Math.random() - 0.5) * 20) ,
Math.floor((Math.random() ) * 10),
Math.floor((Math.random() - 0.5) * 20))
})
obstacles.push(obj)
}
for (let j = 0; j < 20; ++j) {
const obj = dynamicObstacleComponent.createObject(obstacleRoot, {
position: Qt.vector3d(Math.floor((Math.random() - 0.5) * 20),
Math.floor((Math.random()) * 10),
Math.floor((Math.random() - 0.5) * 20))
})
obstacles.push(obj)
}
}
}
}