Character Controller
App: apps/character_controller/
A top-down 3D character controller demo. The character capsule is driven by CharacterController (Jolt CharacterVirtual). The controller handles ground detection, stair-stepping, and slope response automatically. Physics bodies (floor and optional obstacles) are created in code — no .blend required.
Run from root
Section titled “Run from root”% ./plume3d character_controllerControls
Section titled “Controls”| Key | Action |
|---|---|
| WASD / Arrow keys | Move |
| Shift | Run |
| Space | Jump (when grounded) |
| C | Toggle crouch |
| E | Interact (one-shot animation demo) |
| 1 | Toggle instrument out/in (custom state demo) |
| Mouse | Rotate character to face mouse position |
What it does
Section titled “What it does”- Creates a
CharacterControllerin code viaScene.createCharacterController(1.8, 0.3, 0, 2, 0). - Sets speed properties:
walkSpeed = 3,runSpeed = 7,crouchSpeed = 1.5,jumpVelocity = 6. - Creates a static box floor with
Physics.addStaticBox. - Binds the controller to a scene node (
controller.node = _charNode) so the node’s position follows the physics capsule each frame. - Reads
controller.stateand logs state transitions (Idle → Walking → Running → Jumping → Falling, etc.). - Demonstrates all
CharacterStateconstants in a top-down camera setup. - Shadow mapping enabled:
light.castsShadows = true+Graphics.setShadowMappingEnabled(true).
Key code patterns
Section titled “Key code patterns”// Create controller_controller = _scene.createCharacterController(1.8, 0.3, 0, 2, 0)_controller.walkSpeed = 3.0_controller.runSpeed = 7.0_controller.jumpVelocity = 6.0_controller.node = _charNode
// Movement input (in update)var moveX = 0var moveZ = 0if (Input.key("w")) moveZ = moveZ - 1if (Input.key("s")) moveZ = moveZ + 1if (Input.key("a")) moveX = moveX - 1if (Input.key("d")) moveX = moveX + 1_controller.running = Input.modShift()_controller.crouching = Input.key("c")_controller.setDesiredVelocity(moveX * speed, 0, moveZ * speed)
if (Input.keyJustPressed("space") && _controller.isGrounded) { _controller.jump()}
// Read stateif (_controller.state != _lastState) { Logger.info("State: %(_stateNames[_controller.state])") _lastState = _controller.state}- CharacterController —
createCharacterController,setDesiredVelocity,jump,running=,crouching=,isGrounded,state,node=, speed properties. - CharacterState —
IDLE,WALKING,RUNNING,JUMPING,FALLING,CROUCHING,INTERACTING, etc. - Physics —
addStaticBox,setGravity. - Graphics —
setLights,setShadowMappingEnabled. - Light —
castsShadows. - Scene, Node, Camera.