0

I'm new to SpriteKit, and my question is how to load sprite sheets from web API.

Currently, I have an API returns a big PNG image, which contains all sprite sheets, and a json about individual frame information. (file and json are generated by TexturePacker) The API looks like this:

enter image description here

The format just likes a .atlasc folder, which contains a big image and a plist (XML) file.

I was thinking about downloading image and plist file and save it in the disk to load. However, SKTextureAtlas.init(named: String) can only load from app bundle.

In one word, I want to load a sprite animation from the web at runtime.

I have control of the API, so I can update the API to accomplish my goal.

Honghao Z
  • 1,419
  • 22
  • 29
  • This is why extensions exist, use SKTextureAtlas(dictionary:string:AnyObject) as your designated init – Knight0fDragon Jul 21 '16 at 17:05
  • You mean I need to make API return individual images, I download them all and init a `SKTextureAtlas` with `init(dictionary: [String : AnyObject])`? – Honghao Z Jul 21 '16 at 21:43
  • No, you download the other atlas (texture packer atlas) then you make individual textures out of it via code and place them using the method i said. SkTexture allows you to extract a texture from a larder texture, so you load the main image as a texture, then based on the json, you extract the individuals out – Knight0fDragon Jul 21 '16 at 21:51

2 Answers2

2

The way I've figured out is downloading image, create a sourceTexture, like: let sourceTexture = SKTexture(image: image)

Then use the frame information in json to create individual textures with method init(rect rect: CGRect, inTexture texture: SKTexture)

Sample code is:

var textures: [SKTexture] = []

let sourceTexture = SKTexture(image: image)
for frame in spriteSheet.frames {
  let rect = CGRect(
    x: frame.frame.origin.x / spriteSheet.size.width,
    y:  1.0 - (frame.frame.size.height / spriteSheet.size.height) - (frame.frame.origin.y / spriteSheet.size.height),
    width: frame.frame.size.width / spriteSheet.size.width,
    height: frame.frame.size.height / spriteSheet.size.height
  )
  let texture = SKTexture(rect: rect, inTexture: sourceTexture)
  textures.append(texture)
}
Honghao Z
  • 1,419
  • 22
  • 29
0

basically same way with @Honghao Zhang 's answer, but I was little bit confused about the whole structure at first glance.

so I share my code snippet for later readers.

Happy coding :)

    func getSpriteTextures() -> [SKTexture]? {
        guard let spriteSheet = loadSpriteJson(name: "sprite_json_file", codable: SpriteJson.self) else { return nil }
        let sourceImage = UIImage(named: "sprite_img_file.png")!
        let sourceTexture = SKTexture(image: sourceImage)
        var textures: [SKTexture] = []
        
        let sourceWidth = spriteSheet.meta.size.w
        let sourceHeight = spriteSheet.meta.size.h
        
        let orderedFrameImgNames = spriteSheet.frames.keys.sorted()
        
        for frameImgName in orderedFrameImgNames {
            let frameMeta = spriteSheet.frames[frameImgName]!
            let rect = CGRect(x: frameMeta.frame.x / sourceWidth,
                              y: 1.0
                                - (frameMeta.sourceSize.h / sourceHeight)
                                - (frameMeta.frame.y / sourceHeight),
                              width: frameMeta.frame.w / sourceWidth,
                              height: frameMeta.frame.h / sourceHeight)
            let texture = SKTexture(rect: rect, in: sourceTexture)
            textures.append(texture)
        }
        return textures
    }