Character Movement Fundamentals
Character Movement Fundamentals
User Manual
Version 2.2
March 31, 2021
Showcase
’ShowcaseScene’ is meant to demonstrate how the controller moves on different terrains, slopes and
stairs as well as to showcase some interesting gameplay possibilities using special level elements (moving
platforms, switching gravity).
It also allows you to switch between different controller prefabs (first person prefab, multiple third
person prefabs).
1
’TopDownScene’ offers a similar experience, but with a focus on gameplay from a top down perspective.
Special
2
’ExternalCameraScene’ provides an example of a possible camera setup where the character and the
camera are two separate gameobjects.
Although the camera is continuously rotating around a fixed axis, the character will always move in
relation to the current camera view.
3
Just open the scenes, press play and you’re ready to go! Player controls are explained in the scenes
using UI elements or text meshes.
Prefabs
This package also comes with 16 fully functional controller prefabs, which can be found in the ’Con-
troller Prefabs’ folder. They are organized into ’animated’, ’blank’ and ’simplified’ prefabs.
Blank controller prefabs are purposely put together using only components that are absolutely nec-
essary for the controller to function. They are meant to be a ’blank slate’ or base from which start
from.
Animated controllers come with basic animation (and sound) already set up and serve as an example
on how to link animations and sound cues (like footsteps) with the controller’s movement.
Alternatively, they are also very well suited for quick prototyping.
Simplified controllers use a stripped down, simplified controller script and can serve as an easy intro-
duction for anyone new to character movement scripting.
You can use these prefabs by simply dragging them into an empty scene - no further setup is required.
All controller prefabs come with their own cameras, so make sure to delete any unused cameras in the
scene afterwards.
4
Fig. 8 Select a controller prefab ...
5
Fig. 10 ... and delete the old camera.
Contents
1 Introduction 1
3 Package Structure 6
4 Basic Principles 9
4.1 ’Anatomy’ of a Basic Character Controller . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.2 Three Ways to Use this Package in your Projects . . . . . . . . . . . . . . . . . . . . . . 10
6 Component Descriptions 17
6.1 Mover . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
6.1.1 Ceiling Detector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
6.2 Controllers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
6.3 Character Input Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
6.4 Camera Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
6.5 Camera Input Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
6.6 Smoothing and Other Visual Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
6.7 Animation and Audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
6.8 Environment Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.9 UI Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
7
9.2 Adding Forces to a Controller . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
9.3 Rotating the Camera Toward a Target Direction or an Object in the Scene . . . . . . . 49
9.4 Changing Collider Dimensions at Runtime . . . . . . . . . . . . . . . . . . . . . . . . . . 50
1
Fig. 12 Falling, jumping and stopping at walls.
I want to help other developers avoid these common pitfalls altogether and that’s exactly why I created
this package.
To make things as easy as possible for you, this package comes with example scenes, lots of fully set
up controller prefabs and fully documented scripts to help you understand what’s going on behind the
scenes. Even if you don’t intend to write any code, you’ll still be able to create controllers for almost
all types of games just by modifying values in the inspector - all of the components are designed to be
as versatile as possible.
2
(a) First person view.
3
• All-purpose camera system
Highly customizable, can be adapted to work in a wide variety of games.
Built-in camera smoothing system for smooth camera rotations.
Adjustable camera angle limits.
Invertible camera axes.
Different sensitivity settings for gamepad and mouse input.
• Five example scenes to showcase the various features of the package.
• A set of 16 ready-to-use controller prefabs that can be ’drag and dropped’ into any scene -
no further setup required.
A first person camera walker prefab.
A top-down walker prefab.
A 2D sidescroller prefab.
Three different third person camera walker prefabs.
A top-down, ’click-to-move’ walker prefab.
All prefabs come in two versions: One version with animations and sound already set up
and a blank version, for easier customizing.
Two ’simplified’ controller prefabs.
• A collection of environment assets, which can be used for quick prototyping.
Basic environment building blocks (cubes, ramps, stairs, tiles), all textured and set up with
materials.
A simple moving platform system.
4
Fig. 15 ...and a simple level made using these building blocks.
5
3 Package Structure
The package is structured as follows:
To keep everything organized, all package assets are contained in one root folder (’Character Movement
Fundamentals’). This ensures that your project files stay separated from the package’s files if the
package is imported into an existing Unity project.
On the top layer, you’ll also find a copy of this user manual and a readme file that keeps track of all
changes between different versions of this package.
Example Scenes
This folder contains all example scenes in the package, split into three ’showcase’ scenes to demonstrate
the package’s capabilities and three ’special’ scenes for less common level setups.
Example Scenes
Showcase
EmptyShowcaseScene.unity
ShowcaseScene.unity
TopdownScene.unity
Special
ClickToMoveScene.unity
ExternalCameraScene.unity
PlanetWalkerScene.unity
Source
All meshes, animations, sounds files, materials, textures and scripts can be found in this folder.
Source
Capguy
Meshes, animations, textures and materials for
the capguy character model
[...]
Environment
Meshes, animations, textures and materials for
all environment assets
[...]
Scripts
Sounds
Misc
6
All assets are organized by their use - files related to the environment assets are separated from the
files used by the Capguy character (a low-poly, rigged and animated character model).
This makes it a lot easier to delete unneeded parts of the package - if you find no use for the Capguy
character, you can safely delete its folder to reduce the overall package size.
Apart from that, ’Scripts’ contains all scripts, all sound files are located in ’Sounds’ and ’Misc’ contains
miscellaneous files like fonts, shaders and physics materials.
Prefabs
In this folder, you’ll find all the prefabs included in this package.
Prefabs
Controller
Animated
ClickToMoveWalker Animated.prefab
FirstPersonWalker Audio.prefab
SideScroller Animated.prefab
ThirdPersonWalker A Animated.prefab
ThirdPersonWalker B Animated.prefab
ThirdPersonWalker C Animated.prefab
TopDownWalker Animated.prefab
Blank
ClickToMoveWalker.prefab
FirstPersonWalker.prefab
SideScroller.prefab
ThirdPersonWalker A.prefab
ThirdPersonWalker B.prefab
ThirdPersonWalker C.prefab
TopDownWalker.prefab
Simplified
SimpleFirstPersonWalker.prefab
SimpleThirdPersonWalker.prefab
Environment
Interactive
GravityFlipper.prefab
GravityTunnel.prefab
MovingPlatform.prefab
Static
A collection of basic level building blocks
(ramps, tiles, walls...)
[...]
As already mentioned, most of the controller prefabs come in two versions -’blank’ and ’animated’.
Blank controller prefabs are purposely put together using only components that are absolutely neces-
sary for the controller to function. They are meant to be a ”blank slate” or base for more advanced
controllers.
Animated controllers come with basic animation (and sound) already set up and serve as an example
on how to link animations and sound cues (like footsteps) with the controller’s movement.
7
Simplified controllers use a stripped down, simplified controller script and are a great starting point
for anyone new to character movement scripting.
All environment prefabs are split into ’interactive’ and ’static’. Generally speaking, all interactive
environment assets are used in the example scenes for demonstration purposes. The static environment
assets are composed of modular level building blocks and are used in all example scenes. They are also
very useful for quick prototyping of game environments.
More detailed descriptions of each controller prefab can be found in chapter 5, ’Overview Over All
Included Controller Prefabs’.
8
4 Basic Principles
4.1 ’Anatomy’ of a Basic Character Controller
Mover and Controller
All character controllers in this package follow the same basic idea: The task of moving a character
around the scene is split between two components, a ’Mover’ and a ’Controller’.
On its own, the Mover component won’t do anything. Instead, it expects a movement velocity (and
direction) from another script, which we’ll refer to as a ’Controller’ from now on.
After having received a movement velocity, the Mover component will then set the rigidbody’s velocity
appropriately, make sure that the character maintains the correct distance from the ground and stores
any useful collision information (whether the character is grounded, for example).
In the following frame, the Controller will use that information to determine the new movement vector,
pass that vector to the Mover and the cycle repeats.
Or put differently, you can think of the Mover as the body of the character and the Controller as the
brain. One makes the decisions, the other one carries them out.
This setup makes it possible for all characters in a game to use the same basic Mover component. By
choosing different Controllers, we then can implement all kinds of different movement patterns and
behaviours. We could even switch controllers during gameplay!
Object Hierarchy
When it comes to gameobject hierarchy, all character controllers in this package are structured very
similarly. The Mover and Controller components are added to the root gameobject of the hierarchy,
any other parts (like the camera system and the character model) are added as children to that root
gameobject.
Usually, the character mesh/model/animations and the camera system are split into two different child
hierarchies, both for practical and organizational reasons. For example, many third person games will
have the camera fall slightly behind the character model, for a smoother gameplay experience. This
effect is easily achievable by using this design.
In special cases, empty gameobjects may be inserted between the different root gameobjects to prevent
certain scripts from interfering with each other.
9
4.2 Three Ways to Use this Package in your Projects
Depending on your programming experience and your game’s specific requirements, there’s (roughly
speaking) three general ways you can use this package to help you realize your projects.
10
5 Overview Over All Included Controller Prefabs
The selection of character controllers included in this package are designed to cover a wide range of
gameplay types. Each one is meant to provide a good starting point for your own individual character
controller, which is why you’ll find all of them containing only the bare essentials needed for the
character controller to function.
As mentioned in chapter 3, most of the character controllers come in two variants - blank and animated.
Both are functionally identical, however, all animated variants are set up with simple animation
and sound effect systems as an example on how to link character movement and animations/sounds
together.
This chapter will provide a quick description of each prefab, what kind of gameplay styles they are
most suited for and which special components they make use of.
All Controllers
Generally speaking, all prefabs use the following set of basic components (with different settings):
• Mover
• Smooth Position
• Smooth Rotation
11
As the name implies, the player camera is positioned where the character’s eyes would be, giving you
a first-person perspective of the game environment.
This prefab is a great starting point for any kind of first-person character controller. By changing some
of its properties in the inspector (like movement speed, jump speed, air control...), you can fine-tune
its movement to suit almost any type of gameplay.
It uses the following components:
ThirdPersonWalker A
This prefab serves as a basic foundation for a typical third person controller.
Movement-wise, it functions very similarly to the FirstPersonWalker preset, however, the player cam-
era is positioned outside and slightly above the character’s head.
To prevent the camera from going into level geometry or other objects in your scenes, all third-person
prefabs also use a special component called Camera Distance Raycaster, which scans for any colliders
blocking the camera’s view.
In addition to this, the 3D model of the character is continuously rotated toward the movement
direction of the controller.
It uses the following components:
12
ThirdPersonWalker B
This prefab is almost identical to ThirdPersonWalker A, the only difference being that it uses a slightly
more specialized camera controller script, which turns the camera toward the characters movement
direction.
This behaviour is commonly expected by players in third person games, which are not primarily
shooters, such as the ’Dark Souls’ or ’Spyro the Dragon’ series, for example.
ThirdPersonWalker C
This prefab is also almost identical to ThirdPersonWalker A, this time however, the character model
is always rotated toward the direction the camera is facing.
This makes sense for almost all third person shooters (a popular example being ’Fortnite’ ), since the
player character commonly aims in the same direction as the camera.
13
TopDownWalker
If you need a character controller suited for a top-down game, this prefab will meet all your basic
requirements.
The camera itself is offset quite far above the character and camera rotation around its x-axis (the
”pitch” axis) is disabled.
ClickToMoveWalker
This controller provides basic ’click-to-move’ functionality - simply click anywhere on the screen and
the controller will move toward the chosen position.
This kind of movement is commonly found in top-down role-playing games, like the ’Diablo’ series, for
example.
By default, this controller does not include any camera controls (though it’s easy to add them if
needed).
14
SideScroller
This prefab is meant to provide a solid foundation for any 2D character controller - whether you’re
developing a 2D retro platformer, a sidescrolling shooter or a stealth game set in 2D, this prefab is a
good starting point.
In contrast to the other prefabs, character movement is locked to a 2D plane and the camera position
and rotation is fixed, as is usual in most 2D games.
• Sidescroller Controller
• Turn Toward Controller Velocity
• Animation Controller
• Audio Controller
15
5.2 ’Simple’ Controller Prefabs
The package also comes with two ’simple’ controller prefabs. The main purpose of these prefabs is to
provide an easier introduction for anyone who’s never worked with character movement logic before.
SimpleFirstPersonWalker
This prefab is a simplified version of the ’FirstPersonWalker’. The only real difference between them
is that this prefabs uses the Simple Walker Controller component.
SimpleThirdPersonWalker
This prefab is a simplified version of the regular ’Third Person Walker’ prefabs. Again, the only
difference is the use of the Simple Walker Controller component.
16
6 Component Descriptions
In order to use this package to its full potential, it is helpful to have a good understanding of all the
components and their configurable variables available in the inspector.
This chapter will provide a thorough description of all components and their settings and how to
customize them to fit your game.
6.1 Mover
The Mover component is used by all character controllers in this package to handle character movement
and any interactions with the environment.
It also handles resizing the character’s collider and automatically updates any changes to its dimensions
while the editor is running. As a result, you should use the settings provided by this script to change
the shape, size and offset of the attached collider instead of directly changing settings on the collider
component itself.
17
To optimize your game’s performance, you can choose between different sensor types for ground de-
tection.
Different sensor types may exhibit slight differences when dealing with certain slopes and level geometry
- I recommend giving each one a try to determine the best fit for your game.
The component will require a rigidbody and a collider to work. All basic Unity colliders (box, capsule,
sphere) are supported, although I recommend using the capsule variant, as its shape is better suited
to interact with most types of level geometry.
Step Height Ratio Acceptable step height ratio. This value ranges from ’0’
to ’1’ and is relative to the collider’s height. For example,
value of ’0.5’ means that the character will be able to
walk on stairs half its height. See figure 25 for a visual
example.
Collider Height Height of the attached collider
Collider Thickness Thickness/width of the attached collider.
Collider Offset (Relative) position offset of the attached collider.
Sensor Type Which type of sensor will be used for ground detection.
Debug Mode If debug mode is enabled, all surface points and normals
detected are displayed in the editor. Also see figure 24.
Sensor Array Rows If ’RaycastArray’ is chosen as the sensor type, this will
control how many rows the array will have.
Sensor Array Ray Count If ’RaycastArray’ is chosen as the sensor type, this will
control how many rays each row in the array will have.
Sensor Array Rows Are If ’RaycastArray’ is chosen as the sensor type, this will
Offset offset every other row for a better ray distribution.
In addition to that, if ’RaycastArray’ is chosen as the sensor type, a preview will be shown at the
bottom of the inspector (see figure 23b).
18
Fig. 24 With debug mode enabled, detected surface points and normals are shown in red in the scene
view. Using the wireframe view mode is recommended for better visibility. The calculated average
position is shown as a green arrow.
Fig. 25 In the image above, ’step height ratio’ is set to ’0.25’. All obstacles lower than the resulting
height (orange), which is exactly 1/4th (= 0.25) of the characters height (shown in purple), are walkable
- the blocks on the right (green) will be treated as stairs, while the block on the left (red) is considered
a wall.
19
6.1.1 Ceiling Detector
The Ceiling Detector component is an optional component that, if attached to a gameobject that also
has an Advanced Walker Controller component, will help register collisions with colliders above the
character.
The component uses Unity’s collision callback functions (’OnCollisionEnter’, ’OnCollisionStay’) and
will determine whether a collision qualifies as a ”ceiling collision” based on the collision normal.
For more information on how this component works internally, please check out chapter 8.4, ’Detecting
Ceilings Collisions with the ’CeilingDetector’ Component’.
Ceiling Angle Limit This angle limit is used to determine whether a surface
normal counts as a ceiling contact. A value of ’0’ will
never register any collisions, while any value above ’90’
will treat almost anything as ceilings, even walls. For
most cases, ’15’ will work best.
Ceiling Detection This will determine how the component handles multi-
Method ple collision normals. Options include: Only check the
very first normal (’Only Check First Contact’), check if
at least one contact qualifies (’Check All Contacts’) and
checking the average of all contacts (’Check Average Of
All Contacts’).
Is In Debug Mode If enabled, collision contact information will be drawn in
the editor.
20
6.2 Controllers
Simple Walker Controller
This controller offers simple movement options and is used by the ’simple’ controller prefabs included
in the package.
It will get player input from an Input script, keep track of the current vertical speed of the controller
and calculate a movement vector, which is then passed to the Mover component.
21
Movement Speed General movement speed of the controller.
Air Control Rate Rate at which the controller can change direction while
in the air. Generally speaking, a higher value will result
in a more responsive but less ”realistic” game feel.
Jump Speed Jump speed of the controller. Higher jump speed values
will allow the character to jump higher.
Jump Duration Maximum jump duration of the controller. If this value
is set to anything above ’0’, the player can keep pressing
the ’jump’ key for a higher jump.
Air Friction Amount of friction applied to the controller’s momentum
when it is in the air.
Ground Friction Amount of friction applied to the controller’s momentum
when it is grounded.
Gravity Amount of (downwards) gravity when the controller is in
the air.
Slide Gravity Amount of (downwards) gravity when the controller is
sliding on a steep slope.
Slope Limit This controls whether a surface is considered as ground
or as a slope, based on its surface normal. For example, a
value of ’70’ will allow the controller to walk on all slopes
that are less steep than 70 degrees.
Use Local Momentum If this is enabled, the controller’s momentum will be cal-
culated locally (meaning if the controller is rotated, its
momentum will be rotated as well).
Camera Transform If a camera transform is assigned, the controller will move
relative to that camera’s view. If left blank, the con-
troller’s transform axes will be used instead to calculate
its movement direction.
Sidescroller Controller
This component extends the Advanced Walker Controller and locks (horizontal) character movement
to a 2D plane defined by the character’s local ’up’ and ’right’ transform axis.
22
Click To Move Controller
This controller provides basic ’click-to-move’ controls - the controller will continue to move toward the
position the player has clicked on, until the target position is reached or a new target is chosen.
In addition to that, the component also comes with a few customization options, such as:
• Allowing the user to hold down the mouse button to keep the controller moving.
• Two different raycast detection methods to determine the target position.
• A simple time-out system that will stop the controller from moving if it gets stuck (in a corner,
for example).
23
6.3 Character Input Scripts
Character input scripts are responsible for calculating and processing user input. At runtime, these
scripts will be accessed by the controller components to get the latest input.
Horizontal Input Axis Name of input axis used for going left/right.
Vertical Input Axis Name of input axis used for going forward/backward.
Jump Key Key used for jumping.
Use Raw Input Whether to use raw input values or Unity’s built-in
smoothing when calculating input.
Horizontal Input Axis Name of input axis used for going left/right.
Vertical Input Axis Name of input axis used for going forward/backward.
Jump Key Key used for jumping.
Use Raw Input Whether to use raw input values or Unity’s built-in
smoothing when calculating input.
Dead Zone Threshold Any input value below this threshold will be set to ’0’.
This helps with preventing any unwanted inputs caused
by joystick jitters.
24
6.4 Camera Scripts
Camera Controller
This component is a general-purpose camera controller - thanks to its adaptability, you can use it in
almost any game that requires a player-controlled camera.
It provides built-in camera smoothing for a more ”natural” game feel and options for limiting the
vertical camera angle.
Upper Vertical Limit Upper limit (in degrees) of the rotation around the x-axis.
Lower Vertical Limit Lower limit (in degrees) of the rotation around the x-axis.
Camera Speed Speed at which the camera rotates.
Smooth Camera Whether to smooth player input for a smoother camera
Rotation rotation.
Camera Smoothing If ’Smooth Camera Rotation’ is enabled, this value will
Factor be used to smooth the camera’s rotation. A value of ’50’
will result in no noticeable smoothing, while a value of ’1’
will result in very noticeable smoothing.
25
If the option ’Turn Camera Toward Movement Direction’ is enabled, the camera controller will rotate
toward the current movement direction of the character. This camera behaviour is commonly used in
third-person games to give the player a better view of where the character is heading.
The speed of this rotation is tied to the character’s movement speed, as well as the remaining angle
between the camera’s view and the characters movement direction.
Turn Camera Toward If enabled, the camera will turn toward the character’s
Movement Direction movement direction.
Controller Reference to a controller component. The velocity of this
controller will be used to calculate the movement direc-
tion.
Maximum Movement Reference speed used when calculating the speed of the
Speed rotation toward the character’s movement direction. This
value should be set to the maximum movement speed
achievable by the controller (i.e. the ’Movement Speed’
setting).
Camera Turn Speed Speed at which the camera turns.
26
Camera Distance Raycaster
This script will automatically try to detect any obstacles between camera and character and, if any
obstacles are detected, will move the camera closer to the character to prevent it from clipping into
level geometry.
It is recommended to parent the actual camera gameobject to the ’target’ gameobject, in order for the
system to work properly. Please study the included controller prefabs to see this setup in action.
27
Fig. 36 Without the ’Camera Distance Raycaster’ - the camera will clip into level geometry at lower
angles, causing graphical glitches.
Fig. 37 With the ’Camera Distance Raycaster’ enabled - the camera is moved closer to the character
whenever an obstacle is detected. No clipping occurs.
28
6.5 Camera Input Scripts
Camera input scripts are responsible for calculating and processing user input (related to camera
movement). At runtime, the camera controller scripts will then access these inputs scripts to get the
latest input.
Mouse Horizontal Axis Name of input axis used for rotating the camera left/right.
Mouse Vertical Axis Name of input axis used for rotating the camera up/down.
Invert Horizontal Input If enabled, inverts horizontal input.
Invert Vertical Input If enabled, inverts vertical input.
Mouse Input Multiplier Mouse input will be multiplied by this value. Use this to
fine-tune mouse sensitivity.
Joystick Horizontal Axis Name of input axis used for rotating the camera left/right.
Joystick Vertical Axis Name of input axis used for rotating the camera up/down.
Invert Horizontal Input If enabled, inverts horizontal input.
Invert Vertical Input If enabled, inverts vertical input.
Dead Zone Threshold Any input value below this threshold will be set to ’0’.
This helps with preventing any unwanted inputs caused
by joystick jitters.
29
6.6 Smoothing and Other Visual Scripts
Smooth Position
This script will smooth out the position of the gameobject it is attached to by interpolating between
last frame’s position and the current position.
It is used by all the included prefabs to smooth out some of the inconsistencies and occasional stutters,
which can happen from time to time in Unity’s internal physics calculations.
Alternatively, you can use it for a ’smooth camera follow’ effect in third-person or 2D games.
You can choose from two different smoothing methods - Unity’s built-in ’Smooth Damp’ and ’Lerp’
(linear interpolation), which will behave slightly differently. It is recommended to try both and use
the option that serves your game best.
Additionally, the script can either run during Unity’s Update or LateUpdate cycle, to prevent multiple
smoothing scripts from interfering with each other.
30
Smooth Rotation
This script works very similarly to Smooth Position, but smoothes the object’s rotation instead.
It is normally used to rotate a character mesh toward the movement direction of its controller compo-
nent.
31
Turn Toward Camera Direction
This script rotates a gameobject toward the view direction of a Camera Controller component.
Normally, it would be used to make a character look in the same direction as the camera, which is
very common in third-person shooters, for example.
It functions similarly to the Turn Toward Camera Direction component, but uses a target transform.
It can be used to implement a simple ’planetary gravity’ effect when used on a controller prefab.
32
6.7 Animation and Audio
Animation Control
This script serves as a basic animation controller. It is included in this package to demonstrate how
to connect animations and character movement.
It requires an Advanced Walker Controller to work and will pass necessary information (whether the
character is grounded, its current speed) to an animator component.
If ’Use Strafe Animations’ is enabled, a blend tree more suited for strafing character movement will
be used.
Use Strafe Animations Whether to use a blend tree better suited for strafing
character movement.
Land Velocity Threshold The character’s ’land’ animation is only triggered if
the controller’s vertical speed exceeds this threshold on
ground contact.
Audio Control
This script provides some basic audio control features for game characters. It serves as a demonstration
on how to connect animations, character movement and sound effects.
It requires an Advanced Walker Controller component to work and will use the controller’s velocity
and its events to play footstep sounds and sound effects for jumping and landing.
In addition to that, it can trigger footstep sound either when a certain distance has been walked by
the character or based on specific animation curves.
For the second option to work, you need animation curves named ’Footstep’ in your animations, to
trigger a sound every time the character’s animation touches the ground. Please take a look at some
of the animation assets included in this package for a working example.
33
Audio Source Reference to an audio source component, which will be
used to play the audio clips.
Use Animation Based If enabled, footstep sounds will be played based on ani-
Footsteps mation curves instead of based on travelled distance.
Land Velocity Threshold The character’s ’land’ sound effect is only played if
the controller’s vertical speed exceeds this threshold on
ground contact.
Footstep Distance If the above option is disabled, footstep sounds will be
played every time this distance is reached by the charac-
ter.
Audio Clip Volume Volume of all sound clips.
Relative Randomized If set to ’0’, all footsteps will be equally loud. If set to
Volume Range anything higher, footstep sounds will progressively differ
in volume. This results in more natural sounding patterns
of footsteps.
Foot Step Clip Audio clip used for footsteps.
Jump Clip Audio clip used for jumping.
Land Clip Audio clip used for landing.
34
6.8 Environment Scripts
Moving Platform
This script serves as a basic example of a moving platform system and is included in this package
mainly for demonstration purposes.
It will move a gameobject along a predefined path of waypoints and move any controllers standing on
it along.
6.9 UI Scripts
Mouse Cursor Lock
This script serves provides basic mouse cursor locking functionality.
After attaching this script to any object in the scene, you can hide and show the mouse cursor by
pressing assignable keys.
Lock Cursor At Game Whether the mouse cursor will be locked at the start of
Start the game.
Unlock Key Code Key used to unlock mouse cursor.
Lock Key Code Key used to lock mouse cursor.
35
7 Implementing Custom Input
7.1 How the Input Scripts Work
As of version 2.0, Character Movement Fundamentals features a streamlined way to get and process
user input. As a result, implementing custom input systems or even third-party input solutions is now
easier than ever.
Put simply, all input-related code is contained in separate scripts, called Input Scripts, which need to
be attached to the same gameobject as the Controller and Mover components.
At runtime, the controller scripts will get all the necessary input values from these input scripts by
using predefined functions.
There are two distinct types of input scripts included in the package: Character Input and Camera
Input, which will be accessed by controller scripts and camera scripts, respectively.
36
Next, we extend the base CharacterInput class, like this:
public class MyCustomCharacterInputScript : CharacterInput { [...]
At this point, your scripting IDE (Visual Studio, for example), will probably prompt you to implement
the three required functions. For now, we’ll just implement them empty, like this:
public override float GetHorizontalMovementInput()
{
return 0f;
}
Technically, what we have now is already a valid input script and would work as-is when used in
combination with a controller component.
Of course, the script will always return no input, which makes it fairly useless. To change that, we’ll
actually need to return some useful input information.
For example, we could add the following code to the ’IsJumpKeyPressed()’ function:
public override bool IsJumpKeyPressed()
{
if(Input.GetKey(KeyCode.Space) && Input.GetKey(KeyCode.J))
{
return true;
}
else
{
return false;
}
}
As a result, the character will now only jump if the Spacebar and the ’J’ key on the keyboard are
pressed at the same time.
The other two functions should return a float value, typically ranging somewhere from ’-1’ to ’1’.
A very classic implementation could look like this:
public override float GetHorizontalMovementInput()
{
return Input.GetAxis("Horizontal");
}
Which will just get the current axis input directly from Unity’s built-in input system and pass it along.
37
Alternatively, here’s a more unconventional way to achieve a similar result:
public override float GetHorizontalMovementInput()
{
if(Input.GetKey(KeyCode.A))
{
return -1f;
}
else if(Input.GetKey(KeyCode.D))
{
return 1f;
}
else
{
return 0f;
}
}
Generally speaking, you’re free to do whatever you want in a custom input script, as long as the three
functions return the intended values at the end.
For example, you could add code to your custom script to access an external component (maybe a
third-party input solution), receive the appropriate input and pass it along.
You could add a toggle that switches between different kinds of input.
You could invert the input axes, if you want to.
The Camera Input scripts function nearly identical - the only difference being that you would extend
a different base class (’CameraInput’ instead of ’CharacterInput’ ) and override two differently named
functions (as mentioned earlier).
In addition to that, please consider taking a look at all the different input scripts included in the
package to get a better idea of some of the possibilities.
38
8 Writing a Custom Controller Script
In case your game needs some special features, which go beyond what the included controller prefabs
or even overriding input functions can accomplish, there’s always the option of programming a custom
controller script.
Writing your very own controller script may sound difficult at first glance, but thanks to the Mover
component, which takes care of most of the common technical difficulties of character controller pro-
gramming, it’s actually a very straightforward process. Of course, basic knowledge about programming
in Unity is needed here, as this will require you to code.
This chapter may also be relevant for you if you’ve already written a character controller script in
the past (maybe using Unity’s built-in components) and are considering reusing your code in a new
project. Adapting an existing controller script to work with the Mover component should only require
a few minor changes to your code.
void Start () {
//Get references to mover component;
mover = GetComponent<Mover>();
}
void FixedUpdate () {
//Run initial mover ground check;
mover.CheckForGround();
39
For a better understanding of all the basic elements, let’s go through each one separately:
//’CMF’ is the namespace used by the ’Character Movement Fundamentals’ package;
using CMF;
Starting from version 2.0 of this asset, all code in the package is contained within the ’CMF’ namespace
to keep your own code cleanly separated from the included scripts.
As a result, if you intend to use or access any of the code of the package, you need to add a ’using’
directive, usually right below the regular Unity directives.
//Reference to attached mover component;
Mover mover;
void Start () {
//Get references to mover component;
mover = GetComponent<Mover>();
}
Since the mover component will be called every physics frame, it makes sense to store a reference in
Start() or Awake() to save performance.
void FixedUpdate () {
//Run initial mover ground check;
mover.CheckForGround();
Before doing any calculations or checks that rely on whether the character is grounded (or not), it is
crucial to first run the mover’s ground check function.
//Check whether the controller is grounded;
bool _isGrounded = mover.IsGrounded();
After calling the mover’s ground check function, we can determine whether the character is grounded
at any time. Depending on your specific character movement code, being grounded might be required
for the character to jump or change the character’s movement speed, among other effects.
Vector3 _velocity = Vector3.zero;
//Calculate the final velocity for this frame;
[...]
At this point in the script, you would typically put your own code to calculate the character’s velocity
for this physics frame. Later in this chapter, there will a basic code example on how to calculate the
velocity for very basic character movement.
//If the controller is grounded, extend ground detection sensor range;
mover.SetExtendSensorRange(_isGrounded);
To allow the character to move down terrain, slopes and stairs, is is necessary for the mover’s ground
check range to be extended when the character is grounded. This is meant to better approximate
what walking down stairs or slopes feels like: A continuous motion instead of constantly losing and
regaining ground contact.
40
//Set mover velocity;
mover.SetVelocity(_velocity);
Finally, the movement velocity for this frame is passed to the mover component. One important thing
to keep in mind here is that the velocity must not be multiplied with Time.deltaTime.
Kinematic controllers, such as Unity’s built-in character controller, basically expect an instruction like
”Move in this direction by this distance, right now!”, while rigidbody-based controllers, like the
controllers in this package, need to be told something like ”This is your movement velocity, use it later
to calculate your new position when the physics simulation is run!”.
I highly recommend sticking to this script outline, unless you plan on heavily modifying the Mover
component itself (which would go beyond the scope of this user manual).
In order to let the character jump and fall in a believable way, we need a variable to store its current
vertical speed, aptly named currentVerticalSpeed.
This variable’s value will change when the character jumps (by adding speed based on jumpSpeed ) and
when it falls (by subtracting speed based on gravity).
In addition to that, we’ll also add movementSpeed (so we can change the character’s movement speed
if needed) and a simple boolean variable to track whether it is grounded (isGrounded ).
//Run initial mover ground check;
mover.CheckForGround();
Next, after having run the mover’s ground check function, we store the result in our isGrounded
variable.
Vector3 _velocity = Vector3.zero;
On to calculating velocity: We’ll start by adding the characters movement for this frame, which consists
of the player’s input and the character’s movement speed multiplied with two global direction vectors.
Next up is the character’s custom gravity.
41
//Handle gravity;
if(!isGrounded)
{
currentVerticalSpeed -= gravity * Time.fixedDeltaTime;
_velocity += Vector3.up * currentVerticalSpeed;
}
else
{
if(currentVerticalSpeed <= 0f)
currentVerticalSpeed = 0f;
}
Essentially, the above code checks if the character is grounded and if not, subtracts from its current
vertical speed, based on our variable gravity.
However, if the character is grounded, we’ll get rid of any negative vertical speed - after all, we don’t
want any forces pressing the character down, if it is already touching the ground.
//Handle jumping;
if(isGrounded && Input.GetKey(KeyCode.Space))
{
currentVerticalSpeed = jumpSpeed;
isGrounded = false;
}
Right after that, we will implement jumping, by simply checking if a) the character is grounded as
well as b) the player is pressing down the spacebar on their keyboard.
If both conditions are met, we’ll replace the current vertical speed with the characters jump speed,
effectively adding a lot of upwards speed in a split second, thus approximating a jump.
Furthermore, we also need set isGrounded to false, since our character clearly can’t be grounded
anymore, after having just initiated a jump.
//Add vertical velocity;
_velocity += Vector3.up * currentVerticalSpeed;
mover.SetExtendSensorRange(isGrounded);
mover.SetVelocity(_velocity);
The resulting vertical speed is then added to the final velocity by multiplying it with the global ”up”
vector in the scene.
After that, all that is left to do is to extend the mover’s ground check range if the character is grounded
and to finish our script, pass the resulting final velocity to the mover component, which will take it
from here.
Finally, here is the finished script in its entirety:
using CMF;
42
public float gravity = 10f;
void Start () {
//Get references;
mover = GetComponent<Mover>();
}
void FixedUpdate () {
//Run initial mover ground check;
mover.CheckForGround();
//Handle gravity;
if(!isGrounded)
{
currentVerticalSpeed -= gravity * Time.fixedDeltaTime;
}
else
{
if(currentVerticalSpeed <= 0f)
currentVerticalSpeed = 0f;
}
//Handle jumping;
if(isGrounded && Input.GetKey(KeyCode.Space))
{
currentVerticalSpeed = jumpSpeed;
isGrounded = false;
}
mover.SetExtendSensorRange(isGrounded);
mover.SetVelocity(_velocity);
}
}
Please refer to the Advanced Walker Controller (and the scripts which extend it) as well as the Simple
Walker Controller, for examples of more controller scripts. All code is fully documented and, even
though it is more complex, still follows the same basic code structure described in this chapter.
43
8.3 Extending the Abstract Base ’Controller’ Class
The package also comes with an abstract Controller base class that you can extend and use as the base
for your own controller script.
Extending from this base class will allow your custom script to interface properly with some of the
secondary scripts in the package, such as:
To extend this base class in your own controller scripts, include it in your class declaration:
using CMF;
public class MyCustomControllerScript : Controller {
At this point, you’ll need to implement the (virtual) functions of the base class (by using the ’override’
keyword):
public override Vector3 GetVelocity()
{
//Return current controller velocity;
}
In addition to that, the class also includes a set of two delegate functions (’OnLand’ and ’OnJump’ )
that can be called in extending scripts to trigger animations and sounds.
Please see the Advanced Walker Controller and the Simple Walker Controller for some examples of
how you can use these delegates in your own scripts.
44
CeilingDetector ceilingDetector = GetComponent<CeilingDetector>();
if(ceilingDetector.HitCeiling())
{
//Handle collision with ceiling here;
}
However, there’s one important thing to keep in mind when using this script: Always make sure to
call the component’s ’ResetFlags()’ function at the very end of your controller script’s execution.
This resets the last frame’s hit information and could look something like this in your code:
void FixedUpdate()
{
//Your regular controller code goes here;
[...]
45
8.5 Moving a Controller Relative to the Camera’s View
Instead of using global transform axes (like Vector3.up), as we did in the example controller script, it
makes more sense in most games that use a rotating camera for the character to move relative to the
camera’s view.
In this chapter, I’ll quickly go over two ways to implement this in your custom controller scripts.
//We use the character’s ’up’ axis to define a ground plane to project on;
Vector3 groundPlaneNormal = characterTransform.up;
//Normalize result;
projectedForward.Normalize();
After doing this, we can now use the resulting vector to calculate a character’s movement direction.
For a more complex example, I recommend taking a look at the code of the Simple Walker Controller
script, specifically the ’CalculateMovementDirection()’ function, which uses the same method.
46
As seen in the diagram above, each function will return a different vector representing either the
direction the camera is facing in, the corresponding ’strafing’ direction or the direction the camera is
pointing (or aiming) at.
For character movement, you should use the facing direction to move the character forward/backwards
and the strafe direction to move it sidewards.
The aiming direction can either be used to fire projectiles or weapons in shooter games, to raycast for
specific game objects or to determine where the player is currently looking at.
You would use these functions in your custom controller code by replacing the following lines:
Vector3 _velocity = Vector3.zero;
Of course, your character’s hierarchy needs to contain a Camera Controller component and you would
have to get a reference to this component first by using the Start or Awake functions in your custom
script.
47
9 Writing External Scripts
9.1 A Quick Note Regarding Namespaces
Since all the code in the package is contained inside the ’CMF’ namespace (to keep your project’s
scripts separate from the package’s scripts), it is necessary to add a ’using’ directive, usually right
below the default Unity directives, so you can actually access functions and classes from ’Character
Movement Fundamentals’.
Luckily, this is quite easy and only requires you to add one short line of code at the very beginning of
your scripts:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using CMF; //<--This right here;
Calling this function from an external script allows you to directly add to the controller’s momentum
without causing any problems with its internal movement logic.
After that, the newly added momentum will be affected by the controller’s friction and gravity settings.
void LaunchUpwards()
{
//Add upwards momentum to controller;
controller.AddMomentum(Vector3.up * 100f);
}
For example, the code above would instantly launch the controller directly upwards, which could be
used for a ’jump pad’ effect.
The Advanced Walker Controller also comes with a function to directly set the controller’s momentum:
void ResetMomentum()
{
//Nullify controller momentum;
controller.SetMomentum(Vector3.zero);
}
This may come in handy if you need to take direct control of the controller’s momentum, such as
resetting the momentum (as seen above).
48
9.3 Rotating the Camera Toward a Target Direction or an Object in the
Scene
In many games, making the camera look at a specific object in the scene (or in a specific direction) is
a simple but efficient way to direct the player’s attention.
Other times, you might even want to give the player direct control over this camera behaviour, so they
can ”lock on” to enemies in third-person games (as seen in games like ’Dark Souls’ ).
To make implementing this kind of camera movement easier, the Camera Controller component offers
the following two functions:
public void RotateTowardPosition(Vector3 _position, float _lookSpeed)
public void RotateTowardDirection(Vector3 _direction, float _lookSpeed)
Using them in your code only requires you to call one of them from an external script and pass either
the position of an object in the scene or a direction vector you calculated, as well as a speed value (to
control how much the camera will turn in that one frame).
void Update()
{
if(Input.GetKey(Keycode.Q)
{
//Rotate camera toward ’targetObject’;
cameraController.RotateTowardPosition(targetObject.position, 45f);
}
}
In the code example above, the camera is rotated toward a target object as long as the player is holding
down the ’Q’ key on their keyboard.
However, it is important to keep in mind that the function has to be called continuously over many
frames for the camera to eventually look in the intended direction - as a result, it is best used in either
Update() or as part of a coroutine.
49
9.4 Changing Collider Dimensions at Runtime
Sometimes, you might need to resize the character at runtime. A very common example would be a
crouching system, which reduces the character’s vertical height while a button is held down.
Since the Mover component takes the character’s size into account when doing any ground detection,
simply resizing the collider directly will inevitably result in glitching and errors.
Instead, I recommend changing the collider’s dimensions via the Mover component, which comes with
the three following, built-in functions:
public void SetColliderHeight(float _newColliderHeight)
public void SetColliderThickness(float _newColliderThickness)
public void SetStepHeightRatio(float _newStepHeightRatio)
Calling any of these functions will also automatically recalibrate the Mover’s ground detection.
For example, here’s a short code example that reduces the collider’s height to ’1’ whenever the ’Control’
key is pressed and reverts its height by pressing ’Shift’:
if(Input.GetKeyDown(KeyCode.LeftControl))
{
mover.SetColliderHeight(1f);
}
if(Input.GetKeyDown(KeyCode.LeftShift))
{
mover.SetColliderHeight(2f);
}
One thing I’d just like to mention here is that resizing the collider will not change the scale of the
actual gameobject in any way. So, for a convincing ’crouching’ effect, triggering an animation to
visually match the change in height will be necessary as well.
50
10 How to Connect Animations and Audio to Character Move-
ment
The addition of animations and sounds to a character will make it feel more believable as well as add
more feedback for the player to react to. Some practical examples of this include:
• Triggering footstep sound clips whenever a character reaches a certain point in its walking ani-
mation.
• Passing a characters current movement speed to a blend tree for believable animated character
movement.
• Adding a subtle head bobbing motion to your player camera, when the character is moving.
• Activating a screen shake animation when the player character lands on the ground after a high
jump.
In order to make implementing all of this easier, Advanced Walker Controller features getter func-
tions and delegates to help you access all the necessary information you might want to pass to your
animator components and audio scripts.
Already included in the package are two scripts, Animation Control and Audio Control, which are
used by all the animated character controller prefabs as a demonstration on how to realize some of the
examples mentioned above.
Both scripts are fully documented and I recommend referring to them when programming more ad-
vanced animation and audio control scripts.
Here’s a basic code example of these values being retrieved and passed to an animator component:
using CMF;
AdvancedWalkerController controller;
Animator animator;
void Start()
{
controller = GetComponent<AdvancedWalkerController>();
animator = GetComponentInChildren<Animator>();
}
void Update () {
//Get controller velocity;
51
Vector3 _velocity = controller.GetVelocity();
10.2 Delegates
In both cases, the current velocity of the character (at the time the delegate was called) is provided
as a Vector3. You can use this vector to (for example) determine the intensity of the animation which
accompanies the event or to calculate a fitting audio volume for a sound cue.
You can use these delegates in your own code by connecting your own functions to them, like this:
using CMF;
public class MyControllerEventHandler : MonoBehaviour {
AdvancedWalkerController controller;
Animator animator;
AudioSource audioSource;
void Start()
{
controller = GetComponent<AdvancedWalkerController>();
animator = GetComponentInChildren<Animator>();
audioSource = GetComponentInChildren<AudioSource>();
52