Workshop 1 presented by Bryan on Friday, September 6, 2013.
Download the workshop unity package, start a new Unity project, then import the package to view inside Unity.
Customize Your Default Template
You can customize the default C# script template. The C# template file is called 81-C# Script-NewBehaviourScript.cs.txt and can be found in C:\Program Files (x86)\Unity\Editor\Data\Resources\ScriptTemplates. A sample template is included with the workshop project materials.
Inspector properties are just variables declared with the public keyword. I like to keep them at the head of the source code so that they are easier for team mate's to find. Remember to include useful XML comments (see below) so your team mates understand the purpose of the property.
But what if you need a public property that is accessible from other scripts but DOES'T appear in the inspector? Use the [HideInInspector] attribute.
What if you need more control over the accessibility of the property? Use a property with a getter and setter. See Example2.cs.
Be sure to XML code comments because they provide the necessary metadata for the code hinting system in MonoDevelop.
Public and Private
Classes, methods, and variables are considered private by default. The Unity style guide recommends avoiding the use of the private keyword and only specifying public where necessary. I recommend that you explicitly use both public and private. By getting in the habit of using both public and private, you will find that you have to make a conscious decision about the scope of your code elements. I feel it also improves code readability.
MonoBehaviour vs. Plain Old Classes
Unity creates all new scripts as MonoBehaviours but sometimes you don't need all the scaffolding and overhead that comes with that. Use MonoBehaviour when you need to script a GameObject, require an Update() loop, need Coroutines, or or need to draw a GUI. Use plain old classes for your utility functions, data structures, and anything that sits outside the normal per-frame update loop.
GameObject, where are you?
On occasion your scripts will need to find another game object within the scene to do that you will one of the Find() methods provided by the GameObject class. Find() is expensive so you should minimize the number of calls to Find() as much as possible. Avoid using Find inside your Update(), FixedUpdate(), and OnGui loops as this will kill performance.
Most Unity examples show you how to find a GameObject by name but you can also find them by type. Searching by type has advantages:
- The compiler can check the name at compile time avoiding runtime errors.
- If you need to change the name of the type, you can use the refactoring capability of MonoDevelop to intelligently update all references to the type name. You can't do this as easily for strings - sure, you can do a global search and replace, but that leads to erroneously changing partial matches and comment words which should have been excluded from the search.
- Finding objects by type puts the power in the hands of the programmer. You don't have to worry about your level designer changing the name of an object and forgetting to tell you. Even if someone changes the name of an object, the compiler will catch the error.
Embrace and Extend
Extend the MonoBehaviour class whenever you have shared functionality across different types. For example, your game has several different types of enemies all of which have Health, Strength, and Speed properties. Extend the MonoBehaviour class as type Enemy and from there you can create Orc, Goblin, and Kobald without having to repeat work. You can make updates in one place, the Enemy class, and you get the added benefit of being able to find all enemies within a scene by doing a GameObject.FindObjectsOfType(typeof(Enemy)).
Avoid Null Reference Exceptions
Avoid null reference exceptions by checking for null before referencing an object. Improperly handled null references can lead to unpredictable runtime behavior. Remember, null in and of itself is not an error, it's a valid value often returned by a property or method when the requested object does not exist.
Avoid chaining possible null references like:
Think Outside the Box
C# is a fully featured modern programming language. Leverage the full power the .NET 2.0 Framework gives you.
Make use of dynamic data structures provided by System.Collections.Generic such as List<T> and Dictionary<T,U>. Dynamic data structures can grow and shrink with little cost whereas array resize operations are quite expensive. Plus you can LINQ operations on them... huh? Look it up: Introduction to LINQ
Always feel free to stop by my office if you have questions.
Bryan (firstname.lastname@example.org) Room 3109 (by Optimus Prime)