My General Tips for Unity


Now that the Professional(Dark) theme is available for us mortals, the first action in your Unity window should be Edit->Preferences->General->Edit Theme: Change to Professional. Now you can be a professional without paying hundreds of $/month.


While you are there, this next one depends on your personal preference and maybe a bit advanced, but I usually make the project in a way that when scripts recompile and the scene gets Serialized and then Desterilized back, the project keeps working correctly where I left off. So I set Script Changes While Playing to Recompile And Continue Playing in Preferences.


A small detail many don't know is that if you want to replace a script with a similar script, you can do it by clicking with the right mouse button on the tab name (Inspector) and setting it to Debug. Changing the script this way will preserve all the serialized fields.


For UI and every complex system in the game, I assume the worst-case scenario: the data they show may update many times during some frames. So I use the LateUpdate() function to update UI once after all the information that could change, changed. To make sure I do it only when needed, I use versioning. Data has a version and UI Controllers remember, which version of Data they are showing. This also means that when UI is disabled and doesn't run its LateUpdate(), it will only do it when it gets enabled again and sees that its version is not the same as the version of the data they are supposed to be representing.

USE "Component.enabled"

I think that because many people start using Unity experienced with Programming in general, we tend to stick to familiar logic, and some simple things like enabling & disabling a component may fall out of the scope. I make GameObject active/inactive a lot, but fiddling with individual components feels unsafe. I still have a habit of using a boolean "PauseUpdates" instead, but when I remember and do use "enabled" everything feels better.


Talking about UI. If you are using Text Mesh Pro (which you should, it is better) find TMPSettings Scriptable Object and configure it:

  • Set your default font

  • Disable Raycast Target


Here are some examples of a problem:

GetPlayerWeapon(int index) { }
GetPlayerArmor(int armorIndex){ }
GetPlayerArmorStat(int statIndex) {}

It is not hard to imagine a call to a function that looks like this:

var stat = GetPlayerArmorStat(armorIndex);

Which has an error, we sent armour index instead of stat index. And things can get even messier when you are working with many different indexes and ids. Items can have Prototypes(contains values that don't change, like Type, Max Durability) and States(values that are unique to each item, like Current Durability, Upgrades).

Proper naming can save you from logical mistakes, but there is still room for mechanical ones.

To avoid any confusion instead of:

GetPlayerArmor(int armorIndex){ }

I will have:

GetPlayerArmor(ArmorIndex armorIndex){ }


struct ArmorIndex  
  int index;

Yeah, it does look like a lot of work but makes life much easier. Especially when you can do cool stuff like this:

var armorState = player[armorIndex];
var weaponState = player[weaponIndex];

by placing the following syntaxes into the character class:

ArmorState this[ArmorIndex i] => _armorStates[i.index];

May look excessive to some. Totally understandable. But it becomes almost impossible to request something by the wrong index. Lets me sleep better.


While most early prototypes are very quiet, sound can be very useful from the very start of the development. For example: if the button didn't work but the click sound played, you can be sure that the function was called and the button itself works correctly. Same for hits, impacts. The sound will always let you know if the code executed to a certain point.


Create a _PROJECT folder in your Assets and put all your stuff there. You are likely to pull more things from the Asset store into your Assets folder, so having the project on its own is better. I tried to have a folder called ThirdPartyAssets and put all Asset store stuff in there, but it was a losing battle, many things went wrong. The underscore is needed to make sure it stays on the top.


Organizing your assets by Context, not by type. You are likely to have a folder called Materials early on. But if you get a model of a character with it's own Materials, Textures, Scripts, Animations maybe even Shaders, it would be a bad idea to break it apart into separate folders and mix Character Materials with UI Materials. So I have a rule: Context - first, Type - second. For Example:

 _Player Screen
        _Skill Window
               Scriptable Objects
        _Quests Window
        Scripts      // For Player Screen in general
        Textures    // For Player Screen in general
  Scripts        // For _Project in general
     Materials     // For _Project in general
     Shaders      // For _Project in general

The last Scripts, Materials and Shaders folder contains things that I use all throughout the project. Just like there are scripts that manage Player Screen, but Skill Window has its own stuff.


If I instantiate a bunch of objects, like default NPCs and then assign to them the correct outfit and face, I will also change so that in Hierarchy view (where you can see all the stuff in your scene) I can easily find them. So instead of Character(Instance), I will see Bob.


There is a Time.timeScale parameter that can be used to speed up/slow down your game. I always expose it to myself in some way: be it a slider or just pressing some button on the keyboard. Whenever testing the game you want to skip long animations or slow it down if something about it feels off.