SKAction 仅在睡眠后或运行调试器时运行

Posted

技术标签:

【中文标题】SKAction 仅在睡眠后或运行调试器时运行【英文标题】:SKAction only runs after sleep or while running debugger 【发布时间】:2018-06-10 23:27:02 【问题描述】:

使用 SpriteKit,我正在尝试制作一个暂停菜单,当玩家恢复游戏时,该菜单会在屏幕上显示动画(移动)。

我创建了一个 SKAction 并在 touch 开始运行它:

let duration = TimeInterval(0.5)
let moveAction = SKAction.move(to: CGPoint(x: 0, y: 495) , duration: 
duration)
pauseScroll?.run(moveAction) 

pauseScroll被初始化为:

weak var pauseScroll: SKSpriteNode?

override init(size: CGSize) 
  ...
  let pauseScene = SKScene(fileNamed: "PauseMenu")!
  pauseScroll = pauseScene.childNode(withName: "PauseScroll") as? 
  SKSpriteNode
  pauseScroll?.position = CGPoint(x: 0, y: 495)
  pauseScroll?.zPosition = 1000
  pauseScroll?.move(toParent: self)

我在这里所做的是将 pauseScroll 的 UI 布置在另一个 spritekit.scene 文件中,作为所有运行的实际 GameScene 都在代码中完成。然后我通过调用 .move(toParent: self) 将它带过来并添加到 GameScene。

问题是我可以很好地引用 pauseScroll,我可以修改它,例如改变它的位置,给它一个物理体和碰撞掩码,在 pauseScroll 中包含的节点上注册点击等。看起来除了在它上面运行 SKActions 之外的所有东西。

我同时为其他 SKSpriteNodes 运行 SKActions,它们工作正常,当然它们的初始化方式不同,因为它们都是在 .init 中的代码中设置的,例如:

var background: SKSpriteNode!

override init(size: CGSize) 
  ...
  background = SKSpriteNode(imageNamed: "GameBackground")
  background.size = size
  addChild(background)

然后我以与在触摸开始时执行其他任何操作相同的方式为它们设置动画:

let colorAction = SKAction.colorize(withColorBlendFactor: 0.4, 
duration: duration)
background?.run(colorAction)

有趣的是,如果我在 pauseScroll 上运行 SKAction 的函数中的其他任何地方运行 sleep(1);然后滚动动画并按原样向上移出屏幕。因此,这似乎是一种竞争条件,但我对它在等待什么一无所知。

当打印 pauseScroll 和 moveAction 的值时,无论我是否 sleep(1),我都会得到相同的结果。

这是实际中的错误:

如果我将 sleep(1) 添加到触摸开始内的任何位置,则会发生同样的事情,除了整个应用程序等待 1 秒钟,然后滚动条按预期从屏幕顶部向上移动。

如有必要,我很乐意提供更多代码。

【问题讨论】:

在使用 sleep() 之前,为什么不弄清楚它的作用?除非您确切知道自己应该得到什么,否则不要在 SpriteKit 中使用 sleep。 让 waitAction = SKAction.wait(forDuration: duration) let completionAction = SKAction.run 调用 self.run(waitAction, completion: self.pauseScroll?.run(moveAction) ) 与 sleep(1) 的效果不同。尽管 moveAction 仍在等待,但与 sleep 不同,滚动保持在原地。 我最好不要等待。 你根本不想使用睡眠,睡眠会锁定你的线程。您的错误可能有很多,并且无法通过您提供的代码来猜测。 【参考方案1】:

当您使用 .move(toParent: self) 将子级移动到新父级时,请尝试将每个子级的 isPaused 设置为 false。我怀疑当您从场景中加载所有孩子时,它们都会暂停,并且可能 SpriteKit 在场景首次出现时自动将 isPaused 设置为 false。

tempScene.children.forEach()  child in
            child.isPaused = false
            child.move(toParent: newParentNode)

【讨论】:

这个答案仍然有效!谢谢 我注意到从 .sks 文件创建的空 SKNode 可能会默认暂停。【参考方案2】:

尝试在父级的init() 方法中设置isPaused

将其视为UIView - 如果父视图设置为隐藏,则子视图(无论它们是否未隐藏)将不会显示。

【讨论】:

【参考方案3】:

我遇到了这个问题,虽然将“isPaused”设置为false解决了这个问题,但我发现不需要为所有子节点设置它,而只需要为子节点所在的父节点设置它搬到了。

例如,如果我有 sprite1 和三个子精灵节点,并且我想让 sprite2 成为这三个子精灵节点的新父节点,那么在使用 move(toParent) 之后,只需将 sprite2 的 isPaused 设置为 false。

这就是我为自己解决问题所要做的一切。这似乎表明,在使用 move(toParent) 时,接收父级及其子级的操作在设计上会自动暂停。

【讨论】:

以上是关于SKAction 仅在睡眠后或运行调试器时运行的主要内容,如果未能解决你的问题,请参考以下文章

C++ 应用程序仅在使用本地 Windows 调试器时运行,而不是在哪个 exe 文件中运行

Javascript 代码仅在调试时运行

Scala:代码仅在调试时运行(#ifdef 等效?)

编译器指令 - 建议 - 仅在调试模式下运行代码

仅在 Flutter 的调试模式下运行的应用程序

Qtcpserver仅在调试器下返回listen函数的未知错误