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).
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)));
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With