Wednesday, October 15, 2014

Unity Character Controller C# (Tutorial)


The most basic and needed asset for any game, in which you control an avatar, is a script to control your character. In this tutorial I will demonstrate and explain how to build a character controller.

There are a few thing that you want to decide before you start working on your script. What kind of movements will I need? Can it run, jump, attack?

In this tutorial the controller I will create will allow the player to walk, run, jump, bounce, and attack, all while playing in a sidescroling environment. This script communicates with Unity's built in animation tool "Mechanim." The player gameobject requires a collider, rigidbody, and an animator.

Terms Used Frequently:
public - can be accessed from other scripts and can be edited in the inspector.
float - Number variable that allows decimals. Ex 1.251 or 576.6574893.
bool - A value that only holds true or false.
LayerMask - a type that you can assign particular layers to in Unity.
Transform - represents a specific point in 3D or 2D space.
GameObject - pretty simple.



 This is what your Script will start with. Make sure that your script's file name is the same as the "public class" name.



As our first variable, lets make a Boolean value. We want to make this so that in the situation where we want to make the player unable to control the avatar, say for a cut scene or on death, we need this here so we can do so.


Here are the variables that we will need for movement. You can change these at any time here in the script or in Unity's inspector.

The running variable does not control anything in the script, however, we use it to communicate with the Animator. Same with the xSpeed. I will explain those later.


We start the player off with grounded being false because I have the player slightly above the ground at the start of the level. If you try to place it on the ground to start in the editor, you risk clipping issues and the player falling straight through.

The Transform groundCheck is an empty GameObject that is in the avatar's hierarchy. Place it near the feet, or where ever the player would touch the ground. the float groundRadius is the range it takes from the groundCheck to detect ground. The LayerMask whatIsGround is the layer(s) that we declare as ground to detect.

The floats and bools after are not set at a certain value in the script because they require so much tweaking, so I set them in the editor. the bool jumped is used later when checking if the player is off the ground because it jumped or if it fell. Then I am sure you understand the bounce stuff is kind of the same.

My player uses fireballs as his attack. This tutorial does not show how to perform the attack, that will be another tutorial, however, this does give the very basic setup for it.

As stated, you will need an Animator component. Here the Animator anim is set up also where the variables are placed. Now when we want to do something with the animator we only have to use anim to call it.

In the start function we want the script to recognize that the anim is in fact the Animator. You could just make the anim public and drag and drop the GameObject in the inspector, but this way my object's inspector is clearer.









Most of our script will be housed in the FixedUpdate function. This function is best for working with physics (which is how we will move our character) because unlike the Update function, FixedUpdate does not update every frame, it refreshes at a steady pace regardless of the frame rate.

The first line is used to set the rotation of our character. The angle variable is the key to which way our character is facing. With using Vector.up unity will set the rotation based off of the "up" axis. In this case it is the -y.

In the second line we make the float value move equivalent to the Input value of the axis labeled "Horizontal". In the Project Settings > Input I made my "Horizontal Axis" based off of the joystick X-axis. So now, whenever the player moves the joystick along the x-axis, we will return an input value of -1 to 1. This will be used to tell Unity which direction to apply force to.

xSpeed is equal to the amount of velocity the player is moving along the -x axis. The xSpeed and running variable are used for Animation purposes. When animation your player for movement, you do not want the movement input joystick to tell the animator to play the walking animation. Instead it is best to see if the player is actually moving. This way when you run into a wall and stop moving, your character will not be playing the walking animation.

The bool running is used when we want to pass info to the Animator, telling it whether we are running or not running.

 
 
 
 
 
 
 
 
Still in the FixedUpdate function, I have these lines of code so that I can tell my animator to perform certain things. This is not a tutorial for Unity's Mechanim, you can find that elsewhere.












 
 
All of these are fairly simple to understand. I'll explain the first one and then you should be able to comprehend the rest.

If float move is greater than 0.1 (which would happen if the player moved the Horizontal Joystick along the positive -x axis) and if the player is not running (that's what "!" means if it is in front of a Boolean) and the player can be controlled, then we will apply velocity to the gameObjects rigidbody.

In the Vector3, the values inside the "()" are the x, y, and z axis. When working with a Vector3, you do not always have to include the -z axis. In this situation, we are applying force along the -x axis based on the value of float move. We do not wish to apply force along the -y axis so we just type "rigidbody.velocity.y" meaning that whatever amount of velocity it has in this frame, it will continue to have.

When my character moves along the positive -x, he is facing right so I need to make him face right which would put him at 90 degrees along the -y axis. And since I am moving without running, I put the bool running to false.

Now translate that logic to figure out the others.
 

Here we can give the player the ability to jump and bounce off of objects or enemies.
 
If the player is grounded (which we will determine later), then the bool jumped equals false.
 
If the player is grounded and the player presses the button that we assigned for "Jump" (Project Settings > Input) and if the player canControl, then we will apply force. Just like how we applied the movement force with the Vector3, we can do the same here with a Vector2(x,y).
 
So we apply force with 0 along the -x, and then we use the equation jumpForce *(times) 100. You can tweak this however you want using the inspector to set the float jumpForce. You do not even have to multiply by 100, I only do so to keep my inspector value cleaner.
 
Then we set the bool jumped to true. We will use this to tell our animator that we have jumped and not fallen.
 
The bounce brick of logic will make sense after I show you the way we are going to check for grounding.
 
 


As I said, this tutorial does not show how to make an attack, there are too many different kinds and ways to do them to explain here. This piece of code checks if the player has hit the attack button and if the player is in the process of attacking or not.





 
Now we can get to checking if the player is on the ground. We made several variables and components at the beginning of the script:
  • bool grounded
  • Transform groundCheck
  • float groundRadius
  • LayerMask whatIsGround

This line of code is placed in the Update function, which updates every frame. It could reside in the FixedUpdate, although I ran into many bugs with it not detecting my player touching the ground quick enough which messed with my ability to jump again.

The bool grounded is equal to a specific condition. Physics.CheckSphere is the ability to create a sphere from a particular position and gather information with what it touches.


Physics.CheckSphere (where to check from, how far to check, what layermask);

So as long as the CheckSphere that originates from the Transform of the empty GameObject that I placed in the hierarchy touches objects that are under the layers I decide in Unity's inspector, the player will be considered grounded.



These functions are here in case I want to send a message from one script to this one to declare the player as controllable or not.

 



I hope that this helped at least a few people.  If you are new to programming or to Unity, it maybe wise to read over it again to make sure it sticks.

Source File Here

No comments: