- Qt 6.4
- Qt Quick 3D Physics
- Qt Quick 3D Physics Examples and Tutorials
- Qt Quick 3D Physics - Cannon Example
- Qt Quick 3D Physics | Commercial or GPLv3

# Qt Quick 3D Physics - Cannon Example

     // Copyright (C) 2022 The Qt Company Ltd.
     // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
     import QtQuick
     import QtQuick3D
     import QtQuick3D.Physics
     import QtQuick3D.Helpers
     import QtQuick.Controls
     import QtQuick.Layouts

     Window {
         id: appWindow
         width: 800
         height: 600
         visible: true
         title: qsTr("Qt Quick 3D Physics - Cannon")

         DynamicsWorld {}

         View3D {
             width: parent.width
             height: parent.height
             focus: true

             environment: SceneEnvironment {
                 antialiasingMode: SceneEnvironment.MSAA
                 backgroundMode: SceneEnvironment.Color
                 clearColor: "#f0f0f0"
             }

             PerspectiveCamera {
                 id: camera
                 position: Qt.vector3d(-4000, 5000, 10000)
                 eulerRotation : Qt.vector3d(-20, -20, 0)
                 clipFar: 500000
                 clipNear: 100
             }

             DirectionalLight {
                 eulerRotation: Qt.vector3d(-45, 45, 0)
                 castsShadow: true
                 brightness: 1
                 shadowMapQuality: Light.ShadowMapQualityVeryHigh
                 shadowFactor: 100
             }

             StaticRigidBody {
                 eulerRotation: Qt.vector3d(-90, 0, 0)
                 collisionShapes: PlaneShape {}
                 Model {
                     source: "#Rectangle"
                     scale: Qt.vector3d(2000, 2000, 0)
                     materials: PrincipledMaterial {
                         baseColor: "green"
                     }
                     castsShadows: false
                     receivesShadows: true
                 }
             }

             Node {
                 id: shapeSpawner
                 property var instancesBoxes: []
                 property var instancesSpheres: []
                 property int stackCount: 0

                 function createStack(stackZ) {
                     var size = 10;
                     var extents = 400;

                     for (var i = 0; i < size; i++) {
                         for (var j = 0; j < size-i; j++) {
                             var component = Qt.createComponent("box.qml");
                             let x = j*2 - size + i;
                             let y = i*2 + 1;
                             let z = -5*stackZ;
                             let center = Qt.vector3d(x, y, z).times(0.5*extents);
                             let box = component.createObject(shapeSpawner, {position: center, xyzExtents: extents});
                             instancesBoxes.push(box);

                             if (box === null) {
                                 console.log("Error creating object");
                             }
                         }
                     }
                 }

                 function createBall(position, forward) {
                     var diameter = 600;
                     var speed = 20000;
                     var component = Qt.createComponent("sphere.qml");
                     let sphere = component.createObject(shapeSpawner, {position: position, linearVelocity: forward.times(speed), sphereDiameter: diameter});
                     instancesSpheres.push(sphere);

                     if (sphere === null) {
                         console.log("Error creating object");
                     }
                 }

                 function reset() {
                     instancesSpheres.forEach(sphere => { sphere.destroy(); });
                     instancesBoxes.forEach(boxes => { boxes.destroy(); });
                     instancesSpheres = [];
                     instancesBoxes = [];

                     for (var stackI = 0; stackI < stackSlider.value; stackI++) {
                         shapeSpawner.createStack(stackI);
                     }
                 }
             }
             Crosshair {
                 id: crossHair
                 anchors.centerIn: parent
             }
         }

         Component.onCompleted: {
             shapeSpawner.reset()
         }

         WasdController {
             speed: 100
             controlledObject: camera
             Keys.onPressed: (event)=> {
                                 handleKeyPress(event);
                                 if (event.key === Qt.Key_Space) {
                                     shapeSpawner.createBall(camera.position, camera.forward);
                                 }
                             }
             Keys.onReleased: (event)=> { handleKeyRelease(event) }
         }

         Frame {
             background: Rectangle {
                 color: "#c0c0c0"
                 border.color: "#202020"
             }
             anchors.top: parent.top
             anchors.left: parent.left
             anchors.margins: 10

             ColumnLayout {
                 Label {
                     text: "No. Stacks: " + stackSlider.value.toFixed(0)
                 }
                 Slider {
                     id: stackSlider
                     focusPolicy: Qt.NoFocus
                     from: 1
                     to: 9
                     value: 4
                     stepSize: 1
                     snapMode: Slider.SnapOnRelease
                 }
                 Button {
                     id: resetButton
                     Layout.alignment: Qt.AlignHCenter
                     text: "Reset scene"
                     onClicked: shapeSpawner.reset()
                 }
                 Button {
                     id: fireButton
                     Layout.alignment: Qt.AlignHCenter
                     text: "Fire!"
                     onClicked: shapeSpawner.createBall(camera.position, camera.forward)
                 }
             }
         }

     }