使用App Bundle内置纹理图集时SpriteKit绘制调用未批量化如何解决?
问题诱因
该问题是Xcode 13版本对Assets Catalog中SpriteAtlas资源的默认编译逻辑变更、搭配iOS 15模拟器渲染特性共同导致的:
- 使用
SKTextureAtlas(named:)加载Bundle内编译后的图集时,Xcode默认开启的SpriteAtlas优化会将图集中的单个纹理拆分为独立的GPU资源切片,逻辑上属于同一个图集的纹理,实际在GPU层面是独立的纹理对象,SpriteKit无法合并不同纹理对象的绘制调用,所以出现多绘制调用的问题。 - 使用
SKTextureAtlas(dictionary:)动态创建图集时,所有传入的图像会被打包到同一个GPU纹理对象中,符合SpriteKit批量化绘制的要求,因此绘制调用可以正常合并。
可行解决方案
- 方案1:关闭图集编译优化
选中Assets Catalog中的SpriteAtlas资源,在右侧属性检查器中将Optimize Sprite Atlas选项修改为「No」,重新编译项目即可。修改后Xcode会保留完整的图集纹理结构,加载后所有子纹理属于同一个GPU对象,绘制调用可正常合并。 - 方案2:提前预加载完整图集
使用图集前先调用preload方法强制完整加载整个图集资源,避免系统按需拆分加载纹理,参考代码如下:
import SpriteKit class GameScene: SKScene { override func didMove(to view: SKView) { let atlas = SKTextureAtlas(named: "Sprites") // 预加载完成后再创建精灵节点 atlas.preload { [weak self] in guard let self = self else { return } let costume = SKSpriteNode(texture: atlas.textureNamed("costume")) costume.setScale(0.3) costume.position = CGPoint(x: 200, y: 650) let tank = SKSpriteNode(texture: atlas.textureNamed("tank")) tank.setScale(0.3) tank.position = CGPoint(x: 500, y: 650) self.addChild(costume) self.addChild(tank) } } }
- 方案3:使用动态图集创建方式
保持SKTextureAtlas(dictionary:)手动创建图集的逻辑,该方式不受Xcode编译选项影响,兼容性最好,适合需要跨版本稳定运行的项目。 - 方案4:升级开发工具版本
该编译逻辑问题在Xcode 14及以上版本已经被修复,升级Xcode后无需额外修改配置,即可正常合并Bundle加载图集的绘制调用。
内容的提问来源于stack exchange,提问作者clns
相关产品推荐
相关产品推荐

