4

我编写了一个“游戏”,其中一个球被发送到墙上反弹。在伤害墙壁之前,y 上的行为是一个弹簧动画。当它撞到墙壁时,球应该会反弹并有线性运动。

我的问题是我无法停止最初的行为。

我尝试了几种方法:

  • 禁用该行为,但正在进行的运动继续
  • 停止 SpringAnimation:我有错误:“QML SpringAnimation:setRunning() 不能在非根动画节点上使用。”

这是代码

Rectangle {
    id: ball
    property bool enableMoving: false

    function newMousePos(mX,mY){
        if(enableMoving){
            ball.x = mX - ball.width/2
            ball.y = mY - ball.height/2
        }
    }

    Behavior on x {enabled: true;id: behavX; SpringAnimation {id:spX;  spring: 0.8; damping: 0.9; mass: 10; } }
    Behavior on y {enabled: true;id: behavY; SpringAnimation {id:spY;  spring: 0.8; damping: 0.9; mass: 10 ; } }


    onXChanged: {
        if(ball.x>main.width-ball.size) {
            console.log("wall 2 ")
            spX.stop(); spY.stop()
        }
        if(ball.x<0)  {
         ...
        }
       }
    onYChanged: {
       ...
       }
  Timer{
        id:timerDisableMoving
        interval: 500; running:true
        onTriggered: enableMoving=false
    } 
}

我不明白为什么我不能阻止这种行为。是否可以定义状态行为来解决问题?

4

2 回答 2

0

当球撞到墙上时,将此代码置于信号上:

behavX.enabled = false

这将禁用行为(我已经在我的项目中对其进行了测试)。

如果您只想禁用特定动画,请执行以下操作:

spX.running = false  //ignore this, it is equivalent to spX.stop()

我只是想你可能会这样写代码:

function disableBehavior()
{
  behavX.enabled = false
  //...
  behavX.enabled = true
}

如果是这种情况,那么它将不起作用,因为在执行动画期间不会发生。相反,您应该进行异步调用,例如:

function disableBehavior()
{
  behavX.enabled = false
  //...
  myTimer.start()
}

//...
Timer
{
  id: myTimer
  interval: 1
  running: false
  onTriggered:
  {
    behavX.enabled = true
    stop()
  }
}

但是,我认为在“线性行为”完成后(而不是创建新计时器),您会想要调用“行为启动器”。

于 2013-08-31T18:14:48.753 回答
0

我想,我有类似的问题。我有一些行为,它动画了一些属性的变化。我希望能够在它还没有完成的时候中途停止它。

那没起效。顺便说一句,QML 也在控制台中抱怨,我尝试在非根动画上使用一些方法。

简短的回答:看来,在中间停止的 Behavior 不支持它。

但是,可以通过为属性设置新值来中断它。这将重新启动动画以定位新值。当我意识到这一点时,我实现了这样的“停止”功能:

function stopAnimation() {
    // disable animation for the next value change
    moveBehavior.enabled = false 

    // Change value of the property of interest.
    // This stops currently running animation
    y += 1

    // Restore initial value of the property
    y -= 1

    // Enable animation for subsequent property changes
    moveBehavior.enabled = true
}

因此,我禁用该行为以立即更改属性。然后我将目标属性更改为非常接近当前值的值(我相信,我不能使用相同的值,因为不会发出“onChange”信号)。此时运行动画应该停止。然后我将属性重置为其原始值。然后再次启用动画以处理进一步的属性更改。

看起来不太好,但它对我的行为有用......

再想一想,我得出结论,我可能不应该使用 Behavior。然后我直接在需要移动的对象中创建了与我感兴趣的属性相关联的 PropertyAnimation{}。然后我只是动态地分配目标值和持续时间,现在“start()”和“stop()”就像预期的那样工作。

完整的解决方案看起来像这样(它的作用,你可能会弄清楚):

Item {
    id: root
    focus: true

    Rectangle {
        id: racket
        height: 40
        width: 10
        x: 20
        y: 20
        color: "blue"

        property int maxY: 460
        // ...

        PropertyAnimation {
            id: moveDownAnimation
            target: racket
            property: "y"
            to: racket.maxY
            // if you want constant velocity, you need
            // to calculate duration dynamically based
            // on desired velocity and distance
            duration: 1000 
        }

        function moveUp () { // just return racket to the initial position
            y = 50
        }

        function moveDown() {
            moveDownAnimation.start()
        }

        function stopAnimation() {
            moveDownAnimation.stop()
        }

    }

    Keys.onPressed: {
        if (event.isAutoRepeat) {
            return
        }
        if (event.key === Qt.Key_Q) {
            racket.moveUp() // return to initial position
        } else if (event.key === Qt.Key_A) {
            racket.moveDown()
        }
    }

    Keys.onReleased: {
        if (event.isAutoRepeat) {
            return
        }
        if (event.key === Qt.Key_A) {
            racket.stopAnimation()
        }
    }
}
于 2020-02-12T14:14:31.693 回答