Check out the gameplay of the finished game below:
What would this tutorial be good if we didn't had the luxury to play the game that we learned to develop in a mobile device, moreover, our tutorial series was inspired by the very successful games Temple Run, Subway Surfers.
We will be adding this game, the ability to be controlled by accelerometer/touch of a mobile device. In brief we will be learning how to port this game from a Windows platform to Android platform, of course you can follow the same procedure to port it ot iOS.
All we have to do to port this game to Android is change the PlayerControl script.
Before we go on to add some code to make it work with Android input, we will understand some facts about the Android/mobile input.
The Unity Input script reference says that, it assumes the X-axis parallel to the horizontal(shorter) side Y axis parallel to the vertical(longer) side and Z-axis is the one which pierces through the phone.
Now, we will see how to convert the Input.GetAxis to accelerometer control.When the game Starts we will save the Input.acceleration as a reference, zero reference that is. During the gameplay, we subtract the Input.acceleration with this zero reference and use the resulting X for the Input.GetAxis("Horizontal").
To implement this in our script we need to add some variables:
In the Start function, we will capture the Input.acceleration in the reference variable and set the current acceleration to zero.
The Update function is where we track the accelerometer input and the touch(tap to jump) input.
We get the current acceleration by using the Lerp function, Lerp function is basically used to find a point between the two end points, the result of which is being clamped by the value of the third parameter i.e. between 0 to 1.
Since we are interested in only the horizontal movement we only calculate the X-axis movement by clamping the value between -1 and 1.
Next we check if the screen is tapped by the user, this tap makes the character jump. There are various touch phases like TouchPhase.Began, TouchPhase.Ended and others.
For the touch/tap to be counted, the phase has to be other than Ended and Cancelled, for instance, it can be Began, Stationary.
This is all the logic we need. Now we need to use these values instead of the standard Input class.
The moveDirection will get it's value from
Finally, we make the character jump if the fingerCount value is greater than zero i.e., if there is a tap detected/swipe.
Add these changes in the existing script. You might ask, won't there be a conflict between the Touch and the Keyboard input? Well, this is when the Preprocessor Directives come into picture.
We use the
The complete script with both the Android and Keyboard input is as below:
Download the completed version of this game from the Resources page.What would this tutorial be good if we didn't had the luxury to play the game that we learned to develop in a mobile device, moreover, our tutorial series was inspired by the very successful games Temple Run, Subway Surfers.
We will be adding this game, the ability to be controlled by accelerometer/touch of a mobile device. In brief we will be learning how to port this game from a Windows platform to Android platform, of course you can follow the same procedure to port it ot iOS.
All we have to do to port this game to Android is change the PlayerControl script.
Before we go on to add some code to make it work with Android input, we will understand some facts about the Android/mobile input.
The Unity Input script reference says that, it assumes the X-axis parallel to the horizontal(shorter) side Y axis parallel to the vertical(longer) side and Z-axis is the one which pierces through the phone.
Now, we will see how to convert the Input.GetAxis to accelerometer control.When the game Starts we will save the Input.acceleration as a reference, zero reference that is. During the gameplay, we subtract the Input.acceleration with this zero reference and use the resulting X for the Input.GetAxis("Horizontal").
To implement this in our script we need to add some variables:
Vector3 zeroAcc; //zero reference input.acceleration Vector3 currentAcc; //In-game input.acceleration float sensitivityH = 3; //alter this to change the sensitivity of the accelerometer float smooth = 0.5f; //determines how smooth the acceleration(horizontal movement, in our case) control is float GetAxisH = 0; //variable used to hold the value equivalent to Input.GetAxis("Horizontal")
In the Start function, we will capture the Input.acceleration in the reference variable and set the current acceleration to zero.
zeroAcc = Input.acceleration; currentAcc = Vector3.zero;
The Update function is where we track the accelerometer input and the touch(tap to jump) input.
currentAcc = Vector3.Lerp(currentAcc, Input.acceleration-zeroAcc, Time.deltaTime/smooth); GetAxisH = Mathf.Clamp(currentAcc.x * sensitivityH, -1, 1); int fingerCount = 0; foreach (Touch touch in Input.touches) { if (touch.phase != TouchPhase.Ended && touch.phase != TouchPhase.Canceled) fingerCount++; }
We get the current acceleration by using the Lerp function, Lerp function is basically used to find a point between the two end points, the result of which is being clamped by the value of the third parameter i.e. between 0 to 1.
Since we are interested in only the horizontal movement we only calculate the X-axis movement by clamping the value between -1 and 1.
Next we check if the screen is tapped by the user, this tap makes the character jump. There are various touch phases like TouchPhase.Began, TouchPhase.Ended and others.
For the touch/tap to be counted, the phase has to be other than Ended and Cancelled, for instance, it can be Began, Stationary.
This is all the logic we need. Now we need to use these values instead of the standard Input class.
The moveDirection will get it's value from
moveDirection = new Vector3(GetAxisH, 0, 0);
Finally, we make the character jump if the fingerCount value is greater than zero i.e., if there is a tap detected/swipe.
if (fingerCount >= 1){ animation.Stop("run"); animation.Play("jump_pose"); jumpSound.Play(); gameObject.GetComponent().enabled = false; moveDirection.y = jumpSpeed; }
Add these changes in the existing script. You might ask, won't there be a conflict between the Touch and the Keyboard input? Well, this is when the Preprocessor Directives come into picture.
We use the
#if UNITY_ANDROID //some code that we want to be executed for Android platform only #endif
The complete script with both the Android and Keyboard input is as below:
using UnityEngine; using System.Collections; public class PlayerControl : MonoBehaviour { // Use this for initialization public GameControlScript control; CharacterController controller; public float speed = 6.0f; public float jumpSpeed = 8.0f; public float gravity = 20.0f; private Vector3 moveDirection = Vector3.zero; public CountdownScript count; //CountdownScript instance public PauseMenuScript pause; //PauseMenuScript instance //audio source reference variables public AudioSource powerupCollectSound; public AudioSource jumpSound; public AudioSource snagCollectSound; #if UNITY_ANDROID Vector3 zeroAcc; //zero reference input.acceleration Vector3 currentAcc; //In-game input.acceleration float sensitivityH = 3; //alter this to change the sensitivity of the accelerometer float smooth = 0.5f; //determines how smooth the acceleration(horizontal movement, in our case) control is float GetAxisH = 0; //variable used to hold the value equivalent to Input.GetAxis("Horizontal") #endif //start void Start () { //Debug.Log("Inside player control script start"); controller = GetComponent<CharacterController>(); #if UNITY_ANDROID zeroAcc = Input.acceleration; currentAcc = Vector3.zero; #endif } // Update is called once per frame void Update (){ //accelerometer and touch detection #if UNITY_ANDROID currentAcc = Vector3.Lerp(currentAcc, Input.acceleration-zeroAcc, Time.deltaTime/smooth); GetAxisH = Mathf.Clamp(currentAcc.x * sensitivityH, -1, 1); int fingerCount = 0; foreach (Touch touch in Input.touches) { if (touch.phase != TouchPhase.Ended && touch.phase != TouchPhase.Canceled) fingerCount++; } #endif //check if grounded and countdown is done with if (controller.isGrounded && count.isCountDown ) { // We are grounded, so recalculate // move direction directly from axes animation.Play("run"); //check if game is paused if(pause.paused==false) gameObject.GetComponent<AudioSource>().enabled = true; else gameObject.GetComponent<AudioSource>().enabled = false; moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, 0); #if UNITY_ANDROID moveDirection = new Vector3(GetAxisH, 0, 0); #endif moveDirection = transform.TransformDirection(moveDirection); moveDirection *= speed; jumpSound.Stop(); #if UNITY_ANDROID if (fingerCount >= 1){ animation.Stop("run"); animation.Play("jump_pose"); jumpSound.Play(); gameObject.GetComponent<AudioSource>().enabled = false; moveDirection.y = jumpSpeed; } #endif if (Input.GetButton ("Jump")) { animation.Stop("run"); animation.Play("jump_pose"); jumpSound.Play(); gameObject.GetComponent<AudioSource>().enabled = false; moveDirection.y = jumpSpeed; } } //disable run sound if game is over if(control.isGameOver){ gameObject.GetComponent<AudioSource>().enabled = false; } // Apply gravity moveDirection.y -= gravity * Time.deltaTime; // Move the controller controller.Move(moveDirection * Time.deltaTime); } void OnTriggerEnter(Collider other){ if(other.gameObject.name == "Powerup(Clone)") { powerupCollectSound.Play(); //play powerup collected sound control.PowerupCollected(); } else if(other.gameObject.name == "Obstacle(Clone)") { snagCollectSound.Play(); //play snag collected sound control.AlcoholCollected(); } Destroy(other.gameObject); } }
The Road Runner Tutorial 1: Setting Up The World
The Road Runner Tutorial 2: Setting Up The World Continued
The Road Runner Tutorial 3: Adding A Character To Our Game
The Road Runner Tutorial 4: Set The Ground Moving
The Road Runner Tutorial 5: Adding Snags and Powerups to Our Game
The Road Runner Tutorial 6: Collecting The Snags and Powerups
The Road Runner Tutorial 7: Adding Gameplay Logic
The Road Runner Tutorial 8: Creating a Custom GUI Skin
The Road Runner Tutorial 9: Creating a Pause Menu
The Road Runner Tutorial 10: Adding Countdown and Main Menu
The Road Runner Tutorial 11: Adding Sound Effects To Our Game
Why when i add the #if android stuffs in the play mode he cant walk to the left or right?
ReplyDeleteHi! Sujit please help us to switch controls in this game fro gyro to swipe e.g.if we swipe up player jumps ,swipe down player slides ,swipe right player moves right and swipe left. Thanx.
ReplyDeleteCheck the below link on Swipe Controls. This should give provide you a platform of what you want to achieve..
Deletehttp://www.thegamecontriver.com/2014/08/unity3d-swipe-input-for-touch-screen.html
This comment has been removed by the author.
ReplyDeleteWhere did you get count.isCountDown
ReplyDeleteHai Sujith Your tutorial is awesome, Its very helpful for me and I am a noob in unity, I am trying to do a racing game in unity android for that how can i destroy my car when it collide another vehicles or wall ?? Please help me
ReplyDeleteHow to port this game to Windows phone platform ???
ReplyDeletedid you mean "if(count is CountDownScript){}"
ReplyDeleteur dropbox link is not working
ReplyDeleteThis post gives best material to learn the processes of porting the game to Android. As a Gaming software developer, I get many knowledge from this post. Event App Android
ReplyDeletedo you still have your unitypackaage file?
ReplyDelete