Footy volley gameplay – part 6

 estimated time : 12 mn
ingredients needed : Unity, Playmaker
(this recipe is part of the footvolley game menu )

Detailed Steps

Testing the gameplay by sending back the ball :
Detect when ball touches the ground.
Create the opponent aim.
Instantiate the opponent aim and make it disappear.
Sent back the ball.
Tweak vars.
New Feature : Slide.


We can kick a ball right ahead; well that’s not so funny for the moment.
So let’s test how it feels to receive the ball on our side of the field.

The plan is to choose a random point on our side when the ball collides with ground, display an aim to the point where the ball will go , to give the player a chance to anticipate where to go; then make this aim disappear.

00:05 Colliding with the ground

Create a field tag, assign it to terrainL & terrainR

On Soccer ball FSM, in the “Kicked” state, add the action:trigger Event, select “field” as collide Tag.
As send event, create a “onGround” event. Meaning that when our ball will collide with the ground, we sent the grounded event.
create a new state : “Grounded”
Now add the transition onGround, and link it to our “Grounded” state.

on Grounded state add the action “send message”, and use the SentBackBall method, which will be detailed later.
We’ll create an aim for the opponent first.

02:00 Creating the opponent aim

Create a new gameObject, call it “Player2Aim”,then duplicate the Player1’s aim object, and drag & drop it into our Player2Aim, reset it x,y and z pos to 0, but do not change it’s rotation.
Then drag and drop it into our Resources folder. Once it’s done, we add to our new Player2Aim a script to destroy the gameObject, we’ll set to be destroyed under 1 second.

Don’t forget to delete the new created Player2Aim on scene. Also remove from our Player2Aim the rigidbody and collider components, it’s no use for this one as it’s only a display hint made for the player.

Why did we create a gameObject as container for the player2Aim ? because when we will be instantiate the player2aim on scene, the container gameObject position and rotation will be reset at zero value, including its rotation, so we just prevent it this way.

Now create ou SentBackBall() function, by adding to our ball script :

void SentBackBall(){
 start_pos = this.transform.position;
 //the same function than in our playerController resetAimPos()
 //but for the other side of the field
 float  xmin =(gameManager.terrainL.transform.position.x-(gameManager.terrainL.size.x/2));
 float xmax = (gameManager.terrainL.transform.position.x+(gameManager.terrainL.size.x/2))-gameManager.aimWidth;
 float zmin = ((gameManager.terrainL.size.z/2)*-1);
 float zmax = (gameManager.terrainL.size.z/2);
  Vector3 pos = new Vector3 (Random.Range (xmin, xmax), gameManager.terrainL.transform.position.y, Random.Range (zmin, zmax));
 //instantiate an aim gameobject as visible hint for the player 
  GameObject clone = Instantiate(Resources.Load("player2Aim"),pos,Quaternion.identity) as GameObject;
 //here we set our ending position
 end_pos = pos;
 //we reset the main force & height of the ball
 gameManager.power = 0;
 gameManager.aimScale =5;
 //now we shoot the ball back

Reminder :

Yes, we can reset more ‘properly’ our power and aimScale vars.
With a default variable for start, and within a clean function with an explicit name like “resetThoseDamnVars”.
But remember we’re prototyping here, the main purpose is to be fast, and you’ll more likely to go back and forth along the same function changing little things(even deleting those vars at the end); So let’s concentrate on making the proto work first, then we can come back and clean all the stuff.

Let’s test a little : ok, tweak the speed vars in order to be fair.

05:27 Let’s Slide !


We’re now adding a new (and final) move : the slide.

If the player is at the total opposite side of the field, he shouldn’t be able to reach the ball before it hits the ground.
But to compensate this (remember the positive/negative tweaks in a gameplay ?) we will add a new move : the Slide.

Sliding will be activated if you press the kick button while we run (no need for hundreds buttons into this kind of game, it only add unnecessary complexities), as a result, the player will be granted as a boost of speed in that direction, BUT cannot change the direction while sliding, and will be unable to move after a rest time of 0,1sec; but if the player collides with the ball while sliding it send automatically at a random point on the opponent field, with the lower speed and with a random height.


Gameplay Perspective

In order to get a winning edge, the player must anticipate his position on the field.
The closest he is of the future position of the ball, the quicker will be his response. Allowing more time to position his aim, and a more powerful kick.

But if he’s real wrong on his positioning, there’s actually no way to catch up the ball due to his actual speed.

Let’s remedy to that, and spice up the gameplay too.

We’ll add the slide; a move that will allow a brief dash to catch up the ball if we’re too far.
But as even bonus in a gameplay should come with a malus, let’s review the bonus/malus of a slide :

  • Allow a boost of speed.
  • While sliding, you can collide with the ball without further need to release the shoot button.
  • While sliding, the collider will be wider; giving more chances to collide with the ball.
  • When the slide is started, you cannot change its course neither its duration.
  • After a slide, there will be a 0,5s time while the player cannot move.
    Usually, you’ll be able to slide once before the ball touches the ground, slide carefully.
  • If you reach the ball while sliding, the ball will be sent back at a random point on the opponent field at medium speed.
    It can be sent outside of the game field too.

With these additions, it should be funnier (well, at least I hope so).


Now we see it’s quite hard to receive the ball, it’s too fast. So we’ve got 2 options:
– Speed up our player moves.
– Slow down the ball speed.
As we do not all have light speed reflexes, it’s better to slow down the pace, slow down the ball speed because it leave us the chance to charge up our power with a little more time to let our kick button pressed.


05:32 Creating new states

In Player1 FSM, create a state “isSliding”. We’ll use the move vector to see if our player is already moving while pressing kickButton, in that case it’ll activate the slide.
We create in our player FSM a vector3 variable called “P1_moves”.
Then declare it in our playerController script:

private FsmVector3 P1_moves;

And change the update function:

void Update () {
  Vector3 move = new Vector3(Input.GetAxis("Horizontal"),0,Input.GetAxis("Vertical"));
  //here we update the vctor value in the FSM
  P1_moves.Value = move;
  _controller.SimpleMove(move * playerSpeed);

06:47 Actions within “isSliding”

Now in the player1 FSM, we link the Finished “init Aim” transition to our new “isSliding” state.
In this state we’ll add these actions :

-“Activate Collider” where we specify our t_collider as the gameObject to activate. like this our reception collider will surround the player as we slide allowing to triggers collision with the ball.
-“Get Vector3 XYZ”, where we check the P1_moves vector and store 2 new variables : p1x for the X value, and p1z for the Z value.
-After store these values,we compare these with the new action : “Float compare”.
It compares the Float 1 value (here we set as “P1x”) to the Float 2 val (here 0,7, we used 0,7 instead of 0 because there’s a decreasing mechanic when you release a direction meaning that even if you released the input it’s not set at 0 on the instant).
then we choose which event to sent  if the val 1 is greater/lesser/equals val 2.
In our case if P1x is lesser or greater than 0,7, it means we’re moving, so in greater than/lesser than, we create a new event “slide”.
We repeat the same action comparing p1z value.

Once we’ve done we create a new State : “Sliding”, and onto our “isSliding” state, we add 2 transitions :

“slide”, which we link to our “Sliding” state, meaning when slide event is triggered, go to the “Sliding” state.
“Finished” which we link to our “isKicking” state, meaning that the old loop is kept if we’re not moving while kicking.


08:55 Actions within “Sliding”

In “Sliding” state :

-Desactivate the aim gameObject with the action “Activate gameObject”,specifying “aim” gameObject and uncheck “activate”.
This will prevent from seeing the aim sliding along with us on the other side.

-“Set Scale” action, selecting our “t_collider” gameObject, and setting its X,Y & Z values to 2. This shrinks a little bit our collider, in order to avoid that the game became too easy by just sliding everywhere with a big collider circle.
-Set the canMove bool to false, with “Set bool value” action, with the bool var “canMove”.
Preventing the player to change the movement in the update loop.
-“Send message” action, with the method “addSlidingCoeff”. A new method that will add more speed to our slide, working as follows (to be aded in our playerController script :

void addSlidingCoeff(){
//retrieving p1X & p1Z vars from FSM, 
//containing the actual direction of the slide
 FsmFloat p1X =  MyFsm.FsmVariables.FindFsmFloat("p1X");
 FsmFloat p1Z =  MyFsm.FsmVariables.FindFsmFloat("p1Z");
//as p1X can be as negative as positive (1 or -1)
//we adjust the value
  p1X.Value = 3;
 else if(p1X.Value<0) p1X.Value = -3; //same for pZ if(p1Z.Value>0)
  p1Z.Value = 3;
 else if(p1Z.Value<0)
  p1Z.Value = -3;

-“Set Bool value” action, “isKickReleased” must be set to true, as it’s the value allowing us to test collision with the ball.
Like this f our slide meets the ball, it’ll collide automatically without event touching the kick button.
-“Translate” action : changing X by p1X and Z by p1Z. and checking “PerSecond” and on “EveryFrame”.
This is the main action that will translate the player position with our adjusted p1X & Z values, making it moves every frame.
-“Wait” action, with Time set as 0.5, and with the “Finished” event selected. This action only waits 0.5 seconds before ending the state, letting the player slide between a 1/2 second with no other action possible.

Once these actions made, we add the transition Finished and link it to the “Release Kick” state, finishing the loop.

Leave a Reply