I’ve had to pick up a fair bit in order to keep up with the needs of my current team, and while these learnings might be obvious to more experienced programmers some of them have been significant milestones in the learning process for me.
ScriptableObjects
ScriptableObjects have become invaluable for the work I’ve needed to do, namely in that they allow me to create templates for objects we want variations of in our projects. For instance, rather than creating dedicated scenes to contain the audio and visuals assets we might need for different locations, we can simply set up and load in the location-specific elements from a scriptable object (backgrounds, colours, text, audio, etc.). These save a lot of time, but I also hope they create some more transparency in the work I do for my teammates. I walk them through on how to create these objects in the asset menu, the values which need to go in, and I try to give the objects headers, tooltips, and sliders to make them more accessible to non-programmers. Another benefit of these is that they allow us to uniformly make additions to our games. Let’s say every location now needs a unique UI image in a given spot on the screen: all we need to do is add a sprite variable to the scriptable object script, add these images in to the instances via the inspector, and then tell the main scene to read from the template and load in that image after a null check.
Resources.Load()
The main problem I started running into with our projects was increasingly long load times, particularly into and out of the scene selection. I specifically noticed this in one of the games I worked on a couple months ago, where I was using scriptable objects to store the structure and assets for each of four stories. These were all located in the scene selection, and one of them would follow the player into the main scene to give them the illusion of opening up a dedicated scene for the story they’d picked. This was all well and good until I found loading the scene selection crashed my phone. Too much was technically being loaded in at a given time — all of the audio and visuals assets for all four stories. After doing a couple searches, I came across the ‘Resources.Load()’ function, which would allow us to store assets (including custom ScriptableObjects) in a Resources folder for us to then draw on via a file path. By switching us over to a system which uses this function, the scene selection would then only need to store file path references and only ever need to load in one story at a time. This drastically sped up performance in the games while enabling us to continue using the scriptable objects system we had for creating and loading levels/locations.
Structs and Enums
The ability to create custom data types by using structs has been incredibly useful in a variety of settings across that games I’ve worked on. Namely, structs have allowed me to package up what the game needs to know about rounds and levels in order to generate end-of-level feedback for the player. What’s more, being able to save these via a binary formatter means we can easily store and load in information about the player’s overall progress (in a way we couldn’t quite do with ScriptableObjects).
On a similar note, creating and using enums has also been useful, particularly in conjunction with switch statements. We can create, for instance, three different ‘modes’ an object might be in, specify it for the object instance, then reliability read from it and perform appropriate logic. We can also make these visible in the inspector, meaning non-programmers on the team can click to select one of the specified options rather than needing to type them out (and risk misspelling them in the process). Admittedly I tend to need to convert these to strings in order to serialise them, but in practice these can are particularly useful.
In both cases, I prefer to declare the majority of my custom data types in a single location, generally a ‘VariableContainer’ class, so that I have a consistent reference point to hand in order to access them.
Lists and Loops
While I touched on some of this during my masters degree, I’ve finally been able to make extensive use of lists and various loops in the projects I’ve been working on recently. Being able to add and remove elements from a list, creating temporary lists, randomizing their order, combining them, and iterating through them have all been invaluable in a wide variety of contexts.
I’ve had chance to use for, foreach, and while loops in particular, predominantly using the latter for getting the program to wait for a user to perform an action (changing a boolean from false to true within a coroutine). I’ve made a few mistakes along the way with some of these, but learning to use the ‘Attach to Unity’ feature in Visual Studio Community has really helped me follow my code along and see exactly where it’s getting stuck in order to fix it.
Events
I use a fair few scriptable objects and one or two singletons in most of the projects I’ve been working on, which is all well and good until, inevitably, the number of dependencies gets a bit unwieldy. I’ve only recently learnt about how I can use events to mitigate dependencies within my project, having various methods subscribe to custom events without ever needing a direct reference to most of the games other scripts and managers. The idea of being able to have it so that my GameLogic controller doesn’t necessarily need a direct link to some of the game’s other systems, such the FeedbackController, is quite new and exciting to me. This, along with finally learning to add listeners to some of my UI elements, is beginning to allow me to determine a lot more of the game from within the scripts than within the editor. I do need to get the balance right with this so that our team’s main designers can still jump in and edit some public variables, but generally I think this is one of the next main steps I need to make in improving my practice.