core data and sprite kit

Does any one have or know of an example to add core data to sprite kit?


Thanks!

Answered by Pintxo Creative in 218580022

Ok, I'll just quickly run through NSUserDefaults, NSCoding and .plist approaches.


NSUserDefaults: Simple, singular data that is very easily saved and loaded. No data structure really, just a key-value pair where the key is a string by which you save and load the value. Read more: https://developer.apple.com/reference/foundation/userdefaults


// SAVE

let saveData = UserDefaults.standard
saveData.set(true, forKey: "isThisDataSimple")
saveData.set(5, forKey: "amountOfSecondsNeededToUnderstandThisData")
saveData.synchronize()

// LOAD

let loadData = UserDefaults.standard
print("This data is simple: \(loadData.bool(forKey: "isThisDataSimple"))")
print("And it took me only \(loadData.integer(forKey: "amountOfSecondsNeededToUnderstandThisData")) seconds to understand it!")


NSCoding: A straightforward and independent way of saving data with a little bit more complexity. Probably wouldn't be good enough to handle table relationships and other database-related functionalities, but definitely a nice way of getting very far with little hassle. This would for example allow you to save multiple data objects that are defined in a class. Read more: https://developer.apple.com/reference/foundation/nscoding


// CLASS

import SpriteKit

class MyData: NSObject, NSCoding {

    let isThisDataSimple: Bool
    let amountOfSecondsNeededToUnderstandThisData: Int

    init(dataIsThisDataSimple: Bool, dataAmountOfSecondsNeededToUnderstandThisData: Int) {
        isThisDataSimple = dataIsThisDataSimple
        amountOfSecondsNeededToUnderstandThisData = dataAmountOfSecondsNeededToUnderstandThisData
    }

    required convenience init(coder decoder: NSCoder) {
        let isThisDataSimple = decoder.decodeBool(forKey: "isThisDataSimple")
        let amountOfSecondsNeededToUnderstandThisData = decoder.decodeInteger(forKey: "amountOfSecondsNeededToUnderstandThisData")

        self.init(dataIsThisDataSimple: isThisDataSimple, dataAmountOfSecondsNeededToUnderstandThisData: amountOfSecondsNeededToUnderstandThisData)
    }

    func encode(with coder: NSCoder) {
        coder.encode(isThisDataSimple, forKey: "isThisDataSimple")
        coder.encode(amountOfSecondsNeededToUnderstandThisData, forKey: "amountOfSecondsNeededToUnderstandThisData")
    }
}

// PATH

let myDataPathFileName = "MyData.plist"
let myDataPath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(myDataPathFileName)


// SAVE

let myDataToSave = MyData(dataIsThisDataSimple: true, dataAmountOfSecondsNeededToUnderstandThisData: 5)
NSKeyedArchiver.archiveRootObject(myDataToSave, toFile: myDataPath)

// LOAD

if let myData = NSKeyedUnarchiver.unarchiveObject(withFile: myDataPath) as? MyData {
    print("This data is simple: \(myData.isThisDataSimple)")
    print("And it took me only \(myData.amountOfSecondsNeededToUnderstandThisData) seconds to understand it!")
}


Property List: Just a standard way of laying out organized data. You can save into property lists (like above), but if you want to work with static data, you can just visually write your data into a .plist file in Xcode and just simply fetch it in code when needed. Now there are so many varieties of how to fetch that data, which depend on how it is constructed anyway, so maybe I won't present any code on that. Instead you should probably look into it yourself. Read more: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/PropertyLists/UnderstandXMLPlist/UnderstandXMLPlist.html


Hope that helped 😀!

There's no restriction for using CoreData in SpriteKit. It's just not a part of the bundle by default, maybe because Apple expects non-game apps with complex data structures to make more use of it than a normal mobile game would. What you can do is start an empty project, take the CoreData stuff that it produces (probably mostly in the AppDelegate) and just copy-paste it into your SpriteKit project.

I've never used CoreData in SpriteKit, even though I do use it in UIKit apps. Even with some complex structures, I think it may be a bit overkill. CoreData is meant for really rigid data structures where data points can be updated without the whole save file being rewritten and it's optimized to be synced with a server. So crucial for a service app that sync complex data structures and relationships from a server to display user activity, but not really ideal to just save a game score to disk 🙂.

Thank you for trying to help me again. i did copy the data to the AppDelegate and the data saved but when I try to use the data in my gamescene swift file it does not fetch the data successfully.

Are you sure you wouldn't just be happier with a simpler implementation of an NSObject data store that you save into a .plist? It's pretty easy and way more independent from Xcode structures and stuff. Also, if you only had a few things to save, you could try NSUserDefaults, which is the simplest. Can you describe the data that you wish to save? I can provide you with some sample code to get you started.


CoreData is something you would need to know if you wanted a career in UIKit app development, so definitely it's a good thing to learn. I think every iOS developer should know how it works at least. But for games it usually is overkill, unless you're managing for example user accounts that are syncing to a server.

Hi,


I plan to have hundreds of records. Examples would be state capitals, major rivers and mountains. I want this data to be stored and retrived for use in my game.



Thanks!

Okay, then the next questions would be: 1) Is the data static, meaning do you update it based on what the user does or not? 2) Do you need to sync this data from a server?


Let's take the case of a trivia game as an example. You'll want to present facts from the trivia content, but then save the score of the player. Trivia is by definition immutable facts, so it's likely you won't be updating the data based on what the player is doing. Scores are ever-changing data, but they need to be stored so that they persist to be compared later. Also, there's no point in having hard-coded scores there before the player has played anything. At the same time, the trivia content is pretty set-in-stone, meaning you can add chapters later in updates and don't need to be fetching that stuff from servers. Of course, this may vary.


In this case, you have hard-coded static immutable data as the trivia content (without a server connection) and previously non-existing persistently stored user data as the score.


For this kind of simple user data you should be using NSUserDefaults or an NSCoding object (if there's more complexity). For the trivia content, I would maybe user pre-fabricated .plists, which I then just fetch into memory as an object when the app starts. Then I would pick out relevant data from that object when I specifically need to process it. For "hundreds" of items it's perfectly fine and .plists in Xcode give a pretty pleasant interface to manipulate them.


So I still think CoreData would be overkill.

Thank you. Do you have a good example for me to reference? I have always used Core Data in the past.

Accepted Answer

Ok, I'll just quickly run through NSUserDefaults, NSCoding and .plist approaches.


NSUserDefaults: Simple, singular data that is very easily saved and loaded. No data structure really, just a key-value pair where the key is a string by which you save and load the value. Read more: https://developer.apple.com/reference/foundation/userdefaults


// SAVE

let saveData = UserDefaults.standard
saveData.set(true, forKey: "isThisDataSimple")
saveData.set(5, forKey: "amountOfSecondsNeededToUnderstandThisData")
saveData.synchronize()

// LOAD

let loadData = UserDefaults.standard
print("This data is simple: \(loadData.bool(forKey: "isThisDataSimple"))")
print("And it took me only \(loadData.integer(forKey: "amountOfSecondsNeededToUnderstandThisData")) seconds to understand it!")


NSCoding: A straightforward and independent way of saving data with a little bit more complexity. Probably wouldn't be good enough to handle table relationships and other database-related functionalities, but definitely a nice way of getting very far with little hassle. This would for example allow you to save multiple data objects that are defined in a class. Read more: https://developer.apple.com/reference/foundation/nscoding


// CLASS

import SpriteKit

class MyData: NSObject, NSCoding {

    let isThisDataSimple: Bool
    let amountOfSecondsNeededToUnderstandThisData: Int

    init(dataIsThisDataSimple: Bool, dataAmountOfSecondsNeededToUnderstandThisData: Int) {
        isThisDataSimple = dataIsThisDataSimple
        amountOfSecondsNeededToUnderstandThisData = dataAmountOfSecondsNeededToUnderstandThisData
    }

    required convenience init(coder decoder: NSCoder) {
        let isThisDataSimple = decoder.decodeBool(forKey: "isThisDataSimple")
        let amountOfSecondsNeededToUnderstandThisData = decoder.decodeInteger(forKey: "amountOfSecondsNeededToUnderstandThisData")

        self.init(dataIsThisDataSimple: isThisDataSimple, dataAmountOfSecondsNeededToUnderstandThisData: amountOfSecondsNeededToUnderstandThisData)
    }

    func encode(with coder: NSCoder) {
        coder.encode(isThisDataSimple, forKey: "isThisDataSimple")
        coder.encode(amountOfSecondsNeededToUnderstandThisData, forKey: "amountOfSecondsNeededToUnderstandThisData")
    }
}

// PATH

let myDataPathFileName = "MyData.plist"
let myDataPath = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent(myDataPathFileName)


// SAVE

let myDataToSave = MyData(dataIsThisDataSimple: true, dataAmountOfSecondsNeededToUnderstandThisData: 5)
NSKeyedArchiver.archiveRootObject(myDataToSave, toFile: myDataPath)

// LOAD

if let myData = NSKeyedUnarchiver.unarchiveObject(withFile: myDataPath) as? MyData {
    print("This data is simple: \(myData.isThisDataSimple)")
    print("And it took me only \(myData.amountOfSecondsNeededToUnderstandThisData) seconds to understand it!")
}


Property List: Just a standard way of laying out organized data. You can save into property lists (like above), but if you want to work with static data, you can just visually write your data into a .plist file in Xcode and just simply fetch it in code when needed. Now there are so many varieties of how to fetch that data, which depend on how it is constructed anyway, so maybe I won't present any code on that. Instead you should probably look into it yourself. Read more: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/PropertyLists/UnderstandXMLPlist/UnderstandXMLPlist.html


Hope that helped 😀!

Thank you, i got that to work!

core data and sprite kit
 
 
Q