Ok, so I’ve been using Unity to make games (and other interactive prototype work) for several years now. I’ve been the main coder on Fallen City (Our 15-month development for Channel4). Our audiovisual puzzler Avseq (which is en-route to Steam) was also rebuilt in Unity, and I’ve also coded a suite of android/iOS mobile games. Alongside these finished projects I spend a lot of time prototyping various procedural tech and other experiments, and of course working on our next game Sir, You Are Being Hunted.
I come from a C/C++ self taught programming background, and have used loads of IDEs like Visual Studio, Codeblocks, Eclipse and even stuff like Actionscript IDEs and Processing. Initially I shirked away from interface heavy IDE work, preferring to do everythign in code, but after a few years with unity I have come to appreciate the speed and prductivity benefits of using a more integrated environment, especially when working with a small team of developers, each with their own skills and project area ownership.
Anyway, when I first started with Unity one of my big concerns was, how do i structure all this stuff? I’d done a lot of object orientated design and quite a bit of component based stuff too, but the live editing of values in the inspector and the prepackaged object library use of prefabs was new to me. I asked on the forums, with little real result, as expected, the answer is generally that there are many ways to skin a cat. So Im just going to talk briefly about how I organise unity projects. This isn’t anything really do with specific programming paradigms or how to write better code, it’s more about how I structure things in a unity project to hopefully make things more readable and usable.
Old fashioned guy
I am still a big fan of a decent naming policy for classes, and members. I dont mean Hungarian notation (where you use bMyBool etc to indicate variable type, because its a pain to have to change the type and then all instances of the name). I mean more to indicate ownership. Unity doesnt really support namespaces, so it can be difficult to figure out what classes (and their function) are from the core library or from user made code, people say that you can use the IDE functions on rollover to read the class heirarchy etc, which is true, but I sometimes still open files in textedit (especially since you cant have multple unity instances running) and I also like to be able to see at a glance who has written what. As a result of this I tend to name all my classes with a C_ prefix, C_WorldMap, C_Gun, C_PlayerHealth. This might seem excessive, but its instantly obvious that the class and its fucntions are not part of any core library, or anyones third party work. It also avoids potential naming classes, calling one of your classes somethign like Map, PlayerHealth or Bullet, is unlikely to be a unique name, Ive imported several 3rd party code bases to Unity where Ive then had to rename classes due to a clash of this sort. Of course it shouldnt be C_ for everyone (or we’d all clash), but something that is distinguishable by yourself and others, perhaps linked to the project title. I know that code is ideally meant to be portable and non specific, but I think that games development is one of the areas where things almost always get specific and bespoke, due to rapid prototyping, time constraints ad the unique nature of requirements from game to game.
I also advocate naming in functionality nesting order. I mean by this that if a number of classes refer to the map, then use map as the initial naming element. So C_MapAreas, C_MapWater, C_MapHeat rather than C_AreaMap, C_WaterMap, C_HeatMap. It makes the scripts easier to group visually in the editor and helps you to mentally group them by their shared top level element.
Following this prefix approach I also name all member variables with m_ , m_BulletSpeed, m_BulletDamage, m_BulletType etc. I do this for exactly the same reason I C_ my classes, so I can quickly distinguish between a local scope variable and a class member, either when reading or when using dropdowns to select (all my members are in a nice neat range of the dropdown list rather than mixed in with inherited values and functions). I’ll name them via nested terms too if I can remember (such as the m_BulletBlah examples above). It also lets other people see exactly what Im doing. Unity is nice for people to work together on seperate aspects of a project (one person doing textures , another modelling, sounds etc) but its not great for supporting multiple coders.
I do a similar thing for other assets such as models, where i might prefix my test models with a T_ so I can pick them out quickly in the list/grid array that the unity IDE provides you when making inspector assignments. In our Fallen City project we had so many models that having a decent naming convention really helped speed up the development. (Remember to stress this to your 3D modellers!)
I think when a project is small its more useful to group assets/scripts by type. So a folder for textures, folder for sounds, folder for scripts etc. This means you can easily replace and survey all the graphics for your project, or get a sense of how large the codebase is etc. However, once you find that a project is getting large enough it makes more sense to organise folder structure by functionality, a set of nested folders for Map or AI functions for eg. I also use a prefix convention for folders, to seperate them visually in the IDE (and on disk) from default assets or 3rd party packages. A simple example might have directories called
etc and then I might use
as an example of a folder structure nested primarily by function and then by type. This also helps if you have several people working on a project who can claim ownership of a specific area of functionality. Using underscore at the beginning also puts them at the top of the project list and helps to distiguish them from standard unity folders etc.
Prefabs and Pointers
I come from C++ as my main programming language, so unlike most people I actually like pointers! Of course C sharp doesn’t really use pointers, but it does use references. I was initially confused as to when a reference is used or not, it appears that most default types aren’t passed as reference, but anything more complex, like a class or list will be passed to functions as a reference, unless you code it otherwise (by creating your own intermediate object or some other form of deep copy). Another aspect of referencing in Unity is the way you can drag and drop elements onto script variable fields in the inspector. Because you often do this with prefabs it can be easy to end up referencing and changing a prefab or material that is actually in your project folder, rather than one you want to be altered for the actual runtime game. I tend to prefix my references with a m_p to help me remember that the object referred to is to be read only (when using prefabs as a basis for instantiation etc), such as public GameObject m_pSceneryTreePrefab. I also do a similar thing with references to scripts m_pC_PlayerHealth (heh, even though I dont do it properly in the example screenshot above), for instance (or for a quick local scope version _pC_PlayerHealth).
Singletons & Global stuff
I tend to use singleton instances for all the major classes in a project. I prefer this to making them static as I can still control when they are created and destroyed and other scripts can test to see if they exist or not (I might not want every singleton class to always be active). It also means that all scripts can access key (global) information and functions without having to maintain their own local script pointers. The drag and drop system to assign refernces to other gameobjects is great in the inspector, but if your scripts are being instantiated as part of a library prefab, then the appropriate references (specifically non local ones) can only be assigned in code on start or awake etc. Singletons help to avoid some overhead from GameObject.Find calls too. I do use static classes, but generally only for utility functions that arent linked to any specific game scenes or object management.
I don’t do all these things really
Of course I don’t really manage to stick to all these rules, generally rapid prototying and quick hacks make write all kinds of unreadable rubbish, but I do try, and when i do kep things more readable I can work for longer on project before i reach that saturation point (you know, where you have really lost track of your own code). Im also not claiming that my approach is either the most efficient, the most elegant or the most intelligent. Im a self taught programmer and to CS graduates I probably code like an idiot, but there aren’t many people talking about how they organise stuff in relation to unity development so I thought I would. So please don’t flame me for not adhering to the Geneva Convention Of Interfacing or the NATO Polymorphism Treaty.. Thanks!