STICK FLICK PENALTY KICK GAME 3: ADD GOALLINE TECHNOLOGY

Right now, we have a Penalty Shootout game where in we can shoot the ball by swiping the screen of our Mobile device. And yes, even the opponent has the capability to kick the ball. But, what we don't have is the ability to tell whether it's a goal or a no goal. Of course we can determine it by our naked eyes, but then, we will add the Goal Line technology to our penalty shootout game which will help us to determine if it's a goal or a no goal in all the cases no matter how close the call gets. We don't even need the referee! I mean. that's the advantage of creating a Game isn't it?

The gif of what we would achieve in this post is as below:
Notice the change in scores. Also notice that second shot of the opponent where the ball nearly crosses the GoalLine but doesn't and hence it is a No Goal



Swipe and you shoot. Then it's the trun of the opponent to shoot, so just tap on the screen and it will shoot in a random direction after 0.2 Seconds. Of course you need the Unity Remote to test this.

Right, so we have our Goalpost, if you maximize it to see what are it's children, you would find a child object named Goalline, this is nothing but a collider which has Is Trigger checked. By checking this field, we are basically doing this to check if the football has passed through it or even touched it.


If the Goalline object is not in position, reposition it at (-7.53501, 0.164206, 0.1216951)
If you check the tag of this object, you would discover that we have named it as GoalLine. We will use this in our code to check if it has been triggered.


If you have followed the previous posts, then you will have a script named SwipeControl. Double click on it to open it, if you don't have it open already.

Add a variable named triggered to check if the GoalLine is triggered.

public bool triggered = false;

Add the OnTriggerEnter function mentioned below:
 
//function to check if its a goal
void OnTriggerEnter(Collider other) {
//check if the football has triggered an object named GoalLine and triggered is not true
if(other.gameObject.name == "GoalLine" && !triggered){
//if the scorer is the player
if(turn==0)    
scorePlayer++; //increment the goals tally of player
//if the scorer is the opponent
else
scoreOpponent++; //increment the goals tally of opponent
triggered = true;       //check triggered to true
}       
}

The above function is a very simple one where in we check if the football has triggered an object named GoalLine (Line 4). If it has been triggered, we further check to see if the scorer is the Player (Line 6) or the Opponent (Line 9) and increment the score based on who the scorer is.

Next, we will add the OnGUI function to display the scores.

void OnGUI(){
//check if game is not over, if so, display the score
if(!isGameOver)    
{
GUI.Label(new Rect(10, 10, Screen.width/5, Screen.height/6),"PLAYER: "+(scorePlayer).ToString()); //display player's score
GUI.Label(new Rect(Screen.width-(Screen.width/6), 10, Screen.width/6, Screen.height/6), "OPPONENT: "+(scoreOpponent.ToString()));   //display opponent's score
}      
}

Pretty simple code which displays the score. If you have any issues, comment below.

Now, there is one thing remaining though, we need to set the triggered flag to false once the ball is returned to it's initial position. We will add it in the ReturnBall function as below:

IEnumerator ReturnBall() {
yield return new WaitForSeconds(5.0f);  //set a delay of 5 seconds before the ball is returned
rigidbody.velocity = Vector3.zero;   //set the velocity of the ball to zero
rigidbody.angularVelocity = Vector3.zero;  //set its angular vel to zero
transform.position = footballPos;   //re positon it to initial position
//take turns in shooting
if(turn==1)      
turn=0;    
else if(turn==0)
turn=1;
canShoot =true;     //set the canshoot flag to true
returned = true;     //set football returned flag to true as well
triggered = false;
}

There is one issue perhaps, the font size of the label is not dynamic. You can refer this post on Creating a Dynamic Menu to solve this issue.

The complete SwipeControl script is as below:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class SwipeControl : MonoBehaviour
{
 //variables for swipe input detection
 private Vector3 fp; //First finger position
 private Vector3 lp; //Last finger position
 private float dragDistance;  //Distance needed for a swipe to register
 
 //variables for determining the shot power and position
 public float power;  //power at which the ball is shot
 private Vector3 footballPos; //initial football position for replacing the ball at the same posiiton
 private float factor = 34f; // keep this factor constant, also used to determine force of shot
 
 public bool canShoot = true;  //flag to check if shot can be taken
 public int scorePlayer = 0;  //score of player
 public int scoreOpponent = 0; //score of oponent
 public int turn = 0;   //0 for striker, 1 for goalie
 public bool isGameOver = false; //flag for game over detection
 Vector3 oppKickDir;   //direction at which the ball is kicked by opponent
 public int shotsTaken = 0;  //number of rounds of penalties taken
 private bool returned = true;  //flag to check if the ball is returned to its initial position
 public bool isKickedPlayer = false; //flag to check if the player has kicked the ball
 public bool isKickedOpponent = false; //flag to check if the opponent has kicked the ball
 public bool triggered = false;



 void Start(){
  Time.timeScale = 1;    //set it to 1 on start so as to overcome the effects of restarting the game by script
  dragDistance = Screen.height*20/100; //20% of the screen should be swiped to shoot
  Physics.gravity = new Vector3(0, -20, 0); //reset the gravity of the ball to 20
  footballPos = transform.position;  //store the initial position of the football
 }
 
 // Update is called once per frame
 void Update()
 {
  if(returned){     //check if the football is in its initial position
   if(turn==0 && !isGameOver){ //if its users turn to shoot and if the game is not over
    playerLogic();   //call the playerLogic fucntion
   }
   else if(turn==1 && !isGameOver){ //if its opponent's turn to shoot
    opponentLogic(); //call the respective function
   }
  }
 }
 
 void playerLogic(){
  //Examine the touch inputs
  foreach (Touch touch in Input.touches)
  {
   if (touch.phase == TouchPhase.Began)
   {
    fp = touch.position;
    lp = touch.position; 
   }
   
   if (touch.phase == TouchPhase.Ended)
   {
    lp = touch.position; 
    //First check if it's actually a drag
    
    if (Mathf.Abs(lp.x - fp.x) > dragDistance || Mathf.Abs(lp.y - fp.y) > dragDistance)
    {   //It's a drag
     
     //x and y repesent force to be added in the x, y axes.
     float x = (lp.x - fp.x) / Screen.height * factor; 
     float y = (lp.y-fp.y)/Screen.height*factor;
     //Now check what direction the drag was
     //First check which axis
     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) && canShoot)  //If the movement was to the right)
      {   //Right move
       rigidbody.AddForce((new Vector3(x,10,15))*power); 
      }
      else
      {   //Left move
       rigidbody.AddForce((new Vector3(x,10,15))*power);
      }
     }
     else
     {   //the vertical movement is greater than the horizontal movement
      if (lp.y>fp.y)  //If the movement was up
      {   //Up move
       rigidbody.AddForce((new Vector3(x,y,15))*power);
      }
      else
      {   //Down move
       
      }
     }
    }
    canShoot = false;
    returned = false;
    isKickedPlayer = true;
    StartCoroutine(ReturnBall());
   }
   else
   {   //It's a tap
    
   }
  }
 }
 
 IEnumerator ReturnBall() {
  yield return new WaitForSeconds(5.0f);  //set a delay of 5 seconds before the ball is returned
  rigidbody.velocity = Vector3.zero;   //set the velocity of the ball to zero
  rigidbody.angularVelocity = Vector3.zero;  //set its angular vel to zero
  transform.position = footballPos;   //re positon it to initial position
  //take turns in shooting
  if(turn==1)      
   turn=0;    
  else if(turn==0)
   turn=1;
  canShoot =true;     //set the canshoot flag to true
  returned = true;     //set football returned flag to true as well
  triggered = false;
 }
 
 
 void opponentLogic(){
  //check for screen tap
  int fingerCount = 0;
  foreach (Touch touch in Input.touches) {
   if (touch.phase != TouchPhase.Ended && touch.phase != TouchPhase.Canceled)
    fingerCount++; 
  }
  //if tapped, the opponent will shoot the football after some time delay as mentioned below
  if(fingerCount>0){
   StartCoroutine(DelayAdd());  //add delay before the ball is shot
   isKickedOpponent = true;  //set opponent kicked to true
   shotsTaken++;    //increase set of penalty taken
   returned = false;   
   StartCoroutine(ReturnBall()); //return the ball back to its initial position
  }
 }
 
 IEnumerator DelayAdd() {
  yield return new WaitForSeconds(0.2f);  //I have added a delay of 0.2 seconds
  oppKickDir = new Vector3(Random.Range(-4f, 4f), Random.Range(5f, 10f), Random.Range(6f, 12f));     //generate a random x and y value in the range mentioned
  rigidbody.AddForce(oppKickDir, ForceMode.Impulse); //add the force 
 } 

 //function to check if its a goal
 void OnTriggerEnter(Collider other) {
  //check if the football has triggered an object named GoalLine and triggered is not true
  if(other.gameObject.name == "GoalLine" && !triggered){
   //if the scorer is the player
   if(turn==0)    
    scorePlayer++; //increment the goals tally of player
   //if the scorer is the opponent
   else
    scoreOpponent++; //increment the goals tally of opponent
   
   triggered = true;       //check triggered to true
   
  }       
 }
 
 void OnGUI(){
  //check if game is not over, if so, display the score
  if(!isGameOver)    
  {
   GUI.Label(new Rect(10, 10, Screen.width/5, Screen.height/6),"PLAYER: "+(scorePlayer).ToString()); //display player's score
   GUI.Label(new Rect(Screen.width-(Screen.width/6), 10, Screen.width/6, Screen.height/6), "OPPONENT: "+(scoreOpponent.ToString()));   //display opponent's score
  }      
 }
 

 
}

Perhaps, you might ask, we are not changing the value of the isGameOver flag, so it will always be false. Yes, that's a good question indeed. We will change this flag value once we write the logic to determine the winner of the shootout, which, of course, will be covered in the later posts.

See you around.

Stick Flick Penalty Kick Game 1: The Football Ground
Stick Flick Penalty Kick Game 2: Let's Shoot The Football
Stick Flick Penalty Kick Game 4: Goalkeeper Movement
Stick Flick Penalty Kick Game 5: Who Is The Winner?
Share on Google+

About Sujit Horakeri

Sujit Horakeri is a game freak just like any other next door guy you would come across. He is a Web Developer by Profession, Game Developer by Choice.
Connect with him on:
    Blogger
    Facebook

0 comments:

Post a Comment