如何在 GameScene 中等待,然后做某事

How to wait, then do something, in the GameScene

SKAction 具有等待持续时间的能力,在节点上等待一段时间。并且似乎在节点上执行操作。比如moveTo等等

如果我不想这样,而是更愿意在一段时间后调用 GameScene 中的函数,我该如何在 GameScene 中使用 SpriteKit 而不是在 Sprite 或其他节点上调用函数?

SKActions 是执行此操作的方法吗?这样做的唯一方法是什么?

是的。这个问题太简单了。我缺乏寻找答案的启发式方法和术语。只是继续循环了解 SKAction 如何等待 SKSprites 上的调用,以便在一段时间后进行缩放、旋转等操作。这不是我想要的 want/need.

更新:

期望的结果,在 GameScene 中

doSetupStuff() // does some stuff...

waitForAWhile() // somehow wait, perhaps do somethings in here, while waiting

doSomethingElse() // does this after the waitForAWhile has waited

更新 2:

我认为在 didMove(to view...) 中再次发生了什么

        func wait(){
            let timeToPause = SKAction.wait(forDuration: 3)
            run(timeToPause)
        }


     let wontwait = SKAction.wait(forDuration: 3)
  run(wontwait)
  thisFunction(willnot: WAIT"it starts immediately")

    wait()
    thisFunction(forcedToWait: "for wait()'s nested action to complete")

更新 3:

找到了一种无需使用 SKActions 即可获得延迟的方法。它有点粗鲁和残酷,但到目前为止对我来说比 SKActions 更有意义:

DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) {
            print("I waited ten seconds before printing this!")
        }

您可以使用以下功能

#define ANIM_TIME 2

SKAction *customACtion = [SKAction customActionWithDuration: ANIM_TIME actionBlock:^(SKNode *node, CGFloat elapsedTime) {

       // Do Something Here
}];

一种方法,使用 SKActions,在 Swift 3.0 中,看起来像这样:

DEFINE: aPatientlyWaitingFunction() at the top level of GameScene class.

要在调用上述函数之前造成延迟,在

didMove(to view...)

我发现使用操作执行此操作的三种方法:

这三种方式似乎都完成了完全相同的事情:

    let timeToWait: TimeInterval = 3 // is seconds in SKAction thinking time

    let waitSomeTime = SKAction.wait(forDuration: timeToWait)

    // 1st way __________________________________________
    // with a completion handler, the function can be called after Action
    run(waitSomeTime) {self.aPatientlyWaitingFunction()}

    // 2nd way __________________________________________
    // as a completion to be done after action, in the run invocation:
    run(waitSomeTime, completion: aPatientlyWaitingFunction)

    // 3rd way __________________________________________
    // alternatively, as part of a sequence of actions...
    // Create a sequence, by making a run action from waitSomeTime and...
    let thenDoThis = SKAction.run(aPatientlyWaitingFunction)

    // then activate sequence, which does one action, then the next
    run(SKAction.sequence([waitSomeTime, thenDoThis]))

    // OR... for something different ____________________
    ////////////////////////////////////////////////////////
    DispatchQueue.main.asyncAfter(deadline: .now() + timeToWait) {
        self.aPatientlyWaitingFunction()
        print("DispatchQueue waited for 3 seconds")
    }

正如您所引用的,一种选择是在外部进行管理。我通常管理这类事情的方式是有一个外部 运行 更新周期。一个

要驱动此更新程序,您可以使用 CADisplayLink(这是我现在与我的 OpenGL 渲染器一起使用的)或调度源计时器(我已经与我的 SpriteKit 引擎一起使用)。当您使用更新时,您需要计算增量时间。滴答处理程序可能类似于:

func tickHandler() {
    let currTime = NSDate().timeIntervalSince1970
    let dt = lastTime - currTime // lastTime is a data member of the class

    // Call all updaters here, pretend "updater" is a known updater class
    updater.update(dt)
}

updaterupdate 方法看起来像:

func update(deltaTime:NSTimeInterval) {
    // Do your magic
}

我通常有一个主要的整体更新程序 运行ning 独立于人们所说的场景。示例用法类似于在老式街机游戏中使用吸引模式。他们在那里显示标题屏幕、示例游戏、高分、冲洗和重复。场景将是标题、游戏玩法、高分。在这里,您可以让您的主要更新者管理时间并协调场景的 construction/destruction/switching。请注意,这意味着拥有一个整体场景管理器(实际上非​​常方便)。

对于您的情况,您可以使用此更新程序来驱动 GameScene 更新程序。它的更新程序可能类似于:

func update(deltaTime:NSTimeInterval) {
    switch state {
        case .SetupState:
            // noop?
            println("I'm in setup") // Shown just so you can see there is a setup state
        case .WaitState:
            waitTime += deltaTime
            if waitTime >= kWaitTime {
                // Do whats you gots to do
                doSomethingElse()
                state = .NextState
            }
        case .NextState:
            // blah blah blah blah
    }
}

因此,从您的 driver(CADisplayLink 或调度源)执行此调用路径的流程类似于:

tickHandler -> 主更新器 -> 游戏场景更新器

有些人肯定会发现这可能有点粗暴。另一方面,我发现这非常有帮助。虽然显然有一些时间管理,并且失去了触发和忘记的能力,但它可以帮助为编排片段提供更多控制,以及任意更改状态,而不必担心杀死已经排队的动作。也没有什么说你仍然不能混合 SKAction。当我确实使用 SpriteKit 时,我以这种方式进行了所有更新以及一些已发送的项目。我只使用 SKAction 来更新层次结构。请记住,我使用了自己的动画和物理系统。所以至少对我来说,我对 SpriteKit 的依赖性要小得多(它对我来说实际上只是一个渲染器)。

请注意,您必须有自己的方法来处理暂停和进入前台,您的计时器需要重新同步(您只需要担心 tickHandler)。断点也会导致时间跳跃。

另一种让某事在一段时间后发生的方法是利用传递给 update() 的 'current time' 参数。以下代码将每隔 20 到 30 秒产生一个 Boss。

在您的 属性 定义中:

var timeOfLastBoss: CFTimeInterval = -1  //Indicate no boss yet
var timePerBoss = CFTimeInterval()

。 . .

didMoveToView() {
        ...
        timePerBoss = CFTimeInterval(Int.random(20...30))
        '''
        }

。 . .

func update(currentTime: CFTimeInterval) {
    ...
    spawnBossForUpdate(currentTime)
    ...
    }

' ' '

func spawnBossForUpdate(currentTime : CFTimeInterval) {
    if ( timeOfLastBoss == -1 ) {timeOfLastBoss = currentTime}
    if (currentTime - timeOfLastBoss < timePerBoss) {return}
    // Rest of 'spawnBoss code
    self.timePerBoss = CFTimeInterval(Int.random(20...30))
    self.timeOfLastBoss = currentTime  
}