QtQuick3D物体顺逆时针顺序旋转动画问题求助
QtQuick3D实现物体交替顺逆时针旋转的解决方法
为啥你的代码只执行最后一次旋转?
你用的for循环是同步执行的,JS会瞬间跑完所有6次迭代,angle变量直接被最后一次赋值(i=5时为-360)覆盖;同时每次调用start.restart()都会立刻终止当前运行的动画,最终就只剩最后一次设置的旋转效果。
两种可行的解决办法
办法1:用SequentialAnimation串联所有动画
直接创建一个顺序动画,把6次旋转的动画按顺序加入,动画会自动依次执行:
import QtQuick 2.15 import QtQuick.Window 2.14 import QtQuick3D 1.15 import QtQuick.Controls 2.14 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") visibility: "Maximized" property int scl: 5 Node{ id: standAloneScene DirectionalLight { ambientColor: Qt.rgba(1.0, 1.0, 1.0, 1.0) } Node { id: sphere Model { id: model_sphere source: "#Cube" x: 200 y: 100 z: 0 materials: [ DefaultMaterial { diffuseColor: Qt.rgba(0.053, 0.130, 0.219, 0.75) } ] } } // 定义可复用的单次旋转动画组件 Component { id: rotateAnimComponent ParallelAnimation { property int angleParam: 0 NumberAnimation { target: sphere property: "eulerRotation.y" from: sphere.eulerRotation.y to: sphere.eulerRotation.y + angleParam duration: 2000 easing.type: Easing.InOutQuad } NumberAnimation { target: model_sphere property: "eulerRotation.y" from: model_sphere.eulerRotation.y to: model_sphere.eulerRotation.y + 2*angleParam duration: 2000 easing.type: Easing.InOutQuad } } } // 顺序动画,按顺-逆-顺的顺序排列6次旋转 SequentialAnimation { id: rotateSequence rotateAnimComponent.createObject(standAloneScene, {angleParam: 360}) rotateAnimComponent.createObject(standAloneScene, {angleParam: -360}) rotateAnimComponent.createObject(standAloneScene, {angleParam: 360}) rotateAnimComponent.createObject(standAloneScene, {angleParam: -360}) rotateAnimComponent.createObject(standAloneScene, {angleParam: 360}) rotateAnimComponent.createObject(standAloneScene, {angleParam: -360}) } OrthographicCamera { id: cameraOrthographicFront eulerRotation.y: 45 eulerRotation.x: -45 x: 600 y: 800 z: 600 } } Rectangle { id: view anchors.top: parent.top anchors.left: parent.left width: parent.width height: parent.height color: "#848895" border.color: "black" View3D { id: topLeftView anchors.fill: parent importScene: standAloneScene camera: cameraOrthographicFront } Button { id: posmoveZ width: view.width/8 height: view.height/16 anchors.top: view.top anchors.right: view.right text: "start" font.pixelSize: height onClicked: { // 每次点击重置旋转角度,从头开始 sphere.eulerRotation.y = 0 model_sphere.eulerRotation.y = 0 rotateSequence.start() } } } }
办法2:利用动画结束信号递归触发下一次旋转
这种方式更灵活,修改循环次数只需改变量,还能方便添加暂停/中断逻辑:
import QtQuick 2.15 import QtQuick.Window 2.14 import QtQuick3D 1.15 import QtQuick.Controls 2.14 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") visibility: "Maximized" property int scl: 5 property int currentRotation: 0 property int totalRotations: 6 Node{ id: standAloneScene DirectionalLight { ambientColor: Qt.rgba(1.0, 1.0, 1.0, 1.0) } Node { id: sphere Model { id: model_sphere source: "#Cube" x: 200 y: 100 z: 0 materials: [ DefaultMaterial { diffuseColor: Qt.rgba(0.053, 0.130, 0.219, 0.75) } ] } } ParallelAnimation{ id: start running: false // 动画结束后触发下一次旋转 onFinished: { currentRotation++ if(currentRotation < totalRotations){ // 根据当前次数判断旋转方向 const angle = currentRotation % 2 === 0 ? 360 : -360 // 更新动画目标值,基于当前角度累加 sphereAnim.to = sphere.eulerRotation.y + angle modelAnim.to = model_sphere.eulerRotation.y + 2*angle start.start() } else { currentRotation = 0 // 重置计数,方便下次点击 } } NumberAnimation { id: sphereAnim target: sphere property: "eulerRotation.y" duration: 2000 easing.type: Easing.InOutQuad } NumberAnimation { id: modelAnim target: model_sphere property: "eulerRotation.y" duration: 2000 easing.type: Easing.InOutQuad } } OrthographicCamera { id: cameraOrthographicFront eulerRotation.y: 45 eulerRotation.x: -45 x: 600 y: 800 z: 600 } } Rectangle { id: view anchors.top: parent.top anchors.left: parent.left width: parent.width height: parent.height color: "#848895" border.color: "black" View3D { id: topLeftView anchors.fill: parent importScene: standAloneScene camera: cameraOrthographicFront } Button { id: posmoveZ width: view.width/8 height: view.height/16 anchors.top: view.top anchors.right: view.right text: "start" font.pixelSize: height onClicked: { // 重置状态,从头开始旋转 currentRotation = 0 sphere.eulerRotation.y = 0 model_sphere.eulerRotation.y = 0 // 设置第一次旋转的目标值 sphereAnim.to = 360 modelAnim.to = 720 start.start() } } } }
关键注意点
- 别用同步循环修改动画参数:JS循环执行速度极快,动画还没开始就被参数覆盖和中断了。
- 旋转要基于当前角度累加:如果直接设置固定的
to值,多次旋转后会回到初始角度,无法实现持续交替旋转。 - 方案选择:固定旋转次数用顺序动画更直观,需要动态调整次数或添加控制逻辑选递归触发的方式。
内容的提问来源于stack exchange,提问作者Vladimir
相关产品推荐
相关产品推荐

