So I was reading the apple documentation for best sprite kit practices. I came across this:
For example, if your game uses the same textures for all its gameplay, you might create a special loading class that runs once at startup. You perform the work of loading the textures once, and then leave them in memory. If a scene object is deleted and recreated to restart gameplay, the textures do not need to be reloaded.
And this would significantly help performance in my application. Can someone point me in the right direction to how I would go about achieving this?
I presume I would call a function to load up texture's in my View Controller? And then access that texture atlas?
The thing is, do you really want to cache the resources like that? Can't say I ever found a need for something of that nature. Anyways, if doing that somehow helps with your app's performance, then you can make a TextureManager
class which would be a singleton (create separate file for TextureManager
class), like this:
class TextureManager{
private var textures = [String:SKTexture]()
static let sharedInstance = TextureManager()
private init(){}
func getTexture(withName name:String)->SKTexture?{ return textures[name] }
func addTexture(withName name:String, texture :SKTexture){
if textures[name] == nil {
textures[name] = texture
}
}
func addTextures(texturesDictionary:[String:SKTexture]) {
for (name, texture) in texturesDictionary {
addTexture(withName: name, texture: texture)
}
}
func removeTexture(withName name:String)->Bool {
if textures[name] != nil {
textures[name] = nil
return true
}
return false
}
}
Here you are using dictionary and associate each texture with its name. Pretty simple concept. If there isn't a texture with the same name in a dictionary, then add it. Just beware of premature optimization.
The usage:
//I used didMoveToView in this example, but more appropriate would be to use something before this method is called, like viewDidLoad, or doing this inside off app delegate.
override func didMoveToView(view: SKView) {
let atlas = SKTextureAtlas(named: "game")
let texture = atlas.textureNamed("someTexture1")
let dictionary = [
"someTexture2": atlas.textureNamed("someTexture2"),
"someTexture3": atlas.textureNamed("someTexture3"),
"someTexture4": atlas.textureNamed("someTexture4"),
]
TextureManager.sharedInstance.addTexture(withName: "someTexture", texture: texture)
TextureManager.sharedInstance.addTextures(dictionary)
}
As I said, you have to put TextureManager
implementation in a separate file, to make it real singleton. Otherwise, if you define it in GameScene
for example, you will be able to call that private init, and then TextureManager will not be a real singleton.
So, with this code you can create some textures at the very beginning of the app lifecycle, like it is said in the docs:
For example, if your game uses the same textures for all its gameplay, you might create a special loading class that runs once at startup.
and fill the dictionary with them. Later on, whenever you need a texture, you will not use atlas.textureNamed()
method, but rather load it from a dictionary property of a TextureManager
class. Also, when transitioning between scenes, that dictionary will survive scene's deinits, and will persist while app is alive.