在 SpriteKit 中预加载纹理

Posted

技术标签:

【中文标题】在 SpriteKit 中预加载纹理【英文标题】:Preloading textures in SpriteKit 【发布时间】:2016-08-07 20:24:23 【问题描述】:

我进行了一些研究,但似乎找不到任何可以清楚地解释如何在动画中预加载单个纹理和纹理的内容。我目前正在使用Assets.xcassets 中的Atlas 对相关动画图像进行分组。将我的图像放在 Atlas 中是否意味着它们已预加载?就单个图像而言,在 GameScene 之前声明纹理是否有意义:let laserImage = SKTexture(imageNamed: "Sprites/laser.jpg") 然后(例如)在我的 SKSpriteNode 子类之一中我可以通过 laserImage 传递?

我最终想知道是否有明确定义的方法来解决这个问题,或者我是否应该在GameScene 之前将每个纹理存储为常量。任何有关解决此问题的正确(和最有效)方法的建议都会很棒。

【问题讨论】:

【参考方案1】:

我尝试实现 appzYourLife 答案,但它增加了加载每个纹理的时间。所以我最终把所有最常用的 Sprites 放在一个单独的图集中,然后放在一个单例中。

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)

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

【讨论】:

这很好用——正是我一直在寻找的。预加载精灵时是否有用于显示加载屏幕的约定? @Sanf0rd 我看到了相同的结果。我不认为 SpriteKit 在内部缓存预加载的纹理或图集。不过这是有道理的,因为 SpriteKit 怎么知道什么时候是清除缓存的好时机,对吧?如果我保留对预加载纹理/图集的引用,我会看到性能大幅提升。 我相信这应该是正确的解决方案。苹果提供的示例表明它们还保留了对纹理的引用。它们引用一组纹理并在该变量或属性上调用 preload 方法。 谢谢。至于我,您的解决方案应该被接受为正确答案。赞成【参考方案2】:

一个单一的纹理图集

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

预加载

如果您愿意,可以使用此代码将纹理图集预加载到内存中

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

自动缓存

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

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

忘记文件图像的名称,您在资产目录中分配给图像的名称是您唯一需要的名称。

如何从图像创建精灵到纹理图集?

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

【讨论】:

我在 Atlas 上调用.preloadWithCompletionHandler 后,我应该如何引用图像?我会只引用没有扩展名的图像名称吗?此外,这是否意味着为与一个动画相关的一组相关图像使用单独的 Atlas 是没有意义的?非常感谢。 非常感谢,将我的所有纹理存储在单个 Atlas 中是否有任何性能优势?或者我应该根据属于单个动画的动画和包含不一定是动画一部分的单独纹理的另一个将它们分开? 绝对应该使用一个纹理图集,因为它已加载到 GPU 中,并且只要您只使用该精灵图集中的纹理,SpriteKit 就不需要将任何其他资源加载到 GPU . iirc 预加载图集时,使用 preloadWithCompletionHandler,完成块中的代码在后台线程上执行,如果您的代码需要在主线程上执行,这可能会导致问题(因此您需要抓取该完成处理程序中的主队列并在那里执行它)。 我找到了相关的帖子。你可以在这里阅读更多内容:***.com/q/22534088 关于“一个地图集”,我同意@appzYourLife,但我想说,你必须找到最佳的为您的应用程序。如果您有一个包含所有图像的大图集,但在当前场景中仅使用其中的少数图像,那么在该场景中将浪费内存。在这种情况下,两个图集(需要两次绘制调用)将是更优的解决方案。

以上是关于在 SpriteKit 中预加载纹理的主要内容,如果未能解决你的问题,请参考以下文章

使用“预加载”链接指令在 Chrome 中预加载字体

在 CATiledLayer 中预加载/预显示图块?

在 Android 中预加载网页(使用 WebView?)

如何在 vue 项目中预加载图片

我们如何在 Angular 中预加载字体?

在linux中预加载动态加载的库