SpriteKit:如何立即使用removeAllActions停止操作

时间:2022-01-17 10:18:42

According to the documentation, removeAllActions cancels the actions immediately, but the state of the object is getting updated for at least one tick.

根据文档,removeAllActions立即取消操作,但对象的状态将更新至少一个tick。

I have a simple scale animation,

我有一个简单的比例动画,

let scaleUp = SKAction.scaleBy(2.0, duration: time)
sprite.runAction(scaleUp)

and an event that removes all actions and resets the scale. The event gets called during the touchesBegan cycle,

以及删除所有操作并重置比例的事件。在touchesBegan循环期间调用该事件,

sprite.removeAllActions()
sprite.setScale(1.0)

The animation stops, but the sprite is still in the wrong scale. If I call the same event again, then the scale is properly reset.

动画停止,但精灵仍然是错误的比例。如果我再次调用同一事件,则会正确重置比例。

What's the exact timing of these actions? The documentation doesn't seem to mention any of this timing issues. Otherwise I would expect to have an "onCancel" callback that could be passed to runAction and called after removing it, analogous to "completion".

这些行动的确切时间是什么时候?该文档似乎没有提及任何此时间问题。否则我希望有一个“onCancel”回调可以传递给runAction并在删除后调用,类似于“完成”。

Edit: The issue was a bit of my code that tried to reset the size of the sprite before removing the actions (I'm updating its texture, and the aspect ratio might change, so the size needs updating)

编辑:问题是我的代码有点试图在删除动作之前重置精灵的大小(我正在更新其纹理,并且宽高比可能会改变,因此大小需要更新)

Repro case based on Whirlwind's answer below.

Repro案例基于Whirlwind的答案如下。

class GameScene: SKScene {
let sprite = SKSpriteNode(color: .whiteColor(), size: CGSize(width: 123, height: 123))
override func didMoveToView(view: SKView) {
    sprite.alpha = 0.5
    sprite.position = CGPoint(x: 448, y: 223)
    addChild(sprite)
}
private func scaleTest() {
    let scaleUp = SKAction.scaleBy(2.0, duration: 0.5)
    let scaleDown = SKAction.scaleTo(1.0, duration: 3)
    sprite.runAction(SKAction.sequence([scaleUp, scaleDown]))
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    if sprite.hasActions() {
        sprite.size = CGSize(width: 123, height: 123)
        sprite.removeAllActions()
        sprite.setScale(1.0)
    } else {
        scaleTest()
    }
}
}

The fix:

        sprite.removeAllActions()
        sprite.setScale(1.0)
        sprite.size = CGSize(width: 123, height: 123)

1 个解决方案

#1


1  

I can't reproduce what you are saying. For me, everything works fine. Take a look at this example (I didn't changed the size of a scene so it is 1024x768 which is default):

我不能重现你说的话。对我来说,一切正常。看一下这个例子(我没有改变场景的大小,所以默认为1024x768):

import SpriteKit

class GameScene: SKScene {

    let sprite = SKSpriteNode(color: .whiteColor(), size: CGSize(width: 123, height: 123))


    override func didMoveToView(view: SKView) {

        sprite.alpha = 0.5

         let sprite1 = SKSpriteNode(color: .redColor(), size: CGSize(width: 123, height: 123))

        let scaleUp = SKAction.scaleBy(2.0, duration: 7)
        sprite.runAction(scaleUp)
        sprite.position = CGPoint(x: 448, y: 223)
        addChild(sprite)

        sprite1.position = sprite.position
        addChild(sprite1)
    }


    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {


        sprite.removeAllActions()
        sprite.setScale(1.0)
    }

}

Notice how white sprite is scaled to its original size when screen is tapped (at least in my case).

注意在点击屏幕时如何将白色精灵缩放到其原始大小(至少在我的情况下)。

A fact worth of mentioning about how SKActions work is that actions are queued and always processed in the next frame. Also, you can't run an action on a node which is not added to the scene. The point is that what you have posted should work, and if it doesn't work, then something else is wrong, but not this part of the code.

值得一提的是SKActions如何工作的事实是行动排队并始终在下一帧中处理。此外,您无法在未添加到场景的节点上运行操作。关键是你发布的内容应该有用,如果它不起作用,那么其他的东西是错误的,但不是代码的这一部分。

#1


1  

I can't reproduce what you are saying. For me, everything works fine. Take a look at this example (I didn't changed the size of a scene so it is 1024x768 which is default):

我不能重现你说的话。对我来说,一切正常。看一下这个例子(我没有改变场景的大小,所以默认为1024x768):

import SpriteKit

class GameScene: SKScene {

    let sprite = SKSpriteNode(color: .whiteColor(), size: CGSize(width: 123, height: 123))


    override func didMoveToView(view: SKView) {

        sprite.alpha = 0.5

         let sprite1 = SKSpriteNode(color: .redColor(), size: CGSize(width: 123, height: 123))

        let scaleUp = SKAction.scaleBy(2.0, duration: 7)
        sprite.runAction(scaleUp)
        sprite.position = CGPoint(x: 448, y: 223)
        addChild(sprite)

        sprite1.position = sprite.position
        addChild(sprite1)
    }


    override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {


        sprite.removeAllActions()
        sprite.setScale(1.0)
    }

}

Notice how white sprite is scaled to its original size when screen is tapped (at least in my case).

注意在点击屏幕时如何将白色精灵缩放到其原始大小(至少在我的情况下)。

A fact worth of mentioning about how SKActions work is that actions are queued and always processed in the next frame. Also, you can't run an action on a node which is not added to the scene. The point is that what you have posted should work, and if it doesn't work, then something else is wrong, but not this part of the code.

值得一提的是SKActions如何工作的事实是行动排队并始终在下一帧中处理。此外,您无法在未添加到场景的节点上运行操作。关键是你发布的内容应该有用,如果它不起作用,那么其他的东西是错误的,但不是代码的这一部分。