Creating a custom character control script

From the last section, we know how to set up the character controller using the built-in third-person character controller, which works very well. If we look at the built-in character controller closely, we will see that it takes only four animation clips, but we want to add one more clip, which is the fall animation (for the model that we had, it's the backward of the jump animation clip). However, if we have more than four animation clips, we will need to build our own script because there is no support for including a falling animation in the built-in script. So, we will create our character control script which is similar to, but much simpler than, the built-in third-person controller script.

Prepare for Lift Off

Before we start coding, we need to get rid of the built-in Third-person Controller and Third-person Camera scripts. So, let's go to Heroine_animate in the Hierarchy View, under the Inspector view, right-click the Third-person Camera script, and then click Remove Component. We will see the pop-up window that says we'll lose the prefab if we remove it. We can just click on the OK button to remove it because we already created our prefab. Then, we go to Third-person Controller, right-click and select Remove Component to remove it. Now, we are ready to create our character control script.

Engage Thrusters

Now we will create the script to control our character:

  1. Go to Assets | Create | JavaScript and name it CharacterControl, and then right-click on this script and click Sync MonoDevelop Project (or double-click it if you have already set MonoDevelop as your main editor, if not it will open the default script editor either Unitron or UniScite) to open MonoDevelop, and we are ready to code.
  2. We start by adding these parameters as follows:
    // Require a character controller to be attached to the same game object
    @script RequireComponent(CharacterController)
    
    //All Animation Clip Params
    public var idleAnimation : AnimationClip;
    public var walkAnimation : AnimationClip;
    public var runAnimation : AnimationClip;
    public var jumpPoseAnimation : AnimationClip;
    public var fallPoseAnimation : AnimationClip;
    
    //Animation Clip Speed
    public var jumpAnimationSpeed : float = 4;
    public var fallAnimationSpeed : float = 0.1;
    public var runAnimationSpeed : float = 1.5;
    public var walkAnimationSpeed : float = 1.5;
    public var idleAnimationSpeed : float = 0.5;
    
    public var speed : float = 2; //Walk speed
    public var runSpeed : float = 5.0;
    public var jumpSpeed : float = 8.0;
    public var gravity : float = 20.0;
    
    private var controller : CharacterController;
    //Move Params
    private var f_verticalSpeed : float = 0.0;
    private var f_moveSpeed : float = 0.0;
    private var v3_moveDirection : Vector3 = Vector3.zero;
    
    //Boolean
    private var b_isRun : boolean;
    private var b_isBackward : boolean;
    private var b_isJumping : boolean;
    
    //Rotate Params
    private var q_currentRotation : Quaternion; //current rotation of the character
    private var q_rot : Quaternion; //Rotate to left or right direction
    private var f_rotateSpeed : float = 1.0; //Smooth speed of rotation
    
    //Direction Params
    private var v3_forward : Vector3; //Forward Direction of the character
    private var v3_right : Vector3; //Right Direction of the character
    
    private var c_collisionFlags : CollisionFlags; //Collision Flag return from Moving the character
    
    //Create in air time
    private var f_inAirTime : float = 0.0;
    private var f_inAirStartTime : float = 0.0;
    private var f_minAirTime : float = 0.15; // 0.15 sec.

    Here, we have all the necessary parameters to use in our script. In the first line, we want to make sure that we have the character controller script attached when we use this script. Then, we have the animation clip parameters to contain all the animation that we want to play when we control our character. Next, we have the animation speed to control how fast we want our animation clip to play when it uses. We also have the speed for the walk, run, jump and gravity parameters. We need the gravity property because we will use the Move() function in the CharacterController class, which doesn't have the gravity parameter included.

  3. Next, we will start creating the first function Awake() using the following code:
    //Using Awake to set up parameters before Initialize
    public function Awake() : void {
      controller = GetComponent(CharacterController);
      b_isRun = false;
      b_isBackward = false;
      b_isJumping = false;
      f_moveSpeed = speed;
      c_collisionFlags = CollisionFlags.CollidedBelow;
    }
  4. In this function, we set up the necessary parameters before we initialize it. Then, we create the Start() function and initialize it as follows:
    public function Start() : void {
      f_inAirStartTime = Time.time;
    }

    We use the Start() function to set up f_inAirStartTime because we need to get the time when we first start the scene.

  5. Next, we will add the scripts to check the stage of our character, such as jumping, moving backward, on the ground, and in the air. Let's type this as follows:
    //Checking if the character hit the ground (collide Below)
    public function IsGrounded () : boolean {
      return (c_collisionFlags & CollisionFlags.CollidedBelow);
    }
    //Getting if the character is jumping or not
    public function IsJumping() : boolean {
      return b_isJumping;
    }
    //Checking if the character is in the air more than the minimum time 
    //This function is to make sure that we are falling not walking down slope
    public function IsAir() : boolean {
      return (f_inAirTime > f_minAirTime);
    }
    //Geting if the character is moving backward
    public function IsMoveBackward() : boolean {
      return b_isBackward;
    }
  6. Now we will set up the Update() function to make the character move; add the following code:
    public function Update() : void {
      //Get Main Camera Transform
      var cameraTransform = Camera.main.transform;
      
      //Get forward direction of the character
      v3_forward = cameraTransform.TransformDirection(Vector3.forward);
      v3_forward.y = 0; //Make sure that vertical direction equals zero
      // Right vector relative to the character
      // Always orthogonal to the forward direction vector
      v3_right = new Vector3(v3_forward.z, 0, -v3_forward.x); // -90 degree to the left from the forward direction

    In the preceding section, we get the transform from the main camera, the forward direction, and right direction from this transform, because the controls are relative to the camera orientation not the character orientation.

  7. We need to get the Input button from the user by using the Input.GetAxis "Horizontal" and "Vertical":
      //Get Horizontal move - rotation
      var f_hor : float = Input.GetAxis("Horizontal");
      //Get Vertical move - move forward or backward
      var f_ver : float = Input.GetAxis("Vertical");
  8. We check whether the character is moving backward or forward by checking if the result of f_ver is lower than 0, as shown in the following script:
      //If we are moving backward
      if (f_ver < 0) {
        b_isBackward = true;
      } else { 
        b_isBackward = false; 
      }
  9. We get the target direction by multiplying the horizontal value with the camera transform right direction and add the value of vertical multiply with forward direction of the camera, as shown in the following script:
      //Get target direction
      var v3_targetDirection : Vector3 = (f_hor * v3_right) + (f_ver * v3_forward);
  10. We calculate the move direction here by using Vector3.Slerp(), and normalize it, because we only need the direction where our character moves from the user input, as shown in the following script:
      //If the target direction is not zero - that means there is no button pressing
      if (v3_targetDirection != Vector3.zero) {
        //Rotate toward the target direction
        v3_moveDirection = Vector3.Slerp(v3_moveDirection, v3_targetDirection, f_rotateSpeed * Time.deltaTime);
        v3_moveDirection = v3_moveDirection.normalized; //Get only direction by normalizing our target vector
      } else {
        v3_moveDirection = Vector3.zero;
      }

    Note

    Vector3.Slerp() is the function that we can use to interpolate between two vectors spherically by amount of time, and the return vector's magnitude will be the difference between the magnitudes of the first vector and the second vector. This function is usually used when we want to get the smooth rotation from one vector to another vector in a fixed amount of time. You can see more details at the following Unity website:

    http://unity3d.com/support/documentation/ScriptReference/Vector3.Slerp.html.

  11. We get the moving speed of our character by checking if our character is walking or running. In this section, we also check whether the character is grounded or not. We will make sure that we cannot press the Run or Jump buttons while the character is in the air:
      //Checking if character is on the ground  
      if (!b_isJumping) {
        //Holding Shift to run
        if (Input.GetKey (KeyCode.LeftShift) || Input.GetKey (KeyCode.RightShift)) {
          b_isRun = true;
          f_moveSpeed = runSpeed;
        } else {
          b_isRun = false;
          f_moveSpeed = speed;
        }  
            //Press Space to Jump
            if (Input.GetButton ("Jump")) {
                f_verticalSpeed = jumpSpeed;
                b_isJumping = true;
            }
      }
  12. We apply the gravity and calculate in-air timing of our character. We need to apply the gravity here because the Move() function in the character controller script doesn't have any gravity applied to it. We will use the in-air time to track the time when the character is in the air. This will make sure that our character can walk down on the slope without any bugs:
      // Apply gravity
      if (IsGrounded()) {
        f_verticalSpeed = 0.0; //if our character is grounded
        b_isJumping = false; //Checking if our character is in the air or not
        f_inAirTime = 0.0;
        f_inAirStartTime = Time.time;
      } else {
        f_verticalSpeed -= gravity * Time.deltaTime; //if our character in the air
        //Count Time
        f_inAirTime = Time.time - f_inAirStartTime;
      }
  13. We calculate the movement of our character and use the Move() function to move our character:
      // Calculate actual motion
      var v3_movement : Vector3 = (v3_moveDirection * f_moveSpeed) + Vector3 (0, f_verticalSpeed, 0); // Apply the vertical speed if character fall down
      v3_movement *= Time.deltaTime;
        
        // Move the controller
        c_collisionFlags = controller.Move(v3_movement);
  14. Finally, we apply rotation to our character when the user controls our character left or right:
        //Update rotation of the character
        if (v3_moveDirection != Vector3.zero) {
          transform.rotation = Quaternion.LookRotation(v3_moveDirection);
        }
    }

Next, we will assign this script to our character by going back to Unity and dragging the CharacterControl script to the Heroine_animate in the Hierarchy view; we will be able to control our character, but there will be no animation applied to our character yet. We will apply animation to our character/character animation in the next section.

Objective Complete - Mini Debriefing

In this section, we have created a custom character control script to create the character movement by using the Move() function in CharacterController class. This function needs only the direction and it returns the collision flags, which are very convenient to use. We also apply the Gravity and Jump buttons to make our character fall down when there is no collider.

Classified Intel

In the first chapter, we created a 2D platform game which used a plane object to show a sprite animation. We also attached Rigidbody to the character to be able to use a gravity and access to the Rigidbody class to get a nice Physics movement.

However, in this chapter we didn't use Rigidbody, but we used CharacterController to control our character. We can add Rigidbody to our character if we want to create a ragdoll object, but we aren't doing it in this chapter. We will take care of the ragdoll object in Chapter 7, Creating a Destructible and Interactive Virtual World.

The CharacterController script has a lot of advantages. In this case, we will talk about the Move() function. This function takes one parameter, Vector3, which will be the motion of our movement per frame. So, we basically need to get the direction from the input, multiply the speed and Time.deltaTime, and pass it to this function.

The Move() function also returns the CollisionFlags, which we can check for each part of our character collide to another object. This is very useful when we want to check if the top of the character hit the ceiling, or the side of our character hit the wall, and so on. We can read more details of the Move()function and CollisionFlags from the following link:

http://unity3d.com/support/documentation/ScriptReference/CharacterController.Move.html.

http://unity3d.com/support/documentation/ScriptReference/CollisionFlags.html.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.37.10