📼 Also in this series:
- 🎥 Operator
- 🏗️ TrenchFold
- 🎄 Illumination
- 🚧 Blockout Textures
This is a tweakable kinematic character controller suitable for 3D games made with Defold. When you wouldn't like to use a dynamic body and prefer to have more control over the movement.
Although not all the collision cases are handled perfect at the moment, you can avoid problems by providing valid and smooth collision geometry of your level. The geometry in the demo is not smooth exclusively for stress testing purposes.
Ready to use with 🎥 Operator or you own camera controller.
- Collision resolving with level geometry.
- Walking and running.
- Jumping and crouching.
- Climbing slopes and curbs.
- Smooth acceleration and deceleration.
- Internal control with key bindings.
- External manual control with messages.
- Spectator mode.
- Request by adding an issue or contribute.
Add link to the zip-archive of the latest version of defold-kinematic-walker to your Defold project as dependency.
The following settings in the game.project
file are recommended for the walker to work correctly:
[physics]
type = 3D
use_fixed_timestep = 1
max_fixed_timesteps = 1
[display]
update_frequency = 60
[engine]
fixed_update_frequency = 60
Add the dummy.collection
collection to your scene. It's already composed collection of the player with capsule collision objects and models to test hypotheses and adjust things for your needs.
Make sure you set up the camera correctly or connect Operator. The dummy.script
can integrate it automatically, so just fill in the url in the operator
property.
-
Add a gameobject
body
to your character's gamoobject and attach thebody.script
component to it. -
Add the
collision_standing
collision object with the capsule shape to thebody
gameobject. Set type toKinematic
and switch locked rotation totrue
. The position anchor must be on the floor. -
Add
walker.script
to your character's gameobject and configure its script properties in the editor.
To allow crouching add the collision_crouching
collision object with the capsule shape with the same collision properties as the collision_standing
but with a lower height. Then set the is_crouching_allowed
to true
.
To follow your camera gameobject rotation:
msg.post(walker_url, hash 'follow_camera_rotation', { camera = camera_url })
To automatically move the camera up and down when standing and crouching add an empty gameobject eyes
in the walker gameobject and use it to attach your camera. Then set the eyes_switching
to true
.
To use Operator as the camera controller:
msg.post(operator_url, hash 'follow_point', { object = eyes_url })
msg.post(walker_url, hash 'follow_camera_rotation', { camera = operator_url })
To customize controls just change internal_control
key bindings or post manual_control
messages to control the movement manually.
The url
where to send the walker events. Usually it's your character script.
Activates the spectator mode during initialization. In this mode you can fly without the gravity applying.
Resolves the collisions in the spectator mode. If you disable this option, you can fly through walls.
Enables internal control with default key bindings during initialization.
Normal speed of walking. Units per second.
Alternative speed of walking is activated with the input.shift
. Units per second.
If you want to run by default and walk only with the shift input set this property less than normal_speed
.
How much units of velocity should be changed per second to get a greather velocity. Use your normal_speed
and shift_speed
as references.
10
- if thenormal_speed
is5
, then the time required to accelerate from the zero velocity to the walking velocity will be0.5
seconds.0
- don't use if you want to move the walker.
How much units of velocity should be changed per second to get a lower velocity. Use your normal_speed
and shift_speed
as references.
20
- if thenormal_speed
is5
, then the time required to decelerate from the walking velocity to the zero velocity will be0.25
seconds.0
- don't use otherwise you will never stop the walker.
Maximum height of the stair to climb.
0
- ignore any stairs.0.3
- automatically moves up on surfaces no higher than0.3
.
Maximum deviation angle in degrees of the stair surface to climb.
Allowed values are from 0
to 30
degrees, because after 30
it's too unstable.
0
- only horizontal stairs will be handled.15
- stairs with angle from-15
and up to15
degrees will be handled.
Speed of the jump impulse in units per second. Applies immediately to y
of the current velocity.
10
- jump immediately up with10
units per second speed.
Seconds required to stay on the ground before the next jump.
0.2
- a little delay before the next jump.
How much is possible to change the moving direction in the air.
0
- where it jumped, that's where it fall.0.3
- a little control over the direction of the fall.1
- a full control of horizontal moving in the air.
The angle of slopes which are available for climbing.
Allowed value is from 0
up to 90
degrees.
0
- any slope will be as a wall.46
- allow to climb slopes up to46
degrees.
Use a value that will never be used in the level geometry to avoid persistence mistakes.
How much the angle of the slope affects the walker speed.
The calculation comes from the fact that a 45 degree slope is -50% speed on the uphill and +50% speed on the downhill. Then this effect is multiplied by this factor.
0
- the speed always is the same.0.5
- half of the effect applies.
The force of gravity when there is no ground under the walker. Units per second.
vmath.vector3(0, -8, 0)
- a falling gravity with 8 units per second speed.
The x
or z
gravity values also should work but has not been tested enough.
How much units of velocity should be changed per second to reach the gravity
velocity.
3
- if thegravity.y
is-6
, then the time required to accelerate from the zero velocity to the gravity velocity is2
seconds.
The sensor length to check the ground, ceiling and slopes. Minimum value is 0.05
because of the Bullet physics collision margin.
Allows to crouch. Be sure that the collision_crouching
is set.
The url
of the collision object with a standing capsule shape.
The url
of the collision object with a crouching capsule shape.
Is optional if you don't plan to allow crouch.
Animates the eyes
gameobject position up and down when standing and crouching.
The url
of a gameobject for the camera attachment. Its position will be animated when the eyes_switching
is true
.
Is optional if you don't plan to switch the camera position.
Duration of the eyes
gameobject position animation when crouching and standing.
Enable or disable the debug mode. It draws some debug lines to understand what happens.
msg.post(walker_url, hash 'debug', { is_enabled = true } )
Enable or disable the spectator mode.
msg.post(walker_url, hash 'spectator_mode', { is_enabled = true } )
Unfortunately, there is no way to get your collision object mask automatically in Defold at the moment. So if you use a mask other than default
in collision_standing
and collision_crouching
, please provide it with this message during initialization.
msg.post(walker_url, hash 'collision_mask', { hash 'default', hash 'solid' } )
Follow the camera object rotation to apply it on the walker rotation.
msg.post(walker_url, hash 'follow_camera_rotation', { camera = camera_url })
Stop to follow the camera object rotation.
msg.post(walker_url, hash 'unfollow_camera_rotation')
Configure internal controls. Set action identifiers or disable the internal control at all.
is_enabled
- enanbles or disables internal control.bindings.forward
- forward moving action id.bindings.backward
- backward moving action id.bindings.left
- left strafing action id.bindings.right
- right strafing action id.bindings.jump
- jumping action id.bindings.crouch
- crouching action id.bindings.shift
- alternative walking speed action id.
local bindings = {
forward = hash 'key_w',
backward = hash 'key_s',
left = hash 'key_a',
right = hash 'key_d',
jump = hash 'key_space',
crouch = hash 'key_c',
shift = hash 'key_lshift'
}
local message = {
is_enabled = true,
bindings = bindings
}
msg.post(walker_url, hash 'internal_control', message)
Manually control movement of the walker. The structure is similar with bindings but all the values must be bool
or nil
.
local input = {
forward = true,
left = true,
crouch = true,
}
msg.post(walker_url, hash 'manual_control', input)
Move the walker instantly to another position. Since go.set_position()
is used inside the walker script for its own purposes, use this message to change the position.
msg.post(walker_url, hash 'teleport', { position = vmath.vector3() } )
Enables or disables the update and collision resolving functions.
msg.post(walker_url, hash 'pause', { is_paused = true })
Useful in HTML5 builds when the web browser tab loses the focus, check the example.
direction
- a normalized direction of the movement.speed
- speed in the units per second.is_grounded
- standing on the ground or not.
Sends to the observer
when speed of the walker is greather than zero.
Sends to the observer
when the walker has stood up.
Sends to the observer
when the walker has crouched down.
Sends to the observer
when the walker has jumped.
height
- the height of the fall.
Sends to the observer
when the walker has fell down on the ground.
The counter starts from the highest visited point in the air.
Forwards the trigger_response
to the observer
when the walker has entered a trigger.
Forwards the trigger_response
to the observer
when the walker has left a trigger.
position
- the actual position of the walker.correction
- the last position correction.
Sends to the observer
and the following camera
post movement corrections after collision resolving in the on_message
function.
Used by Operator to update the camera position without lags.
normal
- the ground normal or nil.
Sends to the following camera
the current ground normal.
Used by Operator to align the camera to the ground slope.
The current handling of stairs is more suitable for climbing on curbs. Don't use the stairs as is, better to use a slope collision object.
To avoid stucking along the objects, try to remove any internal unused collision geometry.
Using of planes as collision objects along the wall is preferable to boxes to avoid collisions with the joints of these boxes. Keep the collision geometry as simple as possible.
Place a horizontal hidden collision object at the bottom of the gorge so that there is something to stand on, otherwise the walker may get stuck.