I took a break from this project for a while. I’ve since moved to Linux full-time on my desktop PC (this will become relevant later!), and when I came back the project I was a bit perplexed by some of the things I had done so far.
For testing from the editor, I had passed data between scenes in some globals. Looking at Noble engine’s documentation, there are functions to pass data between scenes when you transition. Why wasn’t I using these?
Noble.transition(NewScene[, __duration=1.5[, __transition=Noble.TransitionType.DIP_TO_BLACK[, __transitionProperties={}[, __sceneProperties={}]]]])
It’s pretty simple – The two things that matters are NewScene, which is the scene we’re doing to, and __sceneProperties, which is passed to our new scene when we transition to it. The rest we can leave as nil to leave as the default values.
Except… my copy of Noble Engine doesn’t have that last parameter. Huh? Noble Engine, in its current state now, has had no updates between starting this project and writing this sentence. So while I’m reading the -latest- version of the documentation, it should be the same as what I’ve got. But, ok. I’ll do a sanity check and checkout the submodule to the latest version… and it did indeed update.
I guess the template’s submodule was out of date or something. Whatever. I go and update the code, compile, and run in the simulator, and………. it’s blank. Huh? I reset the simulator and it runs fine as it should. Weird! I then wonder if this happens on hardware too. I upload the game to the playdate, and it appears to launch and run fine. Ok! A simulator bug, I assume.
So the “previous” version of Noble engine works fine in the current-at-time-of-writing (3.0.3) version of the Playdate Simulator, but the current version does not. Perhaps I could bisect the submodule and hunt for the bug, but Noble engine isn’t very complex as is so I’ll just dive in and debug it the good old way. I’m on a freshly installed setup of VSCodium, so I go and install the playdate debugging extension, configure it and hit run with the intent to step through and see where things go odd - it should be pretty obvious. The debugger begins, the simulator starts, we step through and… and it all starts up perfectly fine?!
Ah. A good old Heisenbug. So it works fine in a debugger+simulator and works fine on hardware. That’s honestly good enough for me for now. I’ll go back and look further in to this issue later, but it’s possible its just a weird simulator bug that could just get fixed next week anyway, so I’m not going to spend further time on it right now. That portion of the yak can stay matted.
Lets see where I was last at: Moving between the editor and the testing scene. Oh! Thinking about it, we’ll want autosaves too, and loading levels from a file. Oh! Why don’t we just use that instead - we can autosave whenever we leave the editor, and the test can load from that. All that messing around before was kind of for nought, aside from the fact that it’s just sensible to keep your libraries up to date where possible, as we can just saveload instead of directly passing data between scenes.
Perhaps serializer/deserializer is the wrong word – it’s actually preparing a serializer-friendly table - or reading from one - that we then chuck into playdate’s JSON serializer/deserializer.
The path is very basic, it’s currently a bunch of lines & arcs. The deserializer just ends up being the serializer in reverse. Not particularly interesting.
Playdate has a handy set of functions living under playdate.datastore. These convert a Lua table into json and save it, and we don’t have sensitive data so this seems very nice and convenient. Our editor scene will have three ‘methods’. Save, LoadAutosaveIfAvailable, and Load.
LoadAutosaveIfAvailable will load an autosave if we have one, which we’d check if we’re entering a fresh editor scene. Load just loads from a filename, and Save, well… it saves our level to a file. Save makes up a table, fills it with the relevant data to serialize (with our object / path ‘serializers’) and then calls playdate.datastore.write to write that table to a file. Load does the reverse, with playdate.datastore.read. Game.lua and Editor.lua have seperate implementations of Load, as what concerns the editor and the game are different in a way.
This opens up a few options for tidying things up:
I’m not going to distract myself with too much yak shaving, but we’ve shampoo’d it and are ready to add some conditioner, at the very least. Next up is either new objects/enemies, or refactoring Editor.lua into several files/modules.