I’m not always the most concise blogger. I often get the voices in my head to sound out my posts as I write, but unfortunately they like to hear themselves talk. For all of the words I put down, I end up saying very little, or say things that aren’t even close to the point I want to make.
Yesterday I wrote a post entitled “The Obsession, And Missed Opportunities” which I think ended up coming across as a “woe is me” type post about how I can’t stick with any attempts to make my own game. In truth, the post was about how I viewed my own fascination with video games in parallel with what I’m learning about the history of the video game industry through the book Replay: The History Of Video Games. Ideally, yes, had I been single-minded enough way back when, I might have been able to join the production side of that historical march, but as it stands, my decisions have only allowed me to stand on the consumption side of the video game phenomenon, and that’s merely hindsight talking.
But some encouraging words offered served as a kick in the ass, and I started thinking about revisiting my space trading game. Anything I could create wouldn’t be anywhere near the level of, say, Elite: Dangerous or even Starpoint Gemini 2, which are both fantastic games. But there’s never been self-restraint when it comes to a genre or treatment; my game can be an also-ran, and I’d be OK with that, so long as I can get something done.
So I took some time to visit the Unity site, and found myself in the tutorial section. They have a massive library of video tutorials on various subjects, and I watched two of them: Persisting Data, and Object Pooling. The object pooling data was very helpful, but it was the data persistence video which provided me with a shot in the arm that prompted me to rush out to write this post and start waving it around like a madman.
* * *
In previous attempts, the bulk of my development time was spent with data. Data, not graphics, is the core of every game. Everything we do has to have representation, has to be tracked, modified, and compared. That’s all data, from the speed at which you swing your sword to the amount of damage you can take before your bumper falls off, to how many HP each member of a mob has. Games need to store this data, both the immutable form (a goblin peon has 10 HP, always) and in dynamic form (your own HP increase based on level). Data also has to describe individual items, so although there’s 10 orcs running your way, each orc needs to have his own stats. They may be sourced from the same master data definition of “orc warrior”, but as soon as you hit the first one with an arrow, his HP differ from those of his compatriots.
I was going nuts over how to get the master data into the system, and how to save and load it, and also how to save and load the dynamic data. I felt I needed to have all of this data in place before anything else, because as the core of the game — data — I couldn’t really test anything else until I had something to test with. So I spent a massive amount of time wracking my brain on how to deal with all this crap, and didn’t ever get to the point where I was making visible progress.
After watching the persisting data video, though, I thought “I’m overthinking this”, which is my S.O.P. anyway. See, I had been trying to save everything to files, including master data, because should it need to be updated, I could just re-issue a new file. Thing is, I’d still need to do that via a patch process, and really, replace one file, replace a different one…who cares? It’s still patching. And if this data isn’t intended to change, why worry about making it external to the application? Put it into the application, and remove the need to load and save master data. It would also help during development because with the file method, I’d have to make the change to a stat, then save the data to file, load the data from the file, and see if the results work. With internal data, I can just change the value and run the app.
My loading and saving routines ended up working pretty well, but the kicker was how to store them in memory. I couldn’t load them from disk on demand; that would be way too heavy-handed. Previous attempts relied on singletons, the mention of which just caused the blood pressure of some developers to skyrocket, but when we’re talking about a central, unchanging data store it’s the option that makes sense. My implementation was…complex. More complex than it needed to be, according to the tutorial video. The video shows a psuedo-singleton pattern for a Game Controller object, but in a way that cuts down my pages of code to something relatively simple, yet which does the exact same thing.
This new understanding lead me to re-think how data is stored and distributed to the items in the game that need data representation. Rather than having each instantiated object load it’s own data and then throw it into the Save bucket when the time came, the Game Controller data store would dole out data to relevant objects when the player enters the scene, and each object will return it’s data — modified or unmodified — to the Game Controller data store when the player saves or leaves the scene. If that ends up too top-heavy, then each scene will load it’s own data when the player enters, and write it out when the player leaves. More experimentation will be needed to see which option works best, but I think both are better options than what I had been working with originally.
I got really excited about thinking about this, because from the flow-chart point of view, it dramatically simplifies the assumptions I had been working under that had given me so much grief. I’ve always wondered and have sought out “best practices” for doing the kinds of things that all games do, including data management for master and dynamic data, but the one thing I’ve come to realize is that there is no “best practice”. There’s examples of what has been done, what has worked, and what hasn’t, but holding back progress until the Holy Grail of “how the professions accomplish it” is only going to keep me from making any kind of headway at all.