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 5 of 9 of this article. Click here to view the first page.

Time to test

You already created a GameController object in the Hierarchy earlier and attached the GameController script to it, so you're all set there.

Select the GameController object in the Hierarchy panel, and you'll notice the GameController now has public properties for the player, scoreboard, and basketball. Set those to the appropriate objects in the Inspector by dragging and dropping.

Connecting objects to game controller in Unity's inspector

Now when you click on the play button you will see the time update as the GameController reduces the time every second!

Handling User Input

In many cases you’ll find yourself developing on your desktop machine, and porting over to an actual device with greater frequency as the project nears completion. Therefore you need to handle input in both contexts: from the device touchscreen, as well as the keyboard and mouse.

To do this, first add a helper method into GameController to detect whether the app is running on a mobile device or not:

public bool IsMobile{
	get{
		return (Application.platform == RuntimePlatform.IPhonePlayer || Application.platform == RuntimePlatform.Android); 	
	}
}

Luckily your design requires minimal interaction; all that is required is determining if a finger is down or not, the following snippet does just that.

public int TouchCount {
	get{
		if( IsMobile ){
			return Input.touchCount; 
		} else{
			// if its not consdered to be mobile then query the left mouse button, returning 1 if down or 0 if not  
			if( Input.GetMouseButton(0) ){
				return 1; 	
			} else{
				return 0; 
			}
		}
	}	
}

public int TouchDownCount {
	get{
		if( IsMobile ){
			int currentTouchDownCount = 0; 
			foreach( Touch touch in Input.touches ){
				if( touch.phase == TouchPhase.Began ){
					currentTouchDownCount++; 	
				}
			}

			return currentTouchDownCount;
		} else{
			if( Input.GetMouseButtonDown(0) ){
				return 1; 	
			} else{
				return 0; 
			}
		}
	}
}

To determine if the user is touching the screen or not you use the TocuhCount and TouchDownCount properties that branch depending on what platform the app is running on.

If it's running on the mobile platform then you query (and return) the Input class for the number of touches that have been detected, otherwise you assume we are running on your desktop and query the Input class if the MouseButton is down (returning 1) or not (returning 0).

The only difference between TouchCount and TouchDownCount is that TouchCount counts the number of fingers present on the screen regardless of their phase while TouchDownCount only counts those fingers whose phase is set to Began.

Node:The Touch class has an enumeration called TouchPhase, a touch phase is essentially the current state of the touch e.g. when first detected (when the finger first touches the screen) the touch will be assigned a Began phase, once moving the touch will be assigned the Moved phase, and when finally lifted off the touch will be assigned the Ended phase.

Node:The Touch class has an enumeration called TouchPhase, a touch phase is essentially the current state of the touch e.g. when first detected (when the finger first touches the screen) the touch will be assigned a Began phase, once moving the touch will be assigned the Moved phase, and when finally lifted off the touch will be assigned the Ended phase.

For a full overview of Unity's Input class, please refer to the official Unity site (http://docs.unity3d.com/Documentation/ScriptReference/Input.html).

Ball Handling: Dealing With Messages

Recall that the Ball object sends messages to GameController in the case of two events: when the ball goes through the net, and when it hits the ground.

Replace the OnBallCollisionEnter method to handle the case when the ball collides with the ground:

public void OnBallCollisionEnter (Collision collision)
{
    if (!player.IsHoldingBall) {
        if ((collision.transform.name == "Ground" ||
            collision.transform.name == "Court") &&
            player.State == Player.PlayerStateEnum.Throwing) {

            player.State = Player.PlayerStateEnum.Miss;

        }
    }
}

OnBallCollisionEnter() checks to see if the player is holding the ball. If not, then it’s assumed the ball has been thrown. Therefore, if the ball collides with the ground or the sides of the court, then the turn is over. If the ball hits the ground or the court and the player missed the hoop, then set the player state to Miss.

OnBallCollisionEnter() is called explicitly by the Ball Component and its HandleBasketBallOnNet event. How do you associate OnBallCollisionEnter() with the event from HandleBasketBallOnNet? You do this in the Start() method by registering 'interest' in the OnNet event.

You should add this in a new method called Start(), which is a good place to put initialization code like this:

void Start () {
	// register the event delegates 
	basketBall.OnNet += HandleBasketBallOnNet; 				
}

This is how you assign a callback to the event delegates. When the Ball raises the Net event, the HandleBasketBallOnNet method will be called.

Then add the implementation for HandleBasketBallOnNet as follows:

public void HandleBasketBallOnNet(){
	GamePoints += 3; 
	player.State = Player.PlayerStateEnum.Score;
}

Handling Messages from the Player Component

The other Component that communicates with the GameController is the Player. At this point the Player is only stubbed out, but here you'll implement the handling of messages and events in the GameController. The Player raises an event when an animation is finished playing, which in turn triggers an update in the GameController's game state.

Add the following code to the end of the Start() method to register for the event:

player.OnPlayerAnimationFinished += HandlePlayerOnPlayerAnimationFinished;

Along with its accompanying method:

public void HandlePlayerOnPlayerAnimationFinished (string animationName)
{
    if (player.State == Player.PlayerStateEnum.Walking) {
        player.State = Player.PlayerStateEnum.BouncingBall;
    }
}

This code updates the state of the Player to BouncingBall once he has finished walking.

The next portion of this tutorial will tie all of these events together and allow you to finally shoot a few hoops! :]

The Player: "Stubby" No More!

Here's a quick review of what the Player is responsible for and what functionality will be required:

  • During idle time, the Player should bounce the ball.
  • When in the Play game state, the Player should react to user input; in this case when the user holds their finger on the screen, the Player will ‘wind’ up for the throw.
  • The Player should affect the position of the Ball and influence its behavior.
  • The Player should move around the court after each turn.
  • The Player should animate based on the current state, e.g. show a winning animation when the ball goes through the hoop and a disappointed animation when the ball misses.
  • The Player should notify the GameController when each of the above animations completes.

Head back and open up the Player script, and lets slowly make your way through the code.