Appearance
Use Controls directive
The controls directive allows you to control the movement and actions of a display object using keyboard and gamepad inputs. It automatically supports both input methods when available.
Common example:
html
<script>
import { signal } from "canvasengine";
enum Direction {
Up,
Down,
Left,
Right
}
const x = signal(0);
const y = signal(0);
const speed = signal(10);
const direction = signal(Direction.Down);
const controls = signal({
down: {
repeat: true,
bind: ["down", 'bottom_right', 'bottom_left'],
keyDown() {
y.update((y) => y + speed());
direction.set(Direction.Down);
},
},
up: {
repeat: true,
bind: ['up', 'top_left', 'top_right'],
keyDown() {
y.update((y) => y - speed());
direction.set(Direction.Up);
},
},
left: {
repeat: true,
bind: "left",
keyDown() {
x.update((x) => x - speed());
direction.set(Direction.Left);
},
},
right: {
repeat: true,
bind: "right",
keyDown(_, payload) {
const power = payload?.power ?? 1;
x.update((x) => x + speed() * power);
direction.set(Direction.Right);
},
},
});
</script>
<Sprite
image="path/to/image.png"
sheet = {
{
params: {
direction
}
}
}
controls
x
y
/>Getting the Controls Instance
To access the controls directive instance and use its methods, you can use the mount() hook:
html
<script>
import { signal, mount } from "canvasengine";
// ... controls configuration ...
mount((element) => {
const controlsInstance = element.directives.controls;
if (controlsInstance) {
// Get a specific control
const leftControl = controlsInstance.getControl('left');
// Get all controls
const allControls = controlsInstance.getControls();
// Stop listening to inputs
controlsInstance.stopInputs();
// Resume listening to inputs
controlsInstance.listenInputs();
// Programmatically trigger a control
controlsInstance.applyControl('right', true); // keydown
controlsInstance.applyControl('right', false); // keyup
// Access the controls options
const options = controlsInstance.options;
}
});
</script>Available Methods
The ControlsDirective instance provides the following methods:
getControl(inputName: string)- Get a specific control by input namegetControls()- Get all bound controlsapplyControl(controlName: string, isDown?: boolean, payload?: any)- Programmatically trigger a control (payload can carry extra data, e.g. joystick power)stopInputs()- Stop listening to inputs (both keyboard and gamepad)listenInputs()- Resume listening to inputs (both keyboard and gamepad)options- Access the controls configuration objectkeyboard- Get the keyboard controls instance (if available)gamepad- Get the gamepad controls instance (if available)
Gamepad Support
The controls directive automatically detects and activates gamepad support when joypad.js is available in your project. Gamepad controls work alongside keyboard controls, allowing players to use either input method seamlessly.
Automatic Activation
Gamepad support is automatically enabled when:
joypad.jslibrary is loaded in your project- A gamepad is connected to the system
No additional configuration is required for basic gamepad functionality.
Gamepad Configuration
You can customize gamepad behavior by adding a gamepad property to your controls configuration:
html
<script>
import { signal } from "canvasengine";
const controls = signal({
up: {
repeat: true,
bind: Input.Up,
keyDown() {
// Handle up movement
}
},
// ... other controls ...
// Optional: Customize gamepad behavior
gamepad: {
enabled: true, // Enable/disable gamepad (default: true)
buttonMapping: { // Map gamepad buttons to controls (optional)
'button_0': 'action', // A button -> action
'button_1': 'back', // B button -> back
'button_9': 'back' // Start button -> back
},
axisMapping: { // Map stick directions (optional)
'top': 'up',
'bottom': 'down',
'left': 'left',
'right': 'right'
},
moveInterval: 400, // Movement repeat interval in ms (default: 400)
onConnect: () => console.log('Gamepad connected!'), // Optional callback
onDisconnect: () => console.log('Gamepad disconnected!'), // Optional callback
gamepadConnected: gamepadConnectedSignal // Optional signal to track connection status
}
});
</script>Default Button Mapping
If not specified, the following default mappings are used:
button_0→actioncontrolbutton_1→backcontrolbutton_9→backcontrol
Default Axis Mapping
Analog stick movements are mapped to direction controls:
top→upbottom→downleft→leftright→right
Using Joystick Power/Intensity
Gamepad controls automatically pass the joystick intensity (power) to the keyDown callback via the payload parameter. The power value ranges from 0.0 to 1.0, representing how far the joystick is pushed.
html
<script>
import { signal } from "canvasengine";
const x = signal(0);
const y = signal(0);
const speed = signal(10);
const controls = signal({
up: {
repeat: true,
bind: "up",
keyDown(_, payload) {
const power = payload?.power ?? 1;
y.update((y) => y - speed() * power);
}
},
down: {
repeat: true,
bind: "down",
keyDown(_, payload) {
const power = payload?.power ?? 1;
y.update((y) => y + speed() * power);
}
},
left: {
repeat: true,
bind: "left",
keyDown(_, payload) {
const power = payload?.power ?? 1;
x.update((x) => x - speed() * power);
}
},
right: {
repeat: true,
bind: "right",
keyDown(_, payload) {
const power = payload?.power ?? 1;
x.update((x) => x + speed() * power);
}
}
});
</script>The power value allows for variable-speed movement based on how far the joystick is pushed, providing more precise control similar to analog input.
Gamepad Connection Tracking
You can track gamepad connection status using a signal:
html
<script>
import { signal } from "canvasengine";
// Create a signal to track gamepad connection status
const gamepadConnected = signal(false);
const controls = signal({
// ... other controls ...
gamepad: {
enabled: true,
// Signal will be automatically updated when gamepad connects/disconnects
gamepadConnected: gamepadConnected,
onConnect() {
console.log('Gamepad connected!');
},
onDisconnect() {
console.log('Gamepad disconnected!');
}
}
});
// Use the signal in your UI
// gamepadConnected() will be true when connected, false otherwise
</script>Accessing Gamepad Instance
You can access the gamepad controls instance to customize behavior at runtime:
html
<script>
import { mount } from "canvasengine";
mount((element) => {
const controlsInstance = element.directives.controls;
if (controlsInstance && controlsInstance.gamepad) {
// Update gamepad configuration
controlsInstance.gamepad.updateGamepadConfig({
enabled: true,
buttonMapping: {
'button_0': 'jump',
'button_1': 'attack'
}
});
}
});
</script>Installing joypad.js
To enable gamepad support, install the joypad.js library:
bash
npm install joypad.jsThen import it in your project:
javascript
import 'joypad.js';The controls directive will automatically detect and use it.