Let’s Make a Character Speed system
Character speed that is directly affected by the slope the character is walking on.
LET’S MAKE a movement system that takes into account the current slope under the character and sets their speed over time.
This idea came about when a student of mine wanted to explore a landscape they created in Unreal but felt like running up large mountains and hills at the same speed they moved down was strange and unrealistic. Instead they wanted to simply slow the character down as they climb a steep slope and speed them up when running down hill.
We worked out a quick solution and I wanted to share it here for others! We will make a system that:
- Sets the character speed based on current angle of their surface
- Uses two line traces
- Uses float curve to control our speed
- Blueprint only
- Using Unreal Engine 4.8.1
Updated Video Tutorial:
As an approach to getting tutorial content out faster I am beginning to switch to video format. You can find the new version of this tutorial here:
I will continue to keep the previous version up as well for those who want to look through it. However, after the tutorial was made I was able to find the walkable surface for the character. This can be accessed by going through:
Character Movement Component -> Get Current Floor
Which returns the hit result and a few other variables to use. Note that the video version also has a better way to find the angle just through checking the character’s locations. Using line tracing is fine but is overkill compared to this simpler approach.
Previous Tutorial: How it will work
Our basic idea is to use two line traces to get the angle of the world below us. We then use that angle and feed it into a float curve which gives us control over the speed based on the pitch.
We use line tracing to get our angle as I have not found a way to get the walkable surface angle check from within Blueprint. This is the check that finds out if a surface can be walked on, it’s defaults can be set within blueprint but finding the floors current angle is not available. It should be available in C++ but as we are only using Blueprint we need this step.
We are using the Third Person Template here but the code is interchangeable with the First Person Character as well as most others. We need a character as well as a float curve so lets add them in. Adding in the float curve is shown below as its a bit harder to find if you haven’t used it yet.
Lets setup the Float curve first so we don’t have to worry about it later, double click to open it up and shift click to add in a point. We want to do this 4 times and set them as shown below.
As you can see from each key we start off high and move lower towards the right. This is because we are using the time as the angle, starting from -45 degrees, which would be down hill. As we approach the middle we even out and no longer change the velocity for small inclines. Once we approach 45 degrees we are traveling up hill and need to slow our character down drastically.
Feel free to play with these numbers to get the movement speed you like!
Next open up the character blueprint and add in the Tick event. Once it is added in promote the Delta Seconds float to a variable to keep track of our DeltaTime as we will need it later.
After this we create a new function, call it UpdateMovementSpeed and connect it to our tick event.
This function will act as our main container for all of our other functions for updating the character speed. Create 3 more functions that will be placed within the Update Movement Speed, below are each function we will create:
- Should Update
- Do not update if we are standing still
- Do not update if we are in the air
- Get Movement Angle
- Setup 2 line traces to find the angle of the current surface
- Set Movement Speed
- Find angle and get speed based on pitch
Once created, connect each function in the stated order.
Notice that we have a few inputs and outputs shown in the image for each of the functions so lets set those up!
Within the ShouldUpdate function we need to output a boolean variable which makes sure we should even update our movement speed at all. To do this select the function and hit the New Output in the details panel and rename it to something descriptive. I have mine set as ShouldUpdate.
We then place the branch node between the two functions taking in the output as its Boolean check. This just makes sure we are never checking or updating speed when we don’t want to.
Select the GetMovementAngle and add a new float output. This will is our pitch and will feed into the next function SetMovementSpeed.
Finally select the SetMovementSpeed function and add in a float input, connect it to our previous GetMovementAngle.
At this point we should be ready to move onto setting up each of the functions we just created so lets dive into the first one, the ShouldUpdate Function.
Should Update Function
Here we see that we want to check if the player is not currently jumping and they are currently moving. If they are jumping or if they are standing still we return false and stop the function from continuing.
This function is pretty easy to setup as we only need to grab the character movement variable and do a few checks. Drag and drop the character movement variable and get its IsFalling variable and get its velocity. We want to make sure we are not falling so add a NOT node before adding it to the AND node, hooking them up as shown. With the velocity we want to make sure we are greater than 0, this means that if we are standing still we don’t update the function any further.
The AND Node makes sure that our function will only return true if both conditions are met, if the character is jumping but moving, it will still return false. Same goes for if the character is not jumping but is standing still, it is set to false until both conditions are true.
Once we connect everything together and return our Boolean we are good to go!
Get Movement Angle Function
The next function GetMovementAngle uses two line traces to find two locations we will use to get our floor angle. But before we get a head of ourselves we need to add two variables and one local variable. Add in the following:
- Set as a Float Curve type
- Set to use our custom float curve
- Set as Vector type
- Set as (0,0,-200)
- Traces down to find the ground location
- First (Local Variable)
- Set as Vector type
- Just used to keep blueprint clean
Below is the function we will be creating, starting off by tracing downward from the player to get the ground location. We then save out this location into our local variable and move on to the second trace. You can also see the variables we just created on the left.
By using the character’s velocity we can normalize it and get the direction of travel, regardless of the player’s direction. This means our character can be moving backward, strafing or running forward and our code shouldn’t have any issues with checking for the angle of the floor.
We then set the velocity length to a map node which allows it to be remapped from 0 / max speed, to 0 / 100. I chose 100 units as it seemed far enough to check for the incline but close enough to get a good and accurate result. The Map also allows all the values in between to be used, so if our character is walking it will check closer than if they were running.
Once we have the direction of travel we can trace from that location down searching for the ground hit location.
Finally we take both of our locations, the one right under our character and the one outward in the direction of travel, and use them to get our angle. Unreal has a nice node for it called Find Look At Rotation so we don’t have to do any math to find the angle pitch. We then break the rotation and pass the pitch onto the next function through our output.
Set Movement Speed Function
Inside the SetMovementSpeed function we will be interpolating from our current speed to our desired new speed (The FInterp Node which simply updates each frame so the change occurs over time).
Setup the function as shown below:
Note that we have another float variable named MovementChangeRate which controls how quickly the character will update to the desired speed. Go ahead and create the variable and set it to your desired rate, mine is set to 2.0 at the moment.
We also have a print string node at the end to check our character’s speed but this is for debugging purposes and can be removed once we know its working.
Once this is setup it should all work! Your character will slow as they walk up large hills and speed up when moving down them.
I had fun trying to figure this out with my students in class and I hope others find it useful as well!