Intermediate Unity 3D for iOS: Part 2/3

This is a tutorial by Joshua Newnham, the founder of We Make Play, an independent studio crafting creative digital play for emerging platforms. Welcome back to our Intermediate Unity 3D for iOS tutorial series! In this tutorial series, you are learning how to create a simple 3D game in Unity called “Nothing but Net”. In […] By .

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 8 of this article. Click here to view the first page.

Time to test

Before continuing, lets make sure everything is functioning as expected. To do this we’ll create a new script that will update the time and score of your scoreboard. Create a new script called ScoreboardTest and copy the following code into the script:

using UnityEngine;
using System.Collections;

public class ScoreBoardTest : MonoBehaviour
{        

    public ScoreBoard scoreboard; 

    public void Start()
    {
        scoreboard.SetTime( "60" );
        scoreboard.SetPoints( "100" );
    }

}

Next click GameObject\Create Empty, rename the object to ScoreboardTest, and attach your ScoreBoardTest script to it (again by dragging it on top). Then link up the scene’s scoreboard GameObject with the ScoreBoardTest scoreboard variable and press play.

w00t it works – you should see the text on the scoreboard change as in the above screenshot! If not, trace back your steps to see what might have gone wrong.

Controlling Collisions

Now it’s time to take a look at how Unity handles object collisions.

Recall that the Ball object is responsible for notifying the GameController when it goes through the net and/or hits the ground. The Ball object is attached to a Sphere Collider and Rigidbody , which allows you to detect and react to collisions. In your script, you can listen for those collisions and notify the Game Controller appropriately.

Like you did before, create a new script and name it Ball. Then edit it in MonoDevelop as follows:

using UnityEngine;
using System.Collections;

[RequireComponent (typeof(SphereCollider))]
[RequireComponent (typeof(Rigidbody))]
public class Ball : MonoBehaviour
{

    private Transform _transform;
    private Rigidbody _rigidbody;
    private SphereCollider _sphereCollider; 

    public delegate void Net ();

    public Net OnNet = null;
    private GameController _gameController;

    void Awake ()
    {
        _transform = GetComponent<Transform>();
        _rigidbody = GetComponent<Rigidbody>();
        _sphereCollider = GetComponent<SphereCollider>();
    }

    void Start ()
    {         
        _gameController = GameController.SharedInstance;
    }

    void Update ()
    {

    }

    public Transform BallTransform {
        get {
            return _transform; 
        }   
    }

    public Rigidbody BallRigidbody {
        get {
            return _rigidbody;  
        }
    }

    public SphereCollider BallCollider {
        get {
            return _sphereCollider;     
        }
    }

    public void OnCollisionEnter (Collision collision)
    {
        _gameController.OnBallCollisionEnter (collision);
    }

    public void OnTriggerEnter (Collider collider)
    {
        if (collider.transform.name.Equals ("LeftHoop_001")) {
            if (OnNet != null) {
                OnNet ();    
            }   
        }
    }
}

Note: Because of dependences between objects and the GameController, several required methods need to be stubbed out with an empty method signature that will be implemented later. In this case, the OnBallCollision() instance method and SharedInstance() class method have been stubbed out.

Here’s an overview of the new concepts introduced in this script, code block by code block:

[RequireComponent (typeof (SphereCollider))]
[RequireComponent (typeof (Rigidbody))]

Unity provides class attributes that allow you to add design time logic to your classes. In this case you’re telling Unity that this script is dependent on a SphereCollider and RigidBody Components being attached to this script.

This is a good habit to get into, especially when your projects start growing in size as it provides a way of automatically adding dependent Components to your script thus avoiding unnecessary bugs.

private Transform _transform;
private Rigidbody _rigidbody;
private SphereCollider _sphereCollider; 

void Awake ()
{
    _transform = GetComponent<Transform>();
    _rigidbody = GetComponent<Rigidbody>();
    _sphereCollider = GetComponent<SphereCollider>();
}

The GetComponent() method is inherited by the MonoBehaviour class and provides a way of searching the local GameObject for a specific type of Component. If none exists then null is returned otherwise the Component is returned. Because it requires traversing through the GameObject’s components is always a good idea to cache them locally when frequent access is required (such as when you need them in either the Update() or FixedUpdate() methods).

private GameController _gameController; 

void Start () {			
    _gameController = GameController.SharedInstance; 
}

This object needs a reference to the Game Controller, so it can notify it of events such as collisions. The Game Controller will be a singleton, and you’ll be able to access it via the SharedInstance static property.

public delegate void Net();
public Net OnNet = null;

If you haven’t worked with C# before, the delegate and event may look a little foreign. Essentially, they provide a method of communication between Components. In this case, the external Component would register interest in the OnNet event, and in doing so, will be updated when an OnNet event is raised by the Ball script (implementation of the Observer pattern). This is a very similar concept to the delegate pattern used in iOS programming.

public void OnCollisionEnter( Collision collision ){
    _gameController.OnBallCollisionEnter( collision );
}

The main task of the Ball is to notify GameController each time the Ball goes through the net and/or hits the ground. Since the Ball has a Rigidbody attached, when it collides with the BoxCollider Component of the Ground object, the Physics engine will send notification via the OnCollisionEnter() method.

The Collision parameter passed in gives details about the collision, including which object the Ball collided with. In this case, just pass the details onto the GameController to figure out what to do with it. :]

Note: along with OnCollisionEnter(), there are also OnCollisionStay() and OnCollisionExit() methods, which are called each frame as an object is colliding with something else, and when it stops colliding, respectively. For more details, check out the official Unity documentation at http://docs.unity3d.com/Documentation/ScriptReference/MonoBehaviour.html.

public void OnTriggerEnter( Collider collider ) {
    if( collider.transform.name.Equals ( "LeftHoop_001" ) ) {
        if( OnNet != null ){
            OnNet(); 	
        }	
    }		
}

The above code detects when the ball passes through the net. Remember how in the last tutorial you set up a special box collider right below the net and saved it as a trigger?

Well, since this is not technically a “collision”, there is a separate callback named OnTriggerEnter() (as well as OnTriggerStay() and OnTriggerExit()) that gets called when a collision with a trigger occurs.

Here, you check which object is involved with the collision event. If it happens to be the hoop’s trigger, then you let the GameController know about it via the OnNet method discussed above.

And that’s it! Note you can’t attach the script to the basketball object in Unity yet, because this script depends on the GameController object, which you haven’t created yet.

That takes care of the ball — but now the Player needs to play a part in this game! :] But before we do lets make sure everything is working as expected.