在SpriteKit中预加载纹理

10
我已经做了一些研究,但似乎找不到任何清晰地解释如何预加载单个纹理和动画中的纹理的内容。我目前正在使用Assets.xcassets中的Atlas来组织相关动画图像。将我的图像放在Atlas中是否意味着它们已经被预加载了?对于单个图像,是否有必要在GameScene之前声明纹理,如下所示:let laserImage = SKTexture(imageNamed:“Sprites/laser.jpg”),然后(例如)在我的一个SKSpriteNode子类中,我可以直接传递laserImage吗?
我最终想知道是否有明确定义的方法来解决这个问题,或者是否应该在GameScene之前将每个纹理存储为常量。关于处理此问题的正确(和最有效)方法的任何建议都将非常好。
2个回答

13

我尝试实现appzYourLife的答案,但这增加了加载每个纹理的时间。因此,我最终将所有最常用的精灵放入一个单一的贴图集中,并将其放入单例中。

class Assets {
    static let sharedInstance = Assets()
    let sprites = SKTextureAtlas(named: "Sprites")

    func preloadAssets() {
        sprites.preloadWithCompletionHandler {
            print("Sprites preloaded")
        }
    }
}

我在menuScene中调用了Assets.sharedInstance.preloadAssets()。而且:

let bg1Texture = Assets.sharedInstance.sprites.textureNamed("background1")
bg1 = SKSpriteNode(texture: bg1Texture)

引用已经加载到内存中的纹理。


这个非常好用 - 正是我一直在寻找的。在预加载精灵时,有没有使用显示加载屏幕的约定? - muZero
@Sanf0rd,我看到了相同的结果。我认为SpriteKit没有内部缓存预加载的纹理或图集。这是有道理的,因为SpriteKit怎么会知道清除缓存的好时机呢?如果我保留对预加载纹理/图集的引用,我会看到很大的性能提升。 - damirstuhec
2
我相信这应该是正确的解决方案。 苹果提供的示例显示他们也保留了对纹理的引用。他们引用纹理数组并在该变量或属性上调用预加载方法。 - 3366784
谢谢。对我来说,您的解决方案应该被接受为正确答案。已点赞。 - wm.p1us

8

一个纹理集

将所有资源放入一个纹理集中。如果不适合,至少尝试将单个场景的所有资源放入一个纹理集中。

预加载

如果需要,可以使用以下代码将纹理集预加载到内存中。

SKTextureAtlas(named: "YourTextureAtlasName").preloadWithCompletionHandler { 
    // Now everything you put into the texture atlas has been loaded in memory
}

自动缓存

您不需要保存纹理图集的引用,SpriteKit有一个内部缓存系统。让它去完成它的工作。

我应该使用哪个名称来引用我的图片?

忘记文件图片的名称,您为图像分配到资源目录中的名称是您唯一需要的名称。

enter image description here

如何从图像创建一个纹理图集中的精灵?

let texture = SKTextureAtlas(named:"croc").textureNamed("croc_walk01")
let croc = SKSpriteNode(texture: texture)

非常感谢,还有将所有纹理存储在单个图集中是否有性能优势?或者应该根据属于单个动画的纹理和不一定是动画的一部分的单个纹理进行分离? - muZero
1
绝对应该使用单一的纹理图集,因为它被加载到GPU中,只要你只使用来自该精灵图集的纹理,SpriteKit就不需要将任何其他资源加载到GPU中。 - Luca Angeletti
如果我没记错的话,在使用preloadWithCompletionHandler预加载图集时,完成块中的代码会在后台线程上执行,这可能会导致问题,如果您的代码需要在主线程上执行(因此您需要在完成处理程序中获取主队列并在那里执行)。 - Whirlwind
2
我已经找到了相关的帖子。你可以在这里阅读更多信息:https://dev59.com/n33aa4cB1Zd3GeqPidJQ 关于“一个图集”,我同意@appzYourLife的观点,但我想说的是,你必须找到最适合你的应用程序的解决方案。如果你有一个大的图集,其中包含所有的图片,但你只在当前场景中使用了其中的几张图片,那么内存将在该场景中浪费。在这种情况下,两个图集(需要两个绘制调用)将是更优化的解决方案。 - Whirlwind
@appzYourLife 是的。在我看来,这是意外的行为,但完成处理程序中的代码在后台线程上执行。 - Whirlwind
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接