In 2015 Airsource built its first game. After some research we chose to use Unity due to the multi-platform requirement and the significant amount of graphics and animations.
The first thing to say is that Unity is great!
- There is a really supportive community
- There are tons of free or very cheap pre-built assets you can drop in
- There is a good amount of native mobile support (iOS and Android)
- The development environment is easy to use and powerful, especially for rich graphics, particle animations etc
So now that I've convinced you it's the right tool for your project, here are my ten hot dev tips:
-
C Sharp You have two choices for development language, C Sharp and UnityScript (Javascript but with a syntax for slightly stronger typing). Even if you love Javascript (and I do!), I would still recommend C-Sharp for these reasons:
- Most of the pre-built Unity Store assets are written in C Sharp (JS ones would still work, it's just easier to read all code in the same language)
- You can use namespaces to easily segment your code
- It is easy for weird bugs to creep in with UnityScript due to loose typing and implicit declaration.
There's some good discussion on this in this post.
-
git There are a couple of tricks to get Unity working with git version control. In
Editor > Project Settings > Editor
, make Unity's meta files visible inVersion Control Mode
and switch toForce Text
in> Asset Serialization Mode
. You'll also need a.gitignore
file in the root of your repo to ignore changes to the files you don't want to check in. You can create one with this handy tool. -
Asset Store Before you write any code from scratch, have a good hunt round the Asset Store. It's not just graphic and animation assets, there are lots of full pre-built games and plugins, and most are free or surprisingly cheap considering their high quality.
-
Architecture The big architectural difference I found when working with Unity, is that it is better to attach scripts to individual game objects so they can look after their own state. This is a quite different approach to iOS or Android programming. For example, in iOS you might have a ViewController that disables its 'Refresh' button when it receives a callback that says the network is unreachable. In Unity you would do this quite differently. You would write a script ButtonEnabledIfNetwork, that periodically checked the network and set it's own state accordingly.
public class ButtonEnabledIfNetwork : MonoBehaviour { private const float REACHABILITY_INTERVAL = 0.2f; IEnumerator Start () { Button button = gameObject.GetComponent<Button> (); while (true) { button.interactable = Network.Instance.reachable; yield return new WaitForSeconds(REACHABILITY_INTERVAL); } } }
Now you can attach this same script to all buttons that you need to disable if there is no network. Plus it is efficient as it makes use of Unity's multi threading. Start() is a coroutine, Network is a singleton - both described below.
-
Coroutines Multi-threading is handled with coroutines in Unity and they are a vital part of programming for good performance in a game where multiple elements require updating (which is pretty much every game). In a coroutine you can hand back ('yield') control to the operating system at a sensible point in your execution, like at the end of a loop or while waiting for a network response. In the example above, we yield after we have updated the state of the button. You can yield for a single frame (by returning null), or for an approximate amount of time with the WaitForSeconds class. From then on Unity will handle all the threading for you, balancing requirements to prioritise the game's frame rate.
-
Singletons Singletons are tricky because it's likely you want the game object with the Singleton attached to stick around even when you change scenes. This Unity Wiki example uses DontDestroyOnLoad and it works well. I just removed the applicationIsQuitting stuff which seemed to cause more problems than it fixed in Unity 5.
-
Pre-fabs Pre-fabs are an amazing tool in Unity, but must be used with care. The principle is that you pre-fabricate a game object so you can re-use it throughout the application. Then when you or the runtime create the object you tweak some of the parameters, such as starting position, for that particular instance and away you go. Just take care with the three new buttons at the top of your inspector: If you hit Apply it will take any changes that you have made to this instance and apply them to all other instances based on this pre-fab. My solution to this was to have a hidden master pre-fab instance that I made changes to and then applied globally.
-
Animation 'Gotcha' This is a weird one: You can't drive game object parameters from code and animation, and I can't find this documented anywhere. If you even touch an animatable parameter from code all animations of this parameter will just stop working... If you need to do both you will need to work around this by nesting objects for example.
-
Serializable To store game state you will need to make the class serializable. You can customise serialization with the 'ISerializationSurrogate' interface. There's a good example here.
-
Script Unity I only started to get into this towards the end of the project, and it was the key thing I wish I'd started doing sooner. Personalising Unity to do the things you need for your project is one of the most powerful things about the IDE. If you find yourself doing some repetitive task when importing assets for example, write a quick plugin to do it. It's dead simple and will save you bags of time.
I hope these tips help with your Unity project. Happy coding.