6 Software Practices to Keep, Shed, and Adopt in Unity

Below, I put a brief list of Software Engineering practices you should shed when starting with game development, those you should adopt, and those you should keep.

Shed: Keep it all in code

By simply setting a “Patrol Position” to an empty Game Object, you’ll already have a neat visual game editing experience.

In Software Engineering, it often feels like the more you represent in code, the better off you are: you can analyze your code to find references, jump to definitions, etc. A Software Engineer might be inclined to represent their scenes, objects, and most of the game in code.

But you’ll probably want to get used to leaning more on the Unity Editor UI than you expected.

By simply setting a “Patrol Position” to an empty Game Object, you’ll already have a neat visual game editing experience.

The Unity Engine does a lot of heavy lifting in its serialization/deserialization code and in asset management. If you’re programming in Unity (at least when getting started), you’ll want to swim with the current.

Game design is also inherently visual, usually. Placing your objects in 3D space, constructing guard patrol paths, or setting up a field-of-view for those guards are all easier done while visually editing a scene than by writing down the coordinates imperatively. What’s more, if you need to modify these values later, visually doing so is less error-prone.

Adopt: Write your own Custom Editors and Property Drawers

Along the same lines, one of the first things you should make a habit of doing is to make sure your custom components, property types, and assets feel like first-class citizens in the Unity Editor.

Have your own “Float Range” struct? Why not make sure you can manipulate it in the Editor with sliders that guarantee the min is always smaller than the max?

Have a MonoBehaviour with mutually-exclusive fields? Write a custom editor for the MonoBehaviour that displays them how you want.

Rolling your own Dialogue Tree? Represent that as an asset and write a custom editor for it.

Custom Editors are not just a great way to make your objects editable as first-class citizens; they can also be a way to make sure your objects are debuggable and testable as first-class objects. Write an editor that shows you some of your object’s internal state when in play mode, or add a button to your editor that triggers a state in a controlled way (e.g., an “I got hit” button).

Custom Property Drawer for Interactable Effects
Custom Property Drawer for Interactable Effects
An example “Interactable” component allows setting effects when the player initiates an interaction.

An example “Interactable” component allows setting effects when the player initiates an interaction.

See more in the Unity docs on Custom Editors and Property Drawers. The Brackeys Editor Window video is also helpful.

Keep: Singletons tend to be a code smell

If you’re following game development tutorials or seeing discussions in forums, you’ll see singletons everywhere. But for much the same reasons as in Software Development, the singleton pattern is often inflexible, untestable, and has the potential to tangle your dependencies.

See more here and here.

Shed: Get comfortable with some globals

It might be tempting to be very strict about always encapsulating state and fully separating concerns. In game development, though, I find it helpful to get comfortable with the idea of slightly more state sharing than you would like in some other software system.

Part of this might be because there truly is more global state in games (e.g., has the first level boss been defeated, has the first town been saved, etc.?)

But I argue that even states that you can encapsulate might benefit from being a little more global. For example, you can encapsulate an HP variable within your Player component and use it to drive logic. You would also need your Player component to control HP display in the UI, and maybe screen-shake effects when the player takes a hit. On the other hand, having a global “Player HP” variable that you can pass to the player, a HUD object, and a screen-shake VFX object might be a cleaner alternative.

Person playing Nintendo Switch
Person playing Nintendo Switch
Photo by Kelly Sikkema via Unsplash

Adopt: The Inspector can be your injection framework

I alluded to this above, but I think the way you can have clean globals can be a streamlined form of dependency injection. If a player requires a global Player HP value, let the component reference an HP serialized field and pass it in the inspector. You’ll get some of the nice things about DI (stubbing in a test, isolation), without much of the “magic” that makes it so intimidating to use.

See more in Ryan Hipple’s talk on Scriptable Objects. If you’d like to learn more about Scriptable Objects, I wrote about their serialization and surveying their uses in a Unity tutorial.

Keep: Unit- and Integration Tests are Always Good

It’s easy to spend many months reading about game development & best practices without reading discussions on test frameworks. Unity provides the Unity Test Framework to this end. This tutorial by Anthony Uccello provides an overview of how to get started.

I hope this helped build some intuition practices to lean into. Trusting your Software Engineering sense will usually be the right bet, though in some cases, a step back is warranted.

This article originally appeared as part of a series entitled Unity for Software Engineers.

Written by

Software Engineer living in Brooklyn, NY. MIT Computer Science S.B. ’13, M.Eng. ‘14. From Amman, Jordan. Interested in politics, current affairs, and technology

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store