user3797886
user3797886

Reputation: 339

Add simple animated GIF to iOS Spritekit Game?

I am a beginner programmer and am creating a game using iOS sprite-kit. I have a simple animated GIF (30 frames) saved as a .gif file. Is there a simple way (few lines of code maybe similar to adding a regular .png through UIImage) of displaying this GIF in my game? I have done some research on displaying an animated GIF in Xcode and most involve importing extensive classes, most of which is stuff I don't think I need (I barely know enough to sift through it).

Upvotes: 6

Views: 4407

Answers (2)

Joshua Basch
Joshua Basch

Reputation: 23

Michael Choi's answer will get you half way there. The rest is getting the individual frames out of the gif file. Here's how I do it (in Swift):

func load(imagePath: String) -> ([SKTexture], TimeInterval?) {
    guard let imageSource = CGImageSourceCreateWithURL(URL(fileURLWithPath: imagePath) as CFURL, nil) else {
        return ([], nil)
    }

    let count = CGImageSourceGetCount(imageSource)
    var images: [CGImage] = []

    for i in 0..<count {
        guard let img = CGImageSourceCreateImageAtIndex(imageSource, i, nil) else { continue }
        images.append(img)
    }

    let frameTime = count > 1 ? imageSource.delayFor(imageAt: 0) : nil

    return (images.map { SKTexture(cgImage: $0) }, frameTime)
}

extension CGImageSource { // this was originally from another SO post for which I've lost the link. Apologies.

    func delayFor(imageAt index: Int) -> TimeInterval {
        var delay = 0.1

        // Get dictionaries
        let cfProperties = CGImageSourceCopyPropertiesAtIndex(self, index, nil)
        let gifPropertiesPointer = UnsafeMutablePointer<UnsafeRawPointer?>.allocate(capacity: 0)
        if CFDictionaryGetValueIfPresent(cfProperties, Unmanaged.passUnretained(kCGImagePropertyGIFDictionary).toOpaque(), gifPropertiesPointer) == false {
            return delay
        }

        let gifProperties: CFDictionary = unsafeBitCast(gifPropertiesPointer.pointee, to: CFDictionary.self)

        // Get delay time
        var delayObject: AnyObject = unsafeBitCast(
            CFDictionaryGetValue(gifProperties,
                                 Unmanaged.passUnretained(kCGImagePropertyGIFUnclampedDelayTime).toOpaque()),
            to: AnyObject.self)
        if delayObject.doubleValue == 0 {
            delayObject = unsafeBitCast(CFDictionaryGetValue(gifProperties,
                                                             Unmanaged.passUnretained(kCGImagePropertyGIFDelayTime).toOpaque()), to: AnyObject.self)
        }

        delay = delayObject as? TimeInterval ?? 0.1

        if delay < 0.1 {
            delay = 0.1 // Make sure they're not too fast
        }

        return delay
    }

}

Note that I assume that each frame of the gif is the same length, which is not always the case.

You could also pretty easily construct an SKTextureAtlas with these images.

Upvotes: 2

Michael Choi
Michael Choi

Reputation: 285

The way I think of it gifs are just like animating a sprite. So what I would do is add the gif as textures in a SKSpriteNode in a for loop and then tell it to run on the device with SKAction.repeatActionForever(). To be honest I'm fairly new to this as well. I'm just trying to give my best answer. This is written in Swift, but I don't think it'll be to hard to translate to Objective-C.

var gifTextures: [SKTexture] = [];

    for i in 1...30 {
        gifTextures.append(SKTexture(imageNamed: "gif\(i)"));
    }

    gifNode.runAction(SKAction.repeatActionForever(SKAction.animateWithTextures(gifTextures, timePerFrame: 0.125)));

Upvotes: 3

Related Questions