【问题标题】:Why does creating large amounts of SKNodes take so long为什么创建大量 SKNode 需要这么长时间
【发布时间】:2016-11-06 12:49:31
【问题描述】:

我正在使用 SpriteKit 在 Swift 中为我的 iOS 应用程序创建一个随机项目微调器,但目前我的方法不是很有效,我几乎可以肯定它不是实现我的目标的最佳方法。我目前正在遵循的过程基本上是。
- 在场景加载时,循环浏览包含 13 个不同项目的列表(以 JSON 格式存储)
- 创建一组显示相关数据的节点
- 将每组节点添加到第二组节点,沿 x 轴稍微移动每个节点,创建一长串 SKNode(用于微调器的项目)
- 沿着 x 轴移动该组,给人一种它在项目中旋转的印象

但是这种方法甚至需要大约 6 秒才能加载场景(并且延迟是将节点添加到更大的节点:group.addChild(spinnerItem),因为我只是 Swift 的新手,我相信我有更好的方法这样做,因此任何帮助/建议感谢改进此代码,因为它迫切需要提高效率!

这里是 didMove 函数...

override func didMove(to view: SKView) {
    var xPos = CGFloat(self.frame.width + 150)
    var eventWeapon = weapon()

    for n in 0...13{
        eventWeapon = getWeapon(caseName: "chromaCase", weaponID: n)
        print(eventWeapon)
        let texture = createSpinnerItem(wName: "\(eventWeapon.name)", wSkin: "\(eventWeapon.skin)", wColor: "\(eventWeapon.color)")
        let spinnerItem = SKSpriteNode(texture: texture)
        spinnerItem.position = CGPoint(x: xPos, y: self.frame.height / 2)
        group.addChild(spinnerItem)

        xPos = xPos + 300 * 1.2
    }

    self.addChild(group)
    group.run(SKAction.moveBy(x: -5000, y: 0, duration: 2))
}

以及其中使用的createSpinnerItem 函数......

func createSpinnerItem(wName: String, wSkin: String, wColor: String) -> SKTexture {
    let object = SKNode()

    let bGround = SKShapeNode(rectOf: CGSize(width: 300, height: 300))
    bGround.fillColor = color.offWhite
    bGround.strokeColor = color.gray
    bGround.lineWidth = 5
    object.addChild(bGround)

    let titleBG = SKShapeNode(rectOf: CGSize(width: 300, height: 100))
    if wColor == "blue"{ titleBG.fillColor = color.CSGOblue }
    if wColor == "red"{ titleBG.fillColor = color.CSGOred }
    if wColor == "pink"{ titleBG.fillColor = color.CSGOpink }
    if wColor == "purple"{ titleBG.fillColor = color.CSGOpurple }
    titleBG.strokeColor = color.gray
    titleBG.lineWidth = 5
    titleBG.position = CGPoint(x: 0, y: -150 + 50)
    object.addChild(titleBG)

    let weaponName = SKLabelNode()
    weaponName.text = wName
    weaponName.fontColor = color.white
    weaponName.fontSize = 40
    weaponName.fontName = "Avenir-Regular"
    weaponName.verticalAlignmentMode = .center
    weaponName.position = CGPoint(x: 0, y: -150 + 70)
    object.addChild(weaponName)

    let weaponSkin = SKLabelNode()
    weaponSkin.text = wSkin
    weaponSkin.fontColor = color.white
    weaponSkin.fontSize = 20
    weaponSkin.fontName = "Avenir-Regular"
    weaponSkin.verticalAlignmentMode = .center
    weaponSkin.position = CGPoint(x: 0, y: -150 + 30)
    object.addChild(weaponSkin)

    return object
}

【问题讨论】:

  • 问题 - 为什么人们总是在标题中添加标签?
  • 嗯?我相信我已将我的标签放在帖子的相关Tags 部分中
  • 您在标题中添加了“Swift”。不需要,标签中已经说明你使用的是Swift。
  • @LuckyBowers:所以只有didMove 需要6 秒?或者您是否正在考虑整个启动过程。你在哪个设备上测试它?
  • @appzYourLife 好吧,这一切都运行得非常顺利,但是当将节点添加到 group 父节点时,每次迭代都会延迟相当多的时间。我正在 iPhone6 上测试

标签: ios swift sprite-kit


【解决方案1】:

您要做的第一件事是确定您的“感知”延迟是否真实,而不仅仅是启动应用程序的开销。 6 秒是一段很长的时间,所以如果没有测量,你不知道你是否只是在夸大或理解真正的延迟。我将深入了解我所说的在几个方面的意思。您应该按照 KnightOfDragon 的建议进行操作并实际测量时间。

我现在确实看到代码存在一个问题,而且我看到人们在 SO 上使用 SK 的代码并不少见。这进入了上面提到的感知概念。处理您的工作所需的实际 CPU 使用率可能不会很大,但是您在运行时遇到的情况可能与实际预期的 CPU 负载不匹配。为什么?您可能在主线程上做了很多工作。从加载 JSON 到可能创建纹理。因此,您会发现通过使主线程饥饿,您会看到原本不会看到的减速。普遍的问题,应用程序或游戏,是我看到很多人尝试在他们的didMove 或应用程序viewDidLoad 中加载所有内容。你真正想做的是将它更像是一个引导的起点。在那里做最少的工作来设置,然后使用你最喜欢的方法异步调度耗时的东西。这将减轻您在执行文件 I/O 等操作时锁定主线程的情况。

是的,这确实会使您的代码变得有点复杂,以便能够处理这个问题,但这种方法并不是非典型的。大多数引擎都有加载系统来帮助在后台加载项目并在完成时通知。在加载过程中,您通常会看到加载屏幕或其他一些指示符。

请记住,当您修改 SKNode 层次结构时,您需要确保在正确的线程上执行此操作(例如,当您 addChild 到活动场景时)。您可以通过SKAction 或在主线程上执行此操作。否则您的应用可能会崩溃。

【讨论】:

  • 非常感谢您所做的一切!我将运行您建议的测试,但另一件事是,如果我要在我的 GameView.swift 文件之外生成纹理,let myTexture = view?.texture(from: object) 行会出错,因为在空白的 swift 文件中没有视图。那么如何从 SKNode 创建纹理呢?
  • 我不确定你的意思。你需要通过任何你想要的方式加载你自己的纹理。 developer.apple.com/reference/spritekit/sktexture
猜你喜欢
  • 2016-05-29
  • 1970-01-01
  • 2016-04-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多