I have the following code:
final class PassthroughEmitterNode: SKEmitterNode {
static func load(fnWithoutExtension: String, in bundle: Bundle) -> SKEmitterNode? {
guard
let sksPath = bundle.path(forResource: fnWithoutExtension, ofType: "sks"),
let sksData = try? Data(contentsOf: URL(fileURLWithPath: sksPath)),
let unarchiver = try? NSKeyedUnarchiver(forReadingFrom: sksData),
let texturePath = bundle.path(forResource: fnWithoutExtension, ofType: "png"),
let textureImage = UIImage(contentsOfFile: texturePath)
else { return nil }
// Required to decode into subclass
unarchiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKEmitterNode")
let emitter = unarchiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as? PassthroughEmitterNode
unarchiver.finishDecoding()
guard let emitter else { return nil }
// We still need to set texture, because the texture file is not in main bundle
emitter.particleTexture = SKTexture(image: textureImage)
// Have to enable user interaction to receive touch
emitter.isUserInteractionEnabled = true
return emitter
}
}
This is very similar to reading a SKScene subclass instance from SKS file (such as this: using sks file with SKScene subclass).
However, this doesn't work. The unarchiver's decoding always returns nil.
But unarchiving to SKEmitterNode class itself works. The subclass doesn't work.
We can try this strategy:
SKEmitterNodePassthroughEmitterNodefrom aSKEmitterNodeIn order to do that let's add this init
That's it.
Now you can decode a standard
SKEmitterNodeand convert it into yourPassthroughEmitterNodeWhat if
PassthroughEmitterNodehas additional properties compared toSKEmitterNode?The value for these additional properties cannot come from the
sksfile since there is no place for them. So you will need to populate them using some default value or custom logic.