Thursday 12 October 2017

Updating our C# code



Updating our C# code

We need to drop boxes until all available box are done. The easiest way to do this is by using prefabs. Prefabs are reusable game object which you can use on multiple scenes, multiple times maintaining same properties.

Lets create prefab for our drop box. Create folder inside assets folder and call it Prefabs. Drag and drop our box inside this new folder. Notice the game object is highlighted in blue to show it is an instance of a prefab (object oriented programming knowledge needed to understand what an instance is - copy of game object in simple terms).




Lets now change our code to accommodate the new prefab.

Declare game object dropbox to hold our prefab: public GameObject dropbox;

Set totalboxes to 40 : int totalboxes =40;

set dropped box to 0 int boxdropped=0;


We need to check in the update function whether we have dropped all boxes. The game runs till all boxes are dropped


if ( boxdropped <= totalboxes) {

}


We need to check every time the box is destroyed, we create new one:

if (collid) {

}


Declare variable bool collid = false; On collision, set to true and on creating new one set false




void Update () {
if (collid) {
if (boxdropped <= totalboxes) {

}
collid = false;
}
}



void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag == "box") {
boxescollected += 1;
Destroy (other.gameObject);
collid = true;
}

}


Set collid to true inside start to star droping box


void Start () {
collid = true;
}


Create new instance of box if there is none on the scene and place at y=2.


Instantiate(dropbox, new Vector2(0,2), Quaternion.identity);


Save code and click our catch up game object in hierarchy. Check the script component and drag our prefab from prefab folder to its dropbox.



Delete the box in the hierarchy and not the prefab folder.
 


Save project and run. The boxes should drop till there are all collected.



The complete code is here:


using UnityEngine;
using System.Collections;

public class CatchBox : MonoBehaviour {
int boxescollected =0;
int totalboxes =40,boxdropped=0;
public GameObject dropbox;
bool collid = false;
// Use this for initialization
void Start () {
collid = true;
}

// Update is called once per frame
void Update () {
if (collid) {
if (boxdropped <= totalboxes) {
Instantiate(dropbox, new Vector2(0,2), Quaternion.identity);
}
collid = false;
}
}
void OnCollisionEnter(Collision other)
{
if (other.gameObject.tag == "box") {
boxescollected += 1;
Destroy (other.gameObject);
collid = true;
}

}
void OnGUI()
{
GUI.Label (new Rect (10,10, 300, 50), "Boxes collected: " + boxescollected);
}
}


The game is stagnant. We need to move the catch up and also determine the missed box.

Completing the game code 

Before we proceed to final steps to make this game interesting, there are few thing by now you should know
  1. You can replace boxes with any 2D object from asset store to create a game.
  2. You can change the material, color and texture of boxes.
  3. I will post final code and explain. It helps to learn how I arrived at it by checking the pseudo code. This is the only way you can learn to create a good game.

Our goal is to fix

Move playerbox
if collected
increase boxcollected by one
print boxcollected
end if


in the pseudocode

Moving the collect box
Our game only collects boxes. A box falls from the same position and falls down to the same x position. This doesn't well represent our intention for the game. We can now advance our game to allow us
1. Move the box at the bottom to be able to collect box at any x position.
2. Vary the position x from where the box is dropped to increase difficulty. This would end up defining our levels.

The main focus now is ability to move the bottom box to the right or left. We are developing for android and hence we can utilize the touch setting of android devices. When user swipes to the right or left, our box should move to the same direction. This can be achieved by changing the x position of the box at the bottom. We need to check if the user just tapped or they swiped. This way you can move on swipe and no action, for now, on tap.
To also make the game more interesting, we will now generate box from any random position. We also need to check whether the box is collected or not.

Therefore
1. We move box by swipe right or left.
2. Determine if box is collected or not by introducing floor where if the box fall on it, we missed it.
3. Generate the box from random point

As final step in our basic game development, we will add code to move the box right and left , add lose or win for better game play and generate box from random points. this clearly marks our levels but you can also do level based on another criteria say for every 100 boxes collected increase speed.

Add  variable to store how fast we move the box  
public float MovementSpeed = 1; //speed in meter per second

Add new vector variable  
Vector3 moveDir = Vector3.zero;
 


Add this to update
moveDir.x = Input.GetAxis("Horizontal"); // get result of AD keys in X
This get the horizontal x distance to move based on key pressed.
 
then move our box
transform.position += moveDir * MovementSpeed * Time.deltaTime;
 
 
You can test py pressing play button and use arrow keys
 
To support touch screen on android ,add the following variables
 
private Vector3 fp;

private Vector3 lp;

 private float dragDistance=0.2f;


 add this above 
transform.position += moveDir * MovementSpeed * Time.deltaTime; 
 code
 
See in the code below section for complete code
         #if UNITY_ANDROID || UNITY_IPHONE  // Cap letters
 
 
         #endif   
 
 
To check lose and win,  add a box below our catchup, enlarge to 
fill screen width and reduce height and call it loss and give it a 
tag loss

Add the new variable
int boxeslost =0; 
 
add the following in the update below


if (collid) {
if (boxdropped <= totalboxes) {
Instantiate(dropbox, new Vector2(0,2), Quaternion.identity);
}
collid = false;
}

if (GameObject.FindGameObjectWithTag ("box").transform.position.y < transform.position.y + 0.1) {
Destroy (GameObject.FindGameObjectWithTag ("box"));
collid = true;
boxeslost += 1;
}


You will be getting position of box and compare with catch up. 
If below, destroy and add boxes lost
 
 
Add this in GUI function


GUI.Label (new Rect (10,30, 300, 50), "Boxes lost: " + boxeslost);

  
 We now generate from random places
add new variable at start of update
int rand = Random.Range (-5,5);
 change our x value in
 Instantiate(dropbox, new Vector2(rand,2), Quaternion.identity); 

This is just a basic game. You can advance it further like adding
1. random movement downwards by changing x value
2. introduce obstacles and more



The complete code


using UnityEngine;
using System.Collections;

public class CatchBox : MonoBehaviour {
    int boxescollected =0;
    int boxeslost =0;
    int totalboxes =40,boxdropped=0;
    public GameObject dropbox;
    bool collid = false;

    private Vector3 fp;
    private Vector3 lp;
    private float dragDistance=0.2f;
    public float MovementSpeed = 1;
    Vector3 moveDir = Vector3.zero;

    // Use this for initialization
    void Start () {
        collid = true;

    }

    // Update is called once per frame
    void Update () {

        int rand = Random.Range (-5,5);
            if (collid) {
            if (boxdropped <= totalboxes) {
                Instantiate(dropbox, new Vector2(rand,2), Quaternion.identity);
            }
            collid = false;
        }

        if (GameObject.FindGameObjectWithTag ("box").transform.position.y < transform.position.y + 0.1) {
            Destroy (GameObject.FindGameObjectWithTag ("box"));
            collid = true;
            boxeslost += 1;
        }

        moveDir.x = Input.GetAxis("Horizontal"); // get result of AD keys in X


        #if UNITY_ANDROID || UNITY_IPHONE  // Cap letters

        if (Input.touchCount>0) // user is touching the screen with a single touch
        {
            Touch touch = Input.GetTouch(0); // get the touch
            if (touch.phase == TouchPhase.Began) //check for the first touch
            {
                fp = touch.position;
                lp = touch.position;
            }
            else if (touch.phase == TouchPhase.Moved) // update the last position based on where they moved
            {
                lp = touch.position;
            }
            else if (touch.phase == TouchPhase.Ended) //check if the finger is removed from the screen
            {
                lp = touch.position;  //last touch position. Ommitted if you use list

                //Check if drag distance is greater than 20% of the screen height
                if (Mathf.Abs(lp.x - fp.x) > dragDistance || Mathf.Abs(lp.y - fp.y) > dragDistance)
                {//It's a drag
                    //check if the drag is vertical or horizontal

                    if (Mathf.Abs(lp.x - fp.x) > Mathf.Abs(lp.y - fp.y))
                    {   //If the horizontal movement is greater than the vertical movement...
                        if ((lp.x > fp.x))  //If the movement was to the right)
                        { 
                            //Right swipe
                            // move box right    
                            MovementSpeed = MovementSpeed;
                        }
                        else
                        {   //Left swipe
                            // move box left
                            MovementSpeed = MovementSpeed * -1;
                        }


                    }
                    else
                    {   //the vertical movement is greater than the horizontal movement
                        if (lp.y > fp.y)  //If the movement was up
                        {   //Up swipe
                            // you can add code to move box up on advance levels to evade obstacle
                        }
                        else
                        { 
                            // you can increase speed to advance levels
                        }



                    }
                }
            }
            else
            {   //It's a tap as the drag distance is less than 20% of the screen height

                //you can tap code to attack obstacle and clear way on advance levels
            }
        }


        #endif

        transform.position += moveDir * MovementSpeed * Time.deltaTime;
    }



    void OnCollisionEnter(Collision other)
    {
        if (other.gameObject.tag == "box") {
            boxescollected += 1;
            Destroy (other.gameObject);
            collid = true;
        }


    }
    void OnGUI()
    {
        GUI.Label (new Rect (10,10, 300, 50), "Boxes collected: " + boxescollected);
        GUI.Label (new Rect (10,30, 300, 50), "Boxes lost: " + boxeslost);
    }


        
}