Here we are on day 8! Yesterday, we created a very simple map for a simple FPS feature.
Today, I went to look to see how we can move a character around in the scenery that was created.
Here’s what I got!
Creating Our Character
The first thing I figured out who was the “character”. Turns out for our game, our main character is someone we know well.
Here it is:
That’s right, it's Main Camera! Who knew?
If we think about it, it does make sense.
The camera
object is what we see when we run the game. In an FPS game, we see what our character sees. Which means our camera must be part of the character, specifically their eyes.
Setting Up Our Character
The first thing we do is to create an Empty Game
object that we will call Player
, then we’ll make our main camera
a child of player
.
I’d imagine when we want a character model, we would have the camera
be right in front of the face of the model, but for now, we don’t need one.
Make sure the camera
is set at position (0, 1, 0)
and the Player
position to be (5, 1, 5)
.
The X and Z position is so that we don’t start falling through the edge of our map and the Y value would give us some height, otherwise we would be facing the floor.
Next, we need to add a collider to our Game
Object so that we won’t fall through the world when we start the game.
I created a Capsule Collider
and I set the height to be 2
and left the rest as the same.
I’ve also attached a RigidBody
component, because later on, we’re going to have to write some code to make our camera
move when we click on our keyboard.
And here we are, our player
character:
And here’s what we’ll see when we play:
If you want, you can give our character a Mesh Renderer and a Mesh Filter so that you can see where our character is in the Scene tab. We also get a nice little shadow!
Creating Movement for our Character
Now that we have a character, the next thing we have to do is to move it.
I found that Unity actually offers some very good built in FPS controls from this thread: How to make a first-person player for my game.
If you don’t have the fps scripts like in the thread, you can go to Assets > Import Package > Player to get these scripts.
After downloading them, all you have to do is attach the scripts to the Player
game object.
However, since I’m doing this for learning, I’m going to attempt to write my own script to do something similar.
The first thing I’m going to do is create a new script called PlayerController
, this will be used to control our player
’s position based off of the user’s input.
I actually had to spend a lot of time working on this and searching on Google, but here are the results.
using UnityEngine;
public class PlayerController : MonoBehaviour {
public float Speed = 3f;
private Vector3 _movement;
private Rigidbody _playerRigidBody;
private void Awake()
{
_playerRigidBody = GetComponent<Rigidbody>();
}
private void FixedUpdate()
{
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
Move(horizontal, vertical);
}
private void Move(float horizontal, float vertical)
{
_movement = (vertical * transform.forward) + (horizontal * transform.right);
_movement = _movement.normalized * Speed * Time.deltaTime;
_playerRigidBody.MovePosition(transform.position + _movement);
}
}
The code is pretty straight forward, here’s the flow:
- In
Awake()
, we get our RigidBody
so we can move our player - In
FixedUpdate()
, we use GetAxisRaw()
to get our horizontal and vertical movement so that we can detect if the user is moving left/right and up/down. - In
Move()
, we’re given the movement directions. We want to create a movement vector that captures the direction from where the user is facing, which we achieve with transform.forward
and transform.right
. By multiplying everything together, we get the direction that the player should move based off of their inputs. - Finally, we normalize our movement vector and then we move our position with our new Vector.
It’s important to note that we must use the RigidBody
to move.
Before I was trying to move the player with transform.Translate
, what I found out is that this function is the equivalent of teleportation. What happens is that if there are obstacles in front of the player, our character will just teleport past them.
I also want to emphasize that it’s important that we use transform.forward
and transform.right
especially once we start trying to get the camera
to follow the mouse.
When we start rotating our character to follow the mouse, our vertical and horizontal values don’t give us the direction adjusted for which direction we’re facing.
For example, if we were to face forward and press W to move forward, we would move forward. However, if we were to turn 90 degrees to the right, and press W again, instead of moving forward like you’d expect, you would move to the left where “forward
” use to be.
transform.forward
gives us a vector that the player is facing and then we multiply that with our vertical
value which tells us if we’re moving forward or back. We do the same with transform.right
and horizontal
.
Rotating Our Camera
The next problem after making our character move is trying to figure out how to get the camera
to follow the mouse.
There were a lot of answers, however I think the best explanation is from this Youtube video: How to construct a simple First Person Controller.
I only took the snippet for the camera
controller.
I made another class called MouseCameraController
and attached it to our Main<br /> Camera
.
The script allows us to want to be able to view up and down with the camera without moving the character, but we want to change our player rotation value as we look horizontally.
Here’s the code:
using UnityEngine;
public class MouseCameraContoller : MonoBehaviour
{
public float Sensitivity = 5.0f;
public float Smoothing = 2.0f;
private Vector2 _mouseLook;
private Vector2 _smoothV;
private GameObject _player;
void Awake()
{
_player = transform.parent.gameObject;
}
void Update () {
Vector2 mouseDirection = new Vector2(Input.GetAxisRaw("Mouse X"), Input.GetAxisRaw("Mouse Y"));
mouseDirection.x *= Sensitivity * Smoothing;
mouseDirection.y *= Sensitivity * Smoothing;
_smoothV.x = Mathf.Lerp(_smoothV.x, mouseDirection.x, 1f / Smoothing);
_smoothV.y = Mathf.Lerp(_smoothV.y, mouseDirection.y, 1f / Smoothing);
_mouseLook += _smoothV;
_mouseLook.y = Mathf.Clamp(_mouseLook.y, -90, 90);
transform.localRotation = Quaternion.AngleAxis(-_mouseLook.y, Vector3.right);
_player.transform.rotation = Quaternion.AngleAxis(_mouseLook.x, _player.transform.up);
}
}
There’s a lot of math to digest for this code, but let’s go through them.
As mentioned, it’s important that the script is attached to the camera
and not the main character body.
We want to rotate the characters body when we look left to right, but when we look up to down, we don’t want to rotate the body.
- In our
Start()
function, we want to get the parent element (the Player Game
Object) so we can rotate it as we turn. - In
Update()
, we create a vector that would represent where our mouse is facing which we will use to determine where our camera
will be facing by using our Mouse X
and Mouse Y
positions - Next, we want to multiply the direction we created with 2 variables:
Sensitivity
and Smoothing
Sensitivity
is used to determine how big the vector of our mouseDirection
would be. The higher the number, the more sensitive our mouse would be, allowing us to rotate more quickly. Smoothness
is used to help us evenly move our camera from its starting location to the new location from the mouse location. We use lerp to help us make gradual movement instead of one massive movement
- Once we calculate the new direction we’re facing into
smoothV
, we add that into our mouseLook
variable which is where our character will be facing. - We make sure to clamp the
y
rotation, because we don’t want to be able to go from looking in front of us to behind us. It’s unnatural human anatomy. - Finally, for rotation. We want to rotate the
localRotation
of our camera
, meaning we rotate the game object, relative to its parent.
- For example, if our player is facing 90 degree, if we were to set rotation of our camera to
90
, we would be at 90
, the same location. If we use localRotation
, it would take in the fact our character is facing 90 degree and rotate 90 more. - We create our angle by using our
y
value (the up and down) and rotating by the angle Vector3.right
, which is the X
axis.
- Our last rotation is when we want to turn our player around instead of the
camera
. We don’t have to use localRotation
, because the player doesn’t have a parent (which means it defaults to the game world as the parent), so we can just use rotation, though both would work.
- As for our rotation, we rotate our player by our left and right mouse movements using
Vector3.up
, which is the Y axis.
And that’s it! Play the game and you should be able to move your character around in the game world and bump into our environment that we setup.
Conclusion
Now wasn’t this short compared to the video tutorials?
Today, we learned how to move and rotate the character around in the game screen.
It’s important to know that Unity provides a standard asset that makes movement easy for us, but I do think there’s value in being able to understand some of the inner workings of the code.
Either way, stay tuned for Day 9, where we’ll hopefully start exploring how we can equip a gun in our player and maybe even start shooting something!
Day 7 | 100 Days of VR | Day 9
The post Day 8: Creating a Character in a First Person Shooter appeared first on Coding Chronicles.
CodeProject