50 Tips for working in Unity

edited in Tutorials
Source = Dev.Mag

About these tips
These tips are not all applicable to every project.
  • They are based on my experience with projects with small teams from 3 to 20 people.
  • There’s is a price for structure, re-usability, clarity, and so on — team size and project size determines whether that price should be paid.
  • Many tips are a matter of taste (there may be rivalling but equally good techniques for any tip listed here).
  • Some tips may fly in the face of conventional Unity development. For instance, using prefabs for specialisation instead of instances is very non-Unity-like, and the price is quite high (many times more prefabs than without it). Yet I have seen these tips pay off, even if they seem crazy.
Hope it's some good advice.

Comments

  • Very interesting and informative, thanks!

    I have a few questions though, at point 30 where you say you mustn't show properties in the inspector if they aren't needed, surely one could use [HideInInspector] or would that be bad for some reason?

    Also, something I've often wandered is how would you store...data...about types of objects in a game. For example if you had a game with 20 types of enemies each with their own plethora of stats, how would you go about storing that data? With prefabs? Creating assets of instances of ScriptableObjects? Even then, how would you go about referencing then? Would you just have a list something in a manager and list them all there?
  • I have a few questions though, at point 30 where you say you mustn't show properties in the inspector if they aren't needed, surely one could use [HideInInspector] or would that be bad for some reason?
    If you are using C#, you can also use C# properties, i.e. public float Health {get;set;}
  • Great read, very informative and all-round solid advice, thanks!
  • edited
    @D3zmodoz

    Making variables public is generally bad practice. Making a variable public says to your team mate (or your future-self: "change me! it is safe!" when it may well not be.

    In one game I worked on, I could not figure out how to make things die... just because all the variables were public (health, isAlive, and a bunch of others). It took a whole day to figure out how these all related to each other and actually make the actors die (and stay dead...)

    As for storing data, I always use prefabs.

    The details depends on many things (such as how they differ visually). One way to do it is to have two prefabs for each enemy. One is the art, physics and animation prefab. The other contains just the data. (See tips 17 and 33). This setup makes it easier to tweak game design data versus technical data or visual effects. The first prefab contains a reference to the second, so it is easy to access the data from code.

    Of course, when you start getting to 20, you may consider some other alternatives. Spreadsheets can work great (and are easy to read in as well). Using conditional formatting you can also make it very easy to see visually how enemies get stronger, or whether some value is way off.
  • This needs to be a sticky..
    Thanked by 1Rigormortis
  • Brilliant post Herman, agree on 99.999% of the stuff, and the rest is mostly just minor personal preferences that could go either way.

    In one game I worked on, I could not figure out how to make things die... just because all the variables were public (health, isAlive, and a bunch of others). It took a whole day to figure out how these all related to each other and actually make the actors die (and stay dead...)
    Gee, I wonder which one >.>

    On private vs public, vars should traditionally only be public if you specifically want them to be accessible outside your class. Unity complicates this by making public the way to expose stuff in the editor as well, but at least you can add [HideInInspector] to fields that should be publicly accessible in code, but designers shouldn't touch in the inspector. Otherwise default property setups are useful but potentially expensive:
    public bool Foo { get; set; }

    On storing large amounts of data, such as text and levels, XML is good (and a traditional way to do things) but we've found JSON actually works out better in some regards. It's less verbose, so less wasted space (eg in savegames) and because the structure maps objects pretty much exactly it's easier for everyone to understand. It also plays well with web services (more easily than XML) which helps in some things. There are some excellent json serialization/deserialization libs freely available for Unity that work just fine.

    On naming, I'm also a fan of Pascal case, and always have been. I also tend to despise underscores. One thing is causing me to lean towards all lowercase with underscores as separators though: Mac vs Windows and their handling of case. In theory sticking to Pascal case is ideal, but there are so many fringe cases where people use different capitalization for things, like Background vs BackGround and things get muddled, and this has led to issues. I dunno, still trying to decide where I fall on this.

    On referencing prefabs and never using strings for anything, for the most part I agree, but we found an interesting Unity bug that has led to us to using named prefab paths (aaaargh) instead of prefab references. Unity takes significantly longer to instantiate objects from a prefab reference compared to instantiating it from the prefab path on Android. As in almost an order of magnitude longer. We had epic loading time issues, switched to using named over references, and gained back minutes of load time!
  • Yes, JSON is really cool. Especially since it is already code (Python / Java Script), it's a breeze to write tools for it.

    The only reason why I still prefer XML, is because so many tools save in that format, so it's much easier to get something to edit the data.

    but we found an interesting Unity bug
    ... hmmm we have not experienced this bug... this is worrying.
  • Maybe you have.. what are your load times like on Android? ;)
  • edited
    Just as slow as anywhere else :( I'll check it out though...
  • This is a post of epic awesomeness... so epic I actually need to find time to interrogate it properly. Thanks for sharing.
  • Can also add on the XML front, including the C# system libs for parsing xml adds 1 meg to your compiled output. Not such a big deal on PC/Mac but can make a big difference on Web/Mobile
  • Otherwise default property setups are useful but potentially expensive
    How so?
  • edited
    How so?
    Call into a method vs direct referencing of a field. Not nearly as much of an issue as it used to be, and if Mono/Unity is as good at optimization as regular desktop .Net it should be reducing those to a field access anyway, but why take the risk. If you're accessing it once or twice a frame, no big deal, if it's something being referenced potentially thousands of times in loops and you do it all over the place, it could add up on mobile.

    It's just one of many tiny optimization choices that probably end up being more pedantic than they're worth :P
  • Call into a method vs direct referencing of a field.
    ok, I thought there may have been some special reason in the Unity framework - I think you would REALLY have to go out of your way for that to have an impact :)

    I still twitch slightly every time I declare a public variable though...
    8. Minimise using offsets for GUI components.
    Can you elaborate on this please? I haven't really gotten down to writing GUI's...
    19 [...] Use an empty game object as the prefab root. Do not use the mesh as the prefab root, and do not add any scripts to the mesh node.
    This makes sense, though I have some questions on what are good practices in this area...

    If I understand correctly, you should basically have a blank script in the root prefab that will have references to (typically) 3 other prefabs for MVC - but if I then drag that prefab into the scene the 3 other prefabs will not be instantiated automatically? Or am I misunderstanding? Or are you simply implying that for any prefab should be split into subobjects? Reading it again it seems like the latter is the case.... My concern is that I typically have (as is mentioned in pr0tip 17) two or more very similar prefabs. I guess there is no way getting out of duplicating a lot of work on either, considering that nested prefabs don't work?
  • edited
    @raithza
    8.

    Yes, that is worded a bit vaguely. It is basically to prevent this kind of thing:

    Parent container arbitrarily placed at (100, -50). Child, meant to be positioned at (10, 10), then placed at (90, 60) [relative to parent].

    This error is common when the container is invisible, or does not have a visual representation at all.

    19.

    I see I actually mean something other than what I wrote... o.0. What I mean is to add the mesh to a node, and then make the entire thing a prefab. Scripts should then be added to the root node. (Common practice is to make the mesh a prefab directly, and add scripts to that).

    The reason for this is that it is easy to replace the mesh without loosing any inspector values that may already have been tweaked.

    (I'll clarify the original article).

    Edit
    Hmmm I see 19 is actually three separate points that were mislabeled...grrr that's what happens if you do manual counting :(

    -

    There is a way to get the same benefits as you would from nested prefabs by linking in prefabs, and instantiating instances on Awake or Start.

    For instance, say we have two enemies with the same halo.
    Bot enemies, instead of having the halo attached to the enemy prefabs, just have a link to the halo prefab. When the enemies Awake, the halo prefab is spawned and attached to the right node.
  • There is a way to get the same benefits as you would from nested prefabs by linking in prefabs, and instantiating instances on Awake or Start.
    That is what I thought... of course this has the disadvantages of needing otherwise innecessary Instantiate calls in Awake, and that objects will appear different in the scene view than they would in game (which inevatibly occurs anyway...)

    Again, thanks for the article! I owe you a beer.

    p.s. you have a typo at nr 33:
    public class class [..]
  • This error is common when the container is invisible, or does not have a visual representation at all.
    It's also greatly compounded by Unity assigning seemingly arbitrary coordinates to newly created gameobjects. (Seems to try placing it in the centre of the screen, bit runs into problems figuring out a decent depth.) Having an editor script that creates a new gameobject at the world origin is easy and handy. :)
  • This thread is made of win and the article is awesome, thanks @hermantulleken!

    Adding my own hard-won knowledge to the pool: When creating geometry through code, never create a Mesh and then assign that to a newly created MeshFilter's mesh field. The MeshFilter already has a Mesh and you'll end up leaking a really, really tiny Vertex Buffer Object until the scene changes... Also, you need to manually destroy the MeshFilter's sharedMesh if it's something you've generated on the fly.

    Don't think many Unity users will be doing procedural generation stuff though, prefabs are usually easier.
  • Thanks guys, for the feedback and additional tips. Mind if I add some of these to the article?
Sign In or Register to comment.