Kinematic Character Controller (KCC)
Introduction
The KCC is a pre-build feature for controlling characters in your Quantum game. It supports 2D and 3D worlds and comes with a ready-to-use API to easily make your characters move through landscapes, climbing steps and sliding down slopes.
It moves against physics data of both static and dynamic objects and both will be blocking and defining your characters movement. It handles moving platforms and also triggers callbacks upon collisions against other physics objects.
You always have to combine a KCC with a Quantum Transform component but it is not hard-coupled with a DynamicBody. The KCC uses it's own radius and offset and only utilizes circle (or sphere) overlap checks to calculate its movement.
This is why it is ignored by raycasts. If you need to raycast the entity it has to be done against its DynamicBody.
Notice that this page covers the usage of both 2D and 3D KCCs. Also, if you are not familiar with Quantum Physics, yet, take a look at the physics manual first.
The CharacterController Component
Add the CharacterController component to your entity in the DSL. The example here shows the usage of both the Transform and DynamicBody components, but you can choose the combination of components that better fits your entity setup.
C#
// 2D KCC
entity Character2D[4]
{
use Transform2D;
use DynamicBody;
use CharacterController2D; // this is the 2D KCC component
}
// 3D KCC
entity Character3D[4]
{
use Transform3D;
use DynamicBody3D;
use CharacterController3D; // this is the 3D KCC component
}
You must initialize the component after creating your entity: Use the default KCC config by calling the Init()
method with no parameter or use the overload method to specify the config asset you want to use.
C#
// 2D
character2D->CharacterController2D.Init();
character2D->CharacterController2D.Init(DB.FindAsset<CharacterController2DConfig>("My2DConfig"));
// 3D
character3D->CharacterController3D.Init();
character3D->CharacterController3D.Init(DB.FindAsset<CharacterController3DConfig>("My3DConfig"));
Character Controller Config
You can find the default KCC Config assets (both 2D and 3D) inside the Assets/Resources/DB/Configs
folder. Here is how the 3D KCC config looks like:

Create your own KCC config asset via the context menu under Create > Quantum > Assets > Physics > CharacterController2D/3D
.
A brief explanation into the Config fields
- Offset is used to define the KCC local position based into the entity position. It is normal to use the offset field to position the KCC into the feet of your character. Remember: the KCC is used to move your character, so it doesn't necessarily need to encapsulate all of your character's body.
- Radius defines the boundaries of the character and should encompass the character horizontal size. This is used to know if a character can move towards a direction or if there is a wall blocking the movement, a step/slope to be climbed or to be slipped.
- Max Penetration smoothes the movement when a character penetrates other physics objects. If the character passes the Max Penetration a hard fix will be applied to its position for it to snap correctly. Setting this value to zero will make corrections to be always fully and instantly applied and can make the movement unsmooth.
- Extent defines a field in radius in which collisions are detected preemptively.
- Max Contacts is used to choose how many contact points you want the KCC to compute. 1 will usually work fine and gives the best performance. If you experience jerky movement, try setting this to 2. The performance overhead is neglectable.
- Air Control toggle to
True
and the KCC is able to perform movement adjustments when it not touching the ground. - Air Control Speed defines how fast the movement is while the character is not grounded.
- Acceleration defines how fast the character accelerates.
- Base Jump Impulse defines how strong the impulse is when calling the KCC Jump method. If no specific value is passed into the Jump method this value is used.
- Max Speed caps the character horizontal speed.
- Gravity applies a gravity force to the KCC. It is split into two forces: the gravity magnitude and the gravity normalized value.
- Max Slope is the value in degrees used to know how steep slopes can be that the character can walk up and down.
- Max Slope Speed is similar to the Max Speed, but is the limiting factor when the type of movement is Slope Fall instead of Horizontal.
CharacterController API
Caveat: the API shown below focuses on the 3D API. The 2D and the 3D KCC API are very similar though.
Properties and fields:
C#
public FP MaxSpeed;
public bool Grounded { get; }
public FP CurrentSpeed { get; }
public CharacterController3DConfig Config { get; set; }
Tip: you can change the MaxSpeed value during runtime because this field is cached (after being read from the config asset). You may want to change it when performing dashes, for example.
The methods:
C#
// Initialization
public void Init(CharacterController3DConfig config = null);
// Movement
public static FPVector3 Move(void* entity, Transform3D* transform, CharacterController3D* kcc, FPVector3 velocity, DynamicScene3D scene, FP deltaTime, IKCCCallbacks callback = null);
public static CharacterController3DMovement ComputeRawMovement(void* entity, Transform3D* transform, CharacterController3D* kcc, FPVector3 velocity, DynamicScene3D scene, FP deltaTime, IKCCCallbacks callback = null);
// Jump
public void Jump(FP? impulse, bool ignoreGrounded = false);
public void Jump(bool ignoreGrounded = false);
The most important concepts is: How to use the Move
and ComputeRawMovement
methods to actually move my character?
The answer is that you must choose between one of the two methods.
The Move Method
It returns the resulting character position, considering the current position, the velocity, adding gravity, jumps, slopes, etc., all based on the config asset passed to the Init() method. This is very good for prototyping FPS/TPS/Action games which have terrains, mesh colliders and primitives. But, because it already calculates everything and returns a final FPVector3 result, it doesn't give you that much control over the movement itself. If you wish to have more control over the movement variables you should use the other movement option explained later.
It is important to mention that the Frame already comes with a wrapper for the movement API. Here is a code snippet on how to move your character:
C#
var characters = f.GetAllCharacters();
while (characters.Next())
{
var character = characters.Current;
var input = f.GetPlayerInput(character->PlayerRef);
// the optional Jump method
// as there is no value passed as parameter to the method, the jump impulse used is the one contained on the config asset
if (input->Jump.WasPressed)
{
character->CharacterController3D.Jump();
}
// the frame wrapper to get the movement vector
FPVector3 movement = f.CharacterController3D.Move((Entity*)character, input->Direction.XOY);
// if there is any movement, then apply it to the Transform component
if (movement != FPVector3.Zero)
{
character->Transform3D.Position += movement;
}
}
The Move() method doesn't apply the movement right away. If you call the Move() method and don't apply the result to your character's position it will not move.
Tip: you can also use filters to iterate through all of the entities which has the KCC component. To know more about it, check the Migration Notes and the Dev Log.
The ComputeRawMovement Method
Another way to move your character with the KCC is by using ComputeRawMovement()
. You receive information that you can use to decide how to apply the movement to your character to (implement your own custom steering for example). It is used internally by the Move() method.
The information returned by the method are:
C#
public struct CharacterController3DMovement
{
public MovementType Type;
public FPVector3 NearestNormal;
public FPVector3 AvgNormal;
public FPVector3 GroundNormal;
public FPVector3 Tangent;
public FPVector3 Correction;
public FP Penetration;
public Boolean Grounded;
public Int32 Contacts;
}
Collision Callbacks
Whenever the KCC detects intersections with colliders a callback is called:
C#
public interface IKCCCallbacks
{
bool OnCollision2D(CollisionInfo info);
bool OnCollision3D(CollisionInfo info);
void OnTrigger2D(CollisionInfo info);
void OnTrigger3D(CollisionInfo info);
}
To receive the callbacks and use its information in your own code implement the IKCCCallbacks
interface.
Important: notice that the collision callbacks returns a Boolean value? This is how you can decide if a collision should be ignored: returning false
makes the character pass through that physics object.
Besides implementing the callbacks the movement methods should also pass the IKCCCallbacks
object. Here is sample code using the collision callbacks:
C#
public unsafe class SampleSystem : SystemBase, Core.IKCCCallbacks
{
public bool OnCollision2D(CollisionInfo info)
{
// read the collision information to decide if this should or not be ignored
return true;
}
public bool OnCollision3D(CollisionInfo info)
{
// read the collision information to decide if this should or not be ignored
return true;
}
public void OnTrigger2D(CollisionInfo info)
{
}
public void OnTrigger3D(CollisionInfo info)
{
}
public override void Update(Frame f)
{
// [...]
// adding the IKCCCallbacks as the last parameter (this system, in this case)
var movement = f.CharacterController3D.Move((Entity*)character, input->Direction, this);
// [...]
}
Back to top