The project structure of a game is where things are, and what they are called. Viewed broadly, it may also include decisions about what cloud services to use, version control, and access control, but in this post I want to focus on folder structures and file names: how a project is structured on a specific machine.
Project structure is not rocket science. You need to:
- Figure out some principles.
- Make a few rules.
- Follow the rules (and make others follow them).
- Clean up from time to time.
- Review principles and rules from time to time and adjust as necessary.
Each team and each project is different, and it is impossible to anticipate all the consequences of decisions at the beginning. It is better to have simple rules that people can follow easily, and adjust over time as certain pain points emerge.
It may not be immediately obvious why naming is part of the structure. The reasons are:
- The structure can change the interpretation of names. For example, a file called Model in the Flamingo folder is clearly a Flamingo model.
- The structure can preclude certain naming possibilities. Files in the same folder cannot have the same name.
Principles of project structure
What do we want the project structure to do? Ideally, the project structure should:
- make things easier to find
- make things easier to test, update, deploy
- make it easy for assets to move through your pipeline
- make it easy for people to work together
- convey information about the logical structure of the project
- make the project pleasant to work with
As I said before, your team may land on a different set of principles. The ones you choose reflect your processes (and culture). It is not so important what your principles are, but that you think about how your project structure can support them.
Coming up with rules in order to uphold the principles you came up with is more difficult, and even in a team there may be sharp differences. These differences usually reflect differences in workflow and pain-points, so they are expected and healthy. But it means you need involvement from different members of the team (if not everyone, at least someone from each functional unit) not only to get their buy-in, but also to avoid decisions that affect the workflow of some members negatively.
As an example of how to make (and think) about these rules, I will describe what we do in our studio.
Make things easy to find
Name assets and folders well. The most basic technique of naming things well is to name them what they are. It sounds obvious but people don’t do it. Maybe its because they are concentrating on the task rather than the thing they are naming at that moment.
I find that if I ask someone what something is, they give me a response that will make a good name. “What is this?” It is the bump map for the octopus. OctopusBumpmap. “What is this?” “It’s the button that takes you back to the main menu”
BackToMainMenuButton or perhaps
MainMenuButton or even
BackButton. (The trick can work on yourself too, but it is harder to answer concretely when you already know what it is. Telling someone else forces you to be precise.)
Some bad names arise because something changes over time. This used to be the MainMenuButton, but now it brings up a popup instead. When something changes (what it is or does) the name should change too. It is for this reason that I strongly advise against using names to refer to things in code, because this increases the cost of name changes and therefore bad names are more common.
For programmers, I highly recommend the sections in Code Complete about naming (Section 7.3, Chapter 11, and Section 12.7).
Follow conventions across studio and projects. Conventions do two things:
- Once you know the convention, you don’t need to read documentation or learn something anew for each project. You know the scene of entry is going to be in the Scenes folder called Main.
- You save on design / decide time. You don’t have to think where to put the scene of entry or what to call it – you simply follow the convention. Conventions can save a lot of time, especially at the beginning of a project.
Consider what is used to find assets. There are two basic ways: through search, and through navigating a tree structure. For the former, you would prefer to use more unique names, with the latter you will prefer a well-balanced tree. These two things together usually mean names tend to be a bit longer; not only because fewer duplicates are possible, but they are also less is desirable so that you can identify the asset you are looking for in search results.
Do what a reasonable person may expect. Where would an outsider go to look for things? What would they think they should be called? Over time a group of people will drift away from expected defaults as their process becomes more specific, but when making decisions about something for the first time, try to make decisions that will not surprise other developers.
Make it easy to test, update, and deploy
Keep scenes, code, and assets used for testing separate. This makes it easier to strip them out when you deploy, and in addition, this helps people work together. (This is discussed further later).
Using something like Unity cloud to make builds. This has several advantages, but the main one is as long as the code is committed, anyone can make a build; the settings are consistent, and it’s straightforward to get it to the next step (usually onto various test devices). And besides, you then don’t have to worry about where builds should be.
Keep third-party code and tools separate. This makes it easier to update (and also prevents you from accidentally changing them).
Prevent messing with the structure of third-party code and tools. Some developers like to remold third-party code into their own form. The downside is that this makes updating these assets very expensive. I would definitely not recommend doing this with for example the Facebook SDK that is bound to change a few times during the development of the project. One exception is that you may wish to remove examples and documentation out of the project.
The last two points do not apply to other assets such as models and textures. It makes sense to bring that into the structure of the projects, and those are unlikely to need updates.
Make it easy for people to work together
Split files so that as far as is possible, only one person will need to work on it. This may be difficult with certain files, such as scene files, but even there you can often design things to avoid people having to work on the same scene at the same time. (In Unity, you could use additive scene loading, prefabs, etc.)
Use test scenes to develop new features or assets. Once you have the code or asset in a stable form, move it into the main scene. When you follow this strategy, use a folder called
FeaturesInDevelopment and call the scene by the feature or asset:
CollisionAvoidanceAI. For this to work, you may need to mock certain aspects of the game. Some developers will make a copy of the main scene and use that; but the additional clutter may make it difficult to develop the feature.
Make your structure reflect logical relationships
This is simply common sense: it may be putting similar things together (such as textures or bird models), or it may be putting the components of a thing together, such as all the script files of the UI.
Make your structure pleasant to work with
This is a category of smaller rules that makes things prettier and (sometimes) more usable.
- Don’t use abbreviations (except for a handful of sanctioned ones). Mostly to avoid people abbreviating inconsistently.
- Use consistent capitalization and underscoring for names.
- Don’t use “Final” in any name. (It is never final.)
- Name things with the changing part at the front * like
ButtonCancel). This makes it easier to find particular buttons in lists. If you want to group them, put them in a folder. (Although you would of course not do
- Long names are good when appropriate, but don’t overdo it.
- Try to keep folders balanced (not too few items, not too many).