top of page
DES450 3D Platformer Character Project

For my Technical Design Capstone project, I created a 3D third person platformer character controller in Unreal Engine 5 that inherits from the APawn class. The goal of this project is to make a highly customizable character controller that designers can use without needing to touch code or blueprints. The character controller uses curves to give flexibility to different customizable mechanics that I have implemented.

At the base of this project is the design choice to use curves to control the velocity of the character. I decided to go in this direction because it would allow designers to have more control over the behavior of the character. In order to allow for a more streamlined workflow, I decided to act as if the curves are restricted to [-1, 1] on both axes. Next to the curves in the inspector, I made it so that designers can specify the MaxEvaluationTime for the t axis and the MaxValue for the f(t) axis. These are scalars that designers can use quickly change the speed or acceleration of a behavior without having to take the extra steps involved in modifying a curve.

​

The character has a Base Movement section which controls the general movement for when the character is on a flat surface. Designers can specify max base movement speed, the time to reach max movement speed, and the time stop movement. The character moves towards a target direction that is found by taking the joystick direction and translating it to the perspective of the camera. The character rotates towards the target direction with a specified turn speed.

​

The character has a Slope Movement section which dictates how the character reacts to slopes. When I worked on this mechanic, I found that treating the slope movement as an override of the base movement would lead to awkward jumps in the player's velocity as the code transition from evaluating one curve to a different one. My solution was to approach this more physics-oriented slope mechanic a bit differently by having additive curves rather than curves that override the base logic. The slope movement works by adding an acceleration value found using a Slope-Angle-To-Acceleration curve, and the speed of the character is capped by a Slope-Angle-To-Target-Velocity curve.

​

The player can quick turn by moving the joystick in the opposite direction that the character is moving. To determine when this occurs, I calculate a dot product between the current target move direction and the previous target move direction. If the dot product is less than -FOV_In_Radians, then the current target move direction is close enough to being opposite to the previous target move direction, and so a quick turn is initiated.

​

Movement in the air is done similarly to movement on the ground, except the player does not rotate and instead strafes left or right based on joystick input. This is achieved by splitting the movement into forward movement and sideways movement and evaluating the speed of both movement components with different velocity over time curves.

​

Jumping is evaluated using a custom JumpCurve struct which contains Button-Hold-Time-To-Velocity curves for both vertical and forward velocity. The designer can choose to have infinite hold time and choose whether to have the velocities be additive or override all other velocities.

​

While creating functionality for a glide, I realized that the jumping logic could be repurposed to incorporate it. I implemented the ability to specify an array of JumpCurves that allows for chaining unique jumps. Designers can add a double jump by adding a second jump curve to the array. A glide can be added by creating a jump with a decreasing or flat curve.

​

To wall slide, the character checks for a wall in front of them. If they are close enough, they go into the wall slide state and slowly accelerate downward. While in the wall slide state, they can do a wall jump that makes the player jump along the wall's normal vector.

bottom of page