
Specialization
Player movement in Unreal Engine
What and why?
Player movement has been my absolute favorite thing to work on during my time at The Game Assembly. Additionally, I got to explore Unreal Engine 5 a bit during the 6th and 7th game projects, but I had been wanting to get to know the engine better. Therefore, for my specialization, I decided to combine the two and, using UE5, created a player with a few selected features that I wanted to both feel and look smooth and satisfying to control.
Using Blueprints
I got started by prototyping the functionality using Blueprints and later “translated” it to C++. Aside from the camera and basic horizontal player movement, I decided to implement jumping, sliding, and ledge climbing.
Camera, movement, and jumping
I began by creating the camera and basic player movement. Luckily, there are many great tutorials online which helped me get started. I then moved on to implementing the jump functionality. There already existed a Jump and a Stop Jumping action node, but it wasn’t very forgiving – jumping of a ledge a split second too late simply resulted in falling. I therefore decided to add a coyote timer, giving the player a chance to still jump when leaping of a ledge, as long as the input occured before the timer ran out. Just by adding this, the gameplay experience was massively improved. The accompanied gif shows a coyote time of two seconds.

Sliding
The following picture shows how I created the slide functionality. To prevent the player from sliding when standing still, I started with a simple velocity check. To actually make the player able to slide beneath things, its’ collider size needed to change. For this, I used the existing Crouch and UnCrouch action nodes. I created an animation montage of the sliding animation, which could be played from the script, making the player crouch (and thus resizing the collider) when sliding and uncrouch (resetting the collider size) at the end of the animation. The Do Once node was used to ensure that the action could only execute once, and was only reset once the player had uncrouched, preventing the slide functionality from being spammed.

Ledge climbing
In order to implement ledge climbing, I first created two custom functions: one that performs a horizontal sphere trace in front of the character to detect the nearest collision point, and another that performs a vertical sphere trace to locate the top ledge of any object in front of the player. This logic is visualized in the adjacent image.
To ensure that not all objects in the player gym are climbable, I created a custom trace channel called ClimbableSurface, which can be described as a filter used by traces to determine which objects they should interact with. By doing this, the sphere traces only detect objects marked as climbable while ignoring everything else.

By performing the two sphere traces, I could get the location and normal of the climbable surface, as well as the location of the ledge. By checking whether the player’s hip socket was within a certain distance from the ledge, the custom event Hang could be triggered. This initiated the animation montage for the hang-to-climb transition and used the wall data from the sphere traces to move the player into a position where it looked like it was hanging on the ledge. The custom event Climb Up then played the rest of the animation montage while moving the player up onto the ledge.
Setbacks
The main issue I ran into during this process was animation-related. As soon as the basic movement and jumping had been implemented, I decided to include animations alongside each new feature to avoid having a technically functioning but visually T-posing character. I used animations from Mixamo, but not all of them were compatible with Unreal’s default skeleton. I therefore switched to using a Mixamo model as well, but its’ skeleton was missing a root bone. This became a problem when I wanted to use root motion for the sliding animation – meaning that I wanted the collider to move with the mesh during the animation, which wasn’t happening at the time. I spent many hours trying to fix the animation manually until I eventually found a Blender plugin that added the root bone for me. After that, implementing sliding and ledge climbing became much easier and looked a lot better.
Result
The following video showcases all of the features that I implemented using visual scripting.
Translating Blueprints to C++
As the specialization period was coming to an end, I had to prioritize some features over others. Ledge climbing, therefore, had to be cut when translating the Blueprints into C++.
Camera and basic movement
I was able to implement the camera and basic player movement relatively quickly. I did, however, feel like the player was moving rather slowly. While I could have simply adjusted the player’s max speed until satisfied, I had recently been thinking a lot about Hogwarts Legacy and how the game allows the player to switch between walking, jogging and sprinting – a feature I really enjoyed. Inspired, I decided to implement this in my project.
Sliding
Initially, when I created the sliding functionality, I used the already existing Crouch and UnCrouch nodes to resize the player’s collider. This caused the collider to resize instantly when sliding. While it worked, it also made the camera jerk to its’ new position every time a slide started or ended, due to it being attached to the collider. I wanted the camera to move more smoothly between the crouched and uncrouched collider sizes, and therefore chose to manually interpolate between the collider heights instead of using Crouch and UnCrouch.

float NewHeight = FMath::FInterpTo(GetCapsuleComponent()->GetUnscaledCapsuleHalfHeight(), TargetCapsuleHalfHeight, DeltaTime, CapsuleLerpSpeed);
GetCapsuleComponent()->SetCapsuleHalfHeight(NewHeight);
This approach, however, introduced a new challenge. Every time the player started sliding, its’ mesh “fell” through the floor and only the top of its’ head was visible until the animation was complete. This was solved by adjusting the relative location of the mesh during the slide and interpolating it back to its’ original position afterward.
float MeshOffset = TargetCapsuleHalfHeight - StandingCapsuleHalfHeight;
float TargetZ = (MeshOffset < 0.f) ? MeshOffset : -90.f;
FVector CurrentMeshLocation = GetMesh()->GetRelativeLocation();
float SmoothedZ = FMath::FInterpTo(CurrentMeshLocation.Z, TargetZ, DeltaTime, MeshLocationLerpSpeed);
GetMesh()->SetRelativeLocation(FVector(0.f, 0.f, SmoothedZ));
Result
The following video showcases all of the features that I implemented using C++ code.
Reflection
Overall, I think this project has been a great learning experience. One of my main goals was to become more familiar with Unreal Engine and working with Blueprints gave me valueable insight into a core part of the engine. It helped me better understand the logic and flow behind the features I was building, especially since most tutorials I could find were Blueprint-based. This, in turn, made the later transition to C++ much smoother.
If I’d had more time, there are a few things I would have liked to explore further. Implementing ledge climbing in C++ would’ve been a fun and valueable challenge. I also wanted to improve some edge cases – for example, reducing the risk of the player getting stuck while sliding under obstacles, as well as refining the jump functionality to be even more responsive to quick changes in movement.
All in all, this project has has improved both my technical skills and my confidence working in Unreal. I’ve learned a lot about problem-solving, animation handling, and how to balance visual and functional design – all of which I’ll carry with me into future projects.
