Reflecting on Unity

I was recently prompted to make a list of things I had learned from using Unity and what pitfalls I had come across. I thought it was a good topic for a Devlog post that may be useful for other solo developers starting out, so I have written some of my thoughts below, categorised into good, bad and things to be aware of. If you are interested in more on Software Development in general, I have created another post here on some of my thoughts.

The Good

  • Ease of use: I haven’t used much of Godot or UE but Unity does feel quite easy and intuitive to pick up. Comparing apples to oranges, Unity’s editor was much more approachable to me than Blender’s, Gimp’s, Photoshop or other extendable graphic based tools.
  • C# Integration: I have been brought up on Java in industry, and I just haven’t had to take out my own garbage that much in life!! C# is a short jump from Java and since picking it up 10 years ago, the syntax and structure feels comfortable to me. (I think Unity is best in class for C# integration among game editors still)
  • It is Industry Standard: It has a strong internet presence. There is lots of documentation out there (although can be sparse for latest experimental features) and also training courses everywhere on how to do things, including free courses from Unity itself. However see the point in “The Bad”.
  • The Editor system is expandable: I was pleasantly surprised by how easy it is to customise the editor, add plugins, custom build scripts and menu items. It is also quite intuitive to use and debug with, interacting with your game hierarchy in debug pause is a great boon.

The Bad

  • Money Grabbing: Unity’s latest U-Turn on a money grabbing retroactive policy around charge per install is only a slight mitigation to the original scheme which seemed poorly thought out, not industry standard, incredibly punishing in certain scenarios (to the point people could lose money selling mobile or F2P games), and retroactively applied for games already in the wild. Post-latest update on it, the cost in momentum of moving for me outweighs any potential losses if my game is successfully marketed.
  • All things to all consumers: Since VR, mobile & web support, Unity seems to be increasingly marketing itself also as a graphical tool platform and data / AI Visualisation app. This can be a little unsettling for people only interested in game development.
  • It is not Industry Standard: Despite my point in “The Good” there are relatively little jobs out there advertising solely C# and Unity game development roles (certainly in the UK). Most require C++ and UE experience. I might be just unlucky or looking at a bad time, but having used it for a long time it does leave a bit of a sour taste in the mouth.
  • It can be slow!: Depending on asset counts, shader counts, random performance hogs like breakpoints (!) and your own code (!) compile time and debug performance can be a bit of a slog. See some of the points in pitfalls.

Pitfalls to avoid

  • Be careful around coupling too tightly with Unity’s framework, making porting and maintainability difficult. Unity is often trying to lock you down a rabbit hole of coupling more and more closely with it and its features. This can sometimes adversely affect your design quite significantly. I have managed to steer clear of some of its more obvious online lock-ins such as its matchmaking, ad system for mobile and home grown development support like git integration (I use git through VS and sprint and build management through MS Azure & pipelines). However even if these types of features are avoided you are still inheriting from its own script framework, potentially using its storage system with scriptable objects and tieing yourself closely to its multiplayer, animation, or shader framework.
  • Avoid updating frequently! I keep to an LTS version of Unity and only update if I know there is something I absolutely need in the latest version. Unity is not the best at feature migration. I am often burned on each update, requiring large amounts of time porting code or features that are partially upgrade or sometimes even just turned off. Examples of this are in the more experimental packages like Unity’s SVG support.
  • Multiplayer can be a pain, and Unity’s implementation has a fair few annoying points of design. NetObjects requiring parent objects to also be networkobject is a big one. Reparenting having to be after network.spawn is another. Having to use structs or write large serialisation methods to work around data relationships can be quite a challenge, especially when your original code is expecting object references to be maintained. These types of foibles have made me have to redesign approaches to terrain modification sharing over the network for example.
  • Unity’s use of inheritance might well be an antipattern (although I can see why they do it). Unity uses inheritance to allow interaction with scripts attachable to game objects. All scripts being attached to GameObjects must inherit from MonoBehaviour. Using a subclass of Monobehaviour, (NetworkBehaviour for example), means that all subclasses of your script need to have that behaviour attached to them. So if you make a base entity class with a basic behaviour like health, if a subclass needs network behaviour your base class needs to be inheriting from network behaviour too which means all subclasses and classes in that type hierarchy will be networked. Combine this with all RPC calls only being usable on scripts inheriting from networkbehaviour and you force yourself to either call out from entities to network specific scripts (which breaks the basic idea of the networking) or need to make two similar base classes one networked and one not networked.
  • Try and keep a divide between business, storage and UI logic. This is a general rule of thumb for me in most projects, but with Unity the Monobehaviour system seems to make it quite easy to forget this. Take for example a hierarchy of objects related to a player. UI Health Bar scripts, inventory & container systems, map systems all tend to have elements with UI, business and storage functionality. These often reside in the same object hierarchy or on the same object. By having this close proximity, it can feel natural to cross reference or put multilayer code in one class. By being strict on yourself with this, you save a lot of time when you want to trigger code outside of the UI or re-use data objects or business logic elsewhere.
  • Don’t always look for scripts on the marketplace. Don’t be afraid to use a properly licensed third party library, sometimes they will be better maintained and updated than Unity’s own features and save you time and cost. Third party code is often better found in open source sites, or as generic C# algorithms on the net rather than through the Unity marketplace which can sell you packages that are difficult to integrate and sometimes don’t do what you need.
  • As a solo developer, keep code maintainable and understandable. Solo Development is hard, and progress is often the product of momentum from being “in the zone” and stealing time from your everyday life. Therefore debugging and fixing previously coded work is costly so anything to reduce or speed this up should be grabbed whole-heartedly. Clean Code and SOLID principles are there to help you in this. Large development times mean that you may not remember why particular functions are structured in certain ways, so be kind to the brain cells of your future self!1

Other Tips

  • Use AssemblyDefinitions and namespaces to protect against cyclic dependencies, make code cleaner and make compile times quicker. The last time I looked at Unit Testing in unity, AssemblyDefinitions were a requirement.
  • VS and Unity can often get into a tizz around breakpoints, debugging etc. Clearing your project files and breakpoints every once in a while can help keep things smoother.
  • In Unity’s editor bubble it is often quite easy to lose sight of performance. Having a FPS indicator up during development is useful. Depending on complexity, designing game features using Coroutines & unity’s frame lifecycle update loops may slow down framerates. Threading and thread pools should be used for large background tasks.
  • Simpler is often better. Sometimes just debug logging using System.Stopwatch is better for quick performance analysis than the cluttered unity performance analyser.
  1. I may well expand on this more in other articles. I feel a post on general solo game developer lessons learnt coming on… ↩︎

Posted

in

by

Tags:

Comments

Leave a Reply