【问题标题】:Swift 3 (SpriteKit): Stopping a forever looping SKAction has a delaySwift 3(SpriteKit):停止永远循环的 SKAction 有延迟
【发布时间】:2017-05-02 21:55:57
【问题描述】:

我一直在尝试制作一个永远运行的 SKAction,我可以随时停止。我是这样做的:

override func didMove(to view: SKView) {

    run(SKAction.repeatForever (
        SKAction.sequence ([
            SKAction.run(drawFrame),
            SKAction.wait(forDuration: 0.01),
            ])), withKey: "frameDrawing"
    )
}

然后在 drawFrame 函数中我像这样停止 SKAction:

func drawFrame() {
    //(code)
    if stop {
        removeAction(forKey: "frameDrawing")
    }
}

由于某种原因,SKAction 仅在 stop 变为 true 后运行 3 或 4 次后才停止。我希望它在 stop 设置为 true 时立即停止,而不是在 3 或 4 次重复之后。

如果有人知道如何解决此问题,请告诉我,因为我尝试了很多方法,但他们从未解决此问题。谢谢!

编辑:这是我的代码:

var drawingFrame = SKAction()
class GameScene: SKScene, SKPhysicsContactDelegate {

override func didMove(to view: SKView) {

    drawingFrame = SKAction.repeatForever (
        SKAction.sequence ([
            SKAction.run(drawFrame),
            SKAction.wait(forDuration: 0.03),
            ]))
    run(drawingFrame)
}

func drawFrame() {
   //(code)
    if stop {
        drawingFrame.speed = 0.0
    }
}

如果您想知道为什么我在开始时将 SKAction drawingFrame 设置为一个空的 SKAction,那是因为我需要在这两个函数之前定义 SKAction。否则,不会为这两个函数定义它。

为有相同问题的任何人编辑:我已经使用自己的想法和@appzYourLife 的解决方案解决了这个问题。每次都有效的最有效方法是仅在 stop 等于 false 时运行代码。但是,请确保停止程序的 if 语句位于该括号之外,以便 SKAction 最终停止。这是工作代码:

var drawingFrame = SKAction()
class GameScene: SKScene, SKPhysicsContactDelegate {

override func didMove(to view: SKView) {

    drawingFrame = SKAction.repeatForever (
        SKAction.sequence ([
            SKAction.run(drawFrame),
            SKAction.wait(forDuration: 0.03),
            ]))
    run(drawingFrame)
}

func drawFrame() {
    if stop = false {
       //(code)
    }
    if stop {
        removeAllActions()
    }
}

如果您愿意,可以使用 if else 语句作为 stop = false 语句。

【问题讨论】:

  • 是的,我做了同样的顶级声明“技巧”,所以我可以访问它。我不知道这是否是最好的方法,但它确实有效。
  • 按照我的阅读方式(这不是一个可信的阅读),这应该有效。动作应该停止。
  • 是的,我也是这么想的。这有点奇怪。无论如何感谢您的提示。
  • @J.Treutlein 只是一个问题......你在哪里(如何)设置 stop = true ?为什么不使用完全可行的示例更新您的问题,因为我认为您发布的内容实际上与您之前的示例一样,这意味着当您设置 stop = true 时,将在停止后立即执行多个 drawFrame() 调用......
  • 它检查一个变量是否小于或等于一个数字。如果我发布与该变量相关的所有内容及其更改方式,我将发布我的大部分代码,大约 100 行。这就是我避免它的原因。无论如何,我的新解决方案可以完美运行,并且我希望它可以正常工作,因此不需要对我进行更改。不过感谢您的关注和帮助。

标签: swift sprite-kit skaction


【解决方案1】:

尝试创建对 SKAction 的引用,并在您希望它停止时调用它的速度更改(到 0.0)。这两者都比查找动作名称然后删除它要快。但是在 0.01 时,您已经比帧速率 (0.01666) 更快地重复它,因此无论您停止它的效果如何,您总是会获得至少一次额外的动作迭代。

类似:

let myAction = SKAction.repeatForever (
        SKAction.sequence ([
            SKAction.run(drawFrame),
            SKAction.wait(forDuration: 0.01),
            ]))

//when you want to run it
run(myAction)

// when you want to stop it:
myAction.speed = 0.0

【讨论】:

  • 感谢您的快速回复。
  • 我在我的项目中尝试过,但现在它一直在继续。
  • 我不知道为什么它不起作用,我已经使用打印来确保停止检测有效但速度没有改变。
  • @Confused 我只是用调试器玩了一点,然后弄清楚为什么你的例子没有工作(为什么在将drawingFrame的速度属性设置为零后动作没有停止)。调试器显示,当您运行该操作时,它会在内存中获取另一个地址,就像它是从原始属性之外复制然后运行一样。所以,当你改变一个属性的速度时,你实际上并没有改变一个正在运行的动作的速度。但是,如果您通过按键抓取动作,那么您将获得真实的实例,因此您可以对其施加影响。此外,文档缺乏描述这种行为......
  • 嗯,对不起... theMissingDocsSet += 1
【解决方案2】:

您可以删除当前节点上运行的所有操作。这不仅会立即删除序列动作,还会立即删除嵌入的动作。

func drawFrame() {
    if stop {
        removeAllActions()
    }
}

【讨论】:

  • 谢谢。在 stop 设置为 true 后,迭代仍会再运行 2 次,但这是目前最有效的方法。我可能会使用这个,因为它是我尝试过的最好的。
【解决方案3】:

我没有确切的解释为什么 drawFrame() 目前被多次调用(但我会尝试发现:D)...无论如何,试试这个代码:

import SpriteKit

class GameScene: SKScene, SKPhysicsContactDelegate {



    var stop = false

    override func didMove(to view: SKView) {

        run(SKAction.repeatForever (
            SKAction.sequence ([
                SKAction.run({[unowned self] in
                    if self.stop {
                        self.action(forKey: "frameDrawing")?.speed = 0.0
                    }else{
                        self.drawFrame()
                    }

                }),
                SKAction.wait(forDuration:0.03),
                ])), withKey: "frameDrawing"
        )
    }

    func drawFrame() {
        //(code)
        print("drawFrame")

    }
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches, with: event)
        stop = !stop
        print(stop ? "stopped": "running")
        if !stop {
              self.action(forKey: "frameDrawing")?.speed = 1.0
        }
    }
}

使用 touchesBegan 切换暂停模式。

【讨论】:

  • 谢谢!!这非常有效!虽然,很难直接实施来解决我的问题。但是,我可能会将它用作我的程序的暂停系统,非常感谢!
  • @J.Treutlein 实际上,关键是您应该始终抓住一个动作,然后将其暂停(速度 = 0.0),或者将其删除。你有精确的控制。
  • 感谢您的帮助,我非常感谢。它比使用 removeAllActions() 的其他方法效果更好,因为它更加精确,非常感谢。
  • 酷。我不知道你可以像那样切换 bool,或者在婴儿车中使用三元(不关闭)
  • @J.Treutlein 没问题 :) 如果我以某种方式找出为什么在您的情况下多次调用 drawFrame(),我将更新我的答案。这可能与瞬时和非瞬时动作的工作方式有关,以及动作被推迟到下一帧执行的事实。另外,我会说它有一些延迟(持续时间)。而且,当您将所有这些与实际上(IMO)缺乏详细解释动作序列的文档混合在一起时,当人们遇到此类问题时,很难弄清楚到底发生了什么并给出适当的答案:)跨度>
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-02-12
  • 1970-01-01
  • 2016-04-08
  • 1970-01-01
  • 2014-06-11
  • 1970-01-01
  • 2016-09-02
相关资源
最近更新 更多