astrochili / defold-kinematic-walker

Kinematic character controller extension for Defold
MIT License
42 stars 5 forks source link
3d character defold kinematic

logo

Kinematic Walker

Release License Website Mastodon Twitter Telegram Buy me a coffee

๐Ÿ“ผ Also in this series:

Overview

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.

๐ŸŽฎ Play HTML5 demo.

๐Ÿ’ฌ Discuss on the forum.

Features

Install

Add link to the zip-archive of the latest version of defold-kinematic-walker to your Defold project as dependency.

Project Settings

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

Quick Start

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.

Advanced Start

Minimal setup

  1. Add a gameobject body to your character's gamoobject and attach the body.script component to it.

  2. Add the collision_standing collision object with the capsule shape to the body gameobject. Set type to Kinematic and switch locked rotation to true. The position anchor must be on the floor.

  3. Add walker.script to your character's gameobject and configure its script properties in the editor.

Crouching

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.

Camera

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.

Operator

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 })

Controls

To customize controls just change internal_control key bindings or post manual_control messages to control the movement manually.

Walker Properties

observer

The url where to send the walker events. Usually it's your character script.

spectator_mode

Activates the spectator mode during initialization. In this mode you can fly without the gravity applying.

spectator_clipping

Resolves the collisions in the spectator mode. If you disable this option, you can fly through walls.

internal_control

Enables internal control with default key bindings during initialization.

normal_speed

Normal speed of walking. Units per second.

shift_speed

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.

acceleration

How much units of velocity should be changed per second to get a greather velocity. Use your normal_speed and shift_speed as references.

deceleration

How much units of velocity should be changed per second to get a lower velocity. Use your normal_speed and shift_speed as references.

stair_height

Maximum height of the stair to climb.

stair_angle

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.

jump_power

Speed of the jump impulse in units per second. Applies immediately to y of the current velocity.

anti_bunny_time

Seconds required to stay on the ground before the next jump.

air_control

How much is possible to change the moving direction in the air.

climbing_angle

The angle of slopes which are available for climbing.

Allowed value is from 0 up to 90 degrees.

Use a value that will never be used in the level geometry to avoid persistence mistakes.

slope_speed_factor

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.

gravity

The force of gravity when there is no ground under the walker. Units per second.

The x or z gravity values also should work but has not been tested enough.

gravity_acceleration

How much units of velocity should be changed per second to reach the gravity velocity.

sensor_length

The sensor length to check the ground, ceiling and slopes. Minimum value is 0.05 because of the Bullet physics collision margin.

is_crouching_allowed

Allows to crouch. Be sure that the collision_crouching is set.

collision_standing

The url of the collision object with a standing capsule shape.

collision_crouching

The url of the collision object with a crouching capsule shape.

Is optional if you don't plan to allow crouch.

eyes_switching

Animates the eyes gameobject position up and down when standing and crouching.

eyes

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.

eyes_switch_duration

Duration of the eyes gameobject position animation when crouching and standing.

Incoming Messages

debug

Enable or disable the debug mode. It draws some debug lines to understand what happens.

msg.post(walker_url, hash 'debug', { is_enabled = true } )

spectator_mode

Enable or disable the spectator mode.

msg.post(walker_url, hash 'spectator_mode', { is_enabled = true } )

collision_mask

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_camera_rotation

Follow the camera object rotation to apply it on the walker rotation.

msg.post(walker_url, hash 'follow_camera_rotation', { camera = camera_url })

unfollow_camera_rotation

Stop to follow the camera object rotation.

msg.post(walker_url, hash 'unfollow_camera_rotation')

internal_control

Configure internal controls. Set action identifiers or disable the internal control at all.

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)

manual_control

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)

teleport

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() } )

pause

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.

Outgoing Messages

walker_moving

Sends to the observer when speed of the walker is greather than zero.

walker_standing

Sends to the observer when the walker has stood up.

walker_crouching

Sends to the observer when the walker has crouched down.

walker_jumping

Sends to the observer when the walker has jumped.

walker_falling

Sends to the observer when the walker has fell down on the ground.

The counter starts from the highest visited point in the air.

walker_trigger_enter

Forwards the trigger_response to the observer when the walker has entered a trigger.

walker_trigger_exit

Forwards the trigger_response to the observer when the walker has left a trigger.

object_post_movement

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.

ground_normal

Sends to the following camera the current ground normal.

Used by Operator to align the camera to the ground slope.

Troubleshooting

Stairs

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.

Internal geometry

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.

Fall into a gorge

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.