+10

First Person Controller

Martin Halldin 2 years ago updated by Muhammad Ahsan Rifki 1 week ago 7

So after looking around for a bit and not seeing any simple, straight forward way to create a first person controller using bolt I decided to write a tutorial myself. Hope this helps! :)


1. Setting up our project

So assuming we're starting off fresh, we'll have to import bolt into unity before we get started with everything else. Open up the asset store by pressing Ctrl + 9 and search for Bolt. Import it and run through the setup.


Now that Bolt is installed we'll create our character and then attach a camera to that player. Do this by creating an empty gameobject by pressing Crtl + Shift + N and then name this new object PlayerOn this gameobject we'll add the character controller by pressing Add Component in the inspector and then search for Character Controller

Now we need to attach a camera to our player. We'll do this by using the Main camera already existent within our scene. Attach this camera to the player by dragging it in the hierarchy and dropping it on the player. I like to offset the camera a bit so that I don't feel too short when playing the game. A Y value of something like 0.5 usually works but you use whatever value you like. 

Lastly there needs to be some sort of environment to walk around in so that we don't fall into the never-ending void below us. So we'll create a simple plane to work as our floor. Do this by right-clicking in the hierarchy and select 3D Object > Plane


Now our scene should look something like this:


2. Setting up our variables

Right, now that everything is set up, let's start working on our code!

Select the player in the hierarchy and then press Add Component in the inspector. Search for Flow Machine, then select it in the menu. We'll create a new macro by pressing New in the flow machine and save that macro somewhere safe. I like to stay organized so I'll create a new folder called Scripts, in that folder I'll make a new folder called Player and save our macro in there. Name it something like CharacterController.

Now we need to create a few variables. Open up the variables window by pressing Window > Variables. I always dock this next to the hierarchy, so I'll keep that tradition alive. Next we'll create the variables. The first ones being Movement Speed (Float, value of 2) and Rotation Clamp (Float, value of 60), both of these we will make into object variables so that we can change them in the inspector if we want to, without having to go into the script all the time. The other variables are all graph variables: Vertical Rotation (Float), Horizontal Rotation (Float) and a reference to our camera that we'll call Camera (Game Object). These will only be referenced within this graph, so they don't need to be public variables. Done right, the variables window should look something like this:


The reason we create the rotation variables all within the player graph is because we will be handling the X rotation of the player here. The Y value could be separated into it's own graph if you wanted, I just find it easy to reference the camera and have all the movement be done from the same graph to make things less cluttered. 

3.1 Writing the code (Rotation)

Now comes the fun part, writing the code!

Before I do anything movement-based I always make sure I can have a good ol time looking around my scene, preventing one directional vision and the player getting bored. So let's start with the X rotation. 

Open up the graph editor by selecting the CharacterController graph in the project window and clicking Edit Graph in the inspector. Now you should have an empty canvas with only a Start event and an Update event in front of you. Right click in the canvas and search for GetAxis. Select the top most result and type Mouse X in the input field. We want to hook this up to our Horizontal Rotation Variable and we can do this by right-clicking again in the graph editor and search for Set Horizontal Rotation. Now hook up the Update Event to the Set Variable. This will allow our player to rotate left and right. If you think the rotation is too slow you could always use a Multiply unit and use another Object variable to multiply the current speed with, although I only want to make it slightly faster, so I'll do this by searching for Multiply and hook up the unit between GetAxis and Set Variable and set the B value to 2.


Now create a Rotate Unit by searching Transform > Transform.Rotate(xAngle, yAngle, zAngle). Hook this up to another Update Event and pass the Horizontal Rotation variable into the Y axis of the rotation. We do this because, while the X axis handles left and right movement, it does not handle left and right rotation as it isn't the axis used for that kind of rotation. We actually look left and right by rotating around the Y axis. Same thing goes for the X axis, but for up and down rotation instead. Now the setup should look something like this:


I know some people might think this looks unnecessary, but it will give us the ability to affect the rotation variable later on if we need to, apply extra functionality, insert more values etc. If you want to you could hook up the multiply unit straight into the rotation unit because right now it will do basically the same thing, but I will keep it as is for now.

One important thing to mention is that we don't want to rotate the camera around every axis. We want to turn the body of our player round the Y axis, and then the camera around the X. This way we wont just rotate the camera or just rotate the player.

So now let's make sure we can look up and down. As I said earlier we need to rotate around the X axis for up and down motion, so to make this work we need to do a whole lot. So let's start by setting up a reference to our camera. Do this by using the unit called Find and then input Main Camera into the text field. connect this to a set variable and select Camera. We'll only do this once so we can use the Start Event for this. This should look something like this:


Now comes the tricky part. We cant directly apply rotation to the X yet, because if we did there'd be the problem of tilt, way too much tilt. You could spin around forever if you wanted to, but that's not what we want and so we'll use a function called Clamp.

Clamp allows us to restrict a value from surpassing one or two other values. In this case we don't want our X rotation to surpass the value of our Rotation Clamp (60). Right-click in the editor and search for Mathf and then look for Clamp (Value, min, max) and add that to the graph. Now search for Get Vertical Rotation and hook that up to the Clamp input value. Now search for Get Rotation Clamp and hook that up to both the min and max of the clamp unit. We can now hook up a new Update event to the clamp, then search for Set Vertical Rotation and hook that up from the clamp. Lastly, insert a multiply unit between the rotation clamp and the clamp min and set the value to -1, this way we invert the rotation clamp value and allow full rotation between 60 up and -60 down. Otherwise we'd be stuck looking at clouds being all philosophical and stuff. Yuck, amirite? 

Done right, it should look like this:


The reason we set the vertical rotation value, back to the vertical rotation value is because we need to get it, change it, and store it back within itself without creating a bunch of extra variables like "New Vertical Rotation" or something. 

Now let's apply the rotation, but we cant use Transform.Rotate because that's just a transform and can sometimes suffer from the gimbal lock. (Google it, it's pretty interesting) Instead we're going to be working with Quaternions which are used within unity as substitute for rotation.

Search for localRotation and select Transform.localRotation (Set), as you can see, this does not work with x, y and z axises directly, instead it uses quaternions. This is exactly what we want. but the reference object is currently set to self, when it should be the camera. Remember that we want to keep these two rotations separated, So search for Get Camera and hook that into the object reference input.

But then how do we rotate using Quaternions? Simple, we'll get a reference to our Vertical rotation and hook that into a unity called Quaternion.Euler. Get this by searching Quaternion > Euler (x, y, z) and hook the output of this unit to the localRotation input. Then input the Vertical Rotation into the x Value of the Euler unit. But we need an update event, right? Otherwise we wont be able to run the code. Well... Yes, but we cant update thye rotation while we're clamping the value of the variable we're using to rotate something. That's result in some odd behavior to say the least and if there is one thing I hate more than conformity it's oddities. Yuck, We have to update the rotation after the clamping has been applied. So instead we'll hook up the flow from the set vertical rotation variable from the clamp to the localRotation unit. Done right it should look like this:


Okay... But when I play the game nothing happens, I can rotate left and right but not up and down.

Yes that is true, that's because we're never getting any Y rotation to begin with. So let's do that now! Create a new GetAxis unit and write Mouse Y in the input field. Then hook that up to a set vertical rotation unit, But before you play, we have to tweak this setup a little. We cant just input the mouse y values directly. If you play now the movement will be very gittery and weird. Like I said earlier, weird is really really really bad and don't do it kids. So to fix this we have to subtract the vertical rotation by the mouse y, then input that value back into vertical rotation. Sounds weird, and it is, but not as weird as gittering so it is okay. Be sure that you input Vertical Rotation into A and Mouse Y into B. Now the graph should look something like this:


That should be it for the rotation! If you've done everything correctly you should be able to tilt both up and down (with restrictions) as well as left and right. But we're not moving around yet so we'll fix that now!


3.2 Writing the code (Movement)

So the rotation is done, now let's fix the movement issue. While sticking around in an empty forever where nothing happens because god hasn't decided to do anything with the space yet, it's up to us to figure out how to move around in this hell.

Start by searching for CharacterController and select SimpleMove. This unit is what will handle all physics of our player. The speed of our controller will be of a vector 3, so now we'll search for Vector3 and select new Vector3 (x, y, x) then hook this up into the charactercontroller unit. To actually get some input that affects this controller we'll be using GetAxis again. Search for GetAxis and import two of these units, one for the horizontal movement and one for the vertical. Hook one of them into the x input and the other into the z input. But why you may ask, we're getting the vertical inputs right? Yes, but we're not going to move up or down, we want to move forward and backwards. So that's why we use z instead of y. Input Horizontal into the GetAxis unit connected to x and Vertical in the other. Capitalization is important here. Lastly hook up an Update event into the charactercontroller unit,The graph should look like this:


So now we should be able to look both up and down, left and right, move forward and backwards as well as to the left and right. But if you play the game now you'll notice that when we turn around we're not actually moving in the directions that we want. That's because we're rotating the transform of the player, but not the direction in which we move within the code. The setup now will always treat forward as +z and backwards as -z, no matter in which direction we're currently facing. So we need to do some multiplication again. 

Insert a Multiply unit between the Vector3 and the CharacterController, then connect the Vector3 into the B insert and a Quaternion > Euler (x, y, z) in the A insert. Then search for Transform > eulerAngles, click and drag from the output of the eulerAngles unit and select Vector3 and scroll down and select the top-most y option. Hook the output from the eulerAngles into the get X, and the Get X output into the y of the Euler Unit. Done right you should now have something like this:


If you play the game now you should see that we're able to play, move in the right directions and look wherever we want! Last thing to do is to multiply the new Vector3 value with our Movement Speed variable. Do this by inserting a multiply unit between the already existing one and the CharacterController, hook up the output from the multiplier into the new one, then search for Get Movement Speed and hook that into the B input of the new Multiplier. Given that the Movement Speed variable has a value of something greater than one this should make the player move faster. So the movement graph should now look like this:


4. Finished!

That's it! You can take this graph and extend it, add more functionality if you want to, do all kinds of crazy things. Hope this tutorial was useful in some way :)

(I probably didn't structure this in the right way but if anything you can just follow along with the pictures. I know I would)

Bolt Version:
Unity Version:
Platform(s):
Scripting Backend:
.NET Version (API Compatibility Level):

I should update this tutorial and replace "Find game Object" with a Get Variable unit and add reference to the camera using the variables panel. That way you attach the camera object directly and you have the connection established from the get go without risking null errors. But if you want to make sure you find the camera everytime without a null return then make sure the name is something exremely specific like "FPS Camera Head" or something that nothing else in the scene is named and then find that gameobject using that name.

Using find should be avoided for the most part because of this risk. Use references instead!

Thanks for the reply! I'm not sure where my comment went to be honest, but I did figure out that I was just referencing the wrong camera object. However, I still cannot get vertical rotation to work--even though there are no more errors, its just not working.

I should mention that I am trying to mold this into a third person controller since I cannot find any tutorials on that one. Just trying to get the camera to work at a distance instead of inside the character head. I can still play with it, but this tutorial worked well for me from the get go, it's been super helpful!

Do you know how to increase the X axis rotation speed? Can that be added to this graph?

I've spent 5 days trying to figure this out and I just can't.

I tried this tutorial, and I still can’t look up or down. Please help

+1

When i move my mouse on the x axis, my character looks up and down help

Hi. Please send me screen shot of your graph) 

Hello im having a problem with the code,currently i cant look based on Y axis,Please help.
Here's a screenshot of my unit.

If anybody can help,Thank You!
Note : I already changed the 3 variable values to graph and still didnt work.