Friday, June 22, 2012

Unity Coding Tutorial pt 1

Well, I've missed my one post a week deadline pretty hard core. Well that's something.

I wanted to do a couple brief Unity tutorials, since I really had a hard time searching the internet to find one that I liked and taught the things I wanted to learn. This tutorial assumes you know at least a little bit about Unity (how to open a script, attach it to an object, what a scene is, etc) and some general things about coding and C#.

Let's begin.

MonoBehaviour.

When you create a new C# script, you'll notice that it comes automatically inherited from MonoBehaviour, and has two functions created, Start and Update. Unless a script is inherited from MonoBehaviour, it cannot be attached to an object, so keep that in mind. Of course, if you're doing a larger project, you'll have many scripts that do not inherit from MonoBehaviour, but in general most of your scripts will ultimately want to be derived from it. At the beginning of every scene, Unity will go through all MonoBehaviours that are active in the scene (and whose gameObjects that its attached to is active) and will call Start() on them. It will also call a function called Awake() before it calls Start(), so keep that in mind if you have some pre-setup you ever need to do in a sequential manner. Then, ever frame of the scene, it will also call Update() on every single active MonoBehaviour in the scene. There are many other over loadable functions in MonoBehaviour that you can use and are called at different times, most of which you can view here:

http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.html

Now, since Update() is called once per frame for every active MonoBehaviour, its a good idea to try to keep this as simple as possible. Its easy to bog this function down and slow your game drastically to the point of being unplayable. Try to declare any complicated variables in Start() or Awake(), so that way in Update you don't have to keep building something every time to use it, it will already be there for you to use. Keep in mind, these functions will only be called for scripts that are attached to gameObjects int the scene.

Variables.

Unity is very nice about variables. By making a variable public in your C# script, you can actually change its value in the editor! This include strings, integers, floating point numbers, and more. Even gameObjects and transforms can be assigned. If you make a variable called public GameObject publicObj, this will appear in the inspector, and you can drag and drop the object that you want to be able to access in your code! You can even give your variables a default value, but the game will use whatever value is in the editor over whats in code. This is a very powerful strategy to use when you code. It is assigned and created and able to be referenced and you don't even have to worry about your game being bogged down to have to go and find it, it will have the object from the get go.

public GameObject myObj;

void Awake()
{
   if(myObj != null)
       Debug.Log(myObj.name);
   else
      Debug.Log("You forgot to assign myObj!");
 }

It is very nice. Another thing you can do which is very powerful is to instantiate a prefabbed object. You can do that the function Instantiate.

public GameObject bullet;
public GameObject firingLocation;

void Update()
{
     if(Input.GetKeyDown("space")
         Instantiate(bullet, firingLocation.transform.position, firingLocation.transform.rotation);
}

This code will instantiate whatever gameObject bullet is at firingLocation's position and with firingLocation's rotation (i,e., facing the same way). There is a way to make your own classes able to be setup in the main menu, however this is a little more advanced so I'll save it for a later tutorial.

Another very powerful aspect of variables is public arrays. If you say public string[] Messages, this will an editable variable called Messages in the editor that you can even specify the size of! Say you wanted to play a random audio clip at the start of a scene.

public AudioClip[] playAtStart;

void Start()
{
    if(playAtStart.Length > 0)
      audio.PlayOneShot(playAtStart[Random.Range(0, playAtStart.Length)]);
   else
     Debug.Log("You didn't set up playAtStart");
}

Some objects though, you can't set up in the editor (or it's very impractical to). There is a very convenient  (although very slow) function called GameObject.Find. There are a couple different versions of this function, but the only one I would ever use is FindGameObjectsWithTag(string tagname). This will return an array of GameObjects who have a tag that matches the given argument. DON'T EVER USE THIS FUNCTION OR ANY OTHER FIND FUNCTIONS OUTSIDE OF START OR AWAKE. It will bog down your program to unusable with even the simplest of scenes. If you don't know what a tag is or how to give one to an object, here's a good reference :

http://unity3d.com/support/documentation/Components/Tags.html

Collisions.

Collisions are a very important part of almost any game. MonoBehaviour has two very nice functions for collisions, OnCollisionEnter and OnTriggerEnter. But first, let's learn how to trigger these functions. In order for a MonoBehaviour have one of these functions called, there must a Collider on the object. In the editor, you'll notice a trigger checkbox. If you check it, the collider essentially becomes a trigger. A trigger is not actually a physical object like a wall or anything else. You can go right through it, however it will still recognize that you entered it. Triggers are useful for a broad spectrum of things, such as detecting which lane a player entered, when to trigger an audio clip, and thousands more. Both objects will need a collider attached to them and (in almost every case) a RigidBody. If its a custom that you made in Maya or Blender another software, it will most likely need to be checked "Convex" as well. If for some reason you OnCollisionEnter is not working, out a Debug.Log("Here") at the start of the function and play with these settings on both objects till you get it working. Let's re-visit that bullet example. Since OnCollisionEnter will be called for any object that interacts with it, chances are we wanna only do certain thing's for certain objects. Tags are a great way to do this.

class Enemy : MonoBehaviour {

void OnCollisionEnter(Collision col)
{
   Debug.Log("Collision Detected");
   if(col.gameObject.tag == "Bullet")
       Destroy(gameObject);
}

}

This code will destroy whatever gameObject is attached to when it collides with an object with a tag "Bullet." You can easily set up a trigger as well.

class PlayAudio : MonoBehaviour {

public AudioClip enterRoomSound;

void OnTriggerEnter(Collider col)
{
   Debug.Log("Trigger Detected");
   if(col.gameObject.tag == "Player" && enterRoomSound)
   {
    audio.PlayOneShot(enterRoomSound);
   }

}
You could use this to play enemy noise when you enter the room to let the player know that there are enemies here. Notice that OnCollisionEnter takes a Collision as an argument and OnTriggerEnter takes a Collider. If you don't have these arguments, Unity will complain. Obviously, OnTriggerEnter will be called for objects whose collider is marked as a trigger, and OnCollisionEnter otherwise.


I hope this helped a few people get a start in Unity and get them making games. Practice makes perfect, try to do a couple test scenes on your own. Next tutorial, I would like to go over a couple tricks I've learned, as well as maybe some GUI elements.

--daviD Ward