@fred3d/input
v0.0.2
Published
A modern, flexible input system for games and interactive applications.
Readme
@fred3d/input
A modern, flexible input system for games and interactive applications.
Features
- Device Abstraction: Support for keyboard, mouse, gamepad, and touch input with a unified API
- Action-Based Input: Map physical inputs to logical game actions
- Context-Aware: Different input mappings for different game states (e.g., gameplay, menus)
- Remappable Controls: Built-in support for user-defined control schemes
- Vector Input: Support for 1D, 2D, and 3D input values
- Input Recording: Record and playback input sequences for testing and demos
Installation
pnpm add @fred3d/inputBasic Usage
import {
InputSystem,
KeyboardDevice,
MouseDevice,
InputActionType
} from '@fred3d/input';
// Create input system
const inputSystem = new InputSystem({
element: document.getElementById('game-canvas'),
autoLoadMappings: true
});
// Register input devices
inputSystem.registerDevice(new KeyboardDevice());
inputSystem.registerDevice(new MouseDevice());
// Register actions
const jumpAction = inputSystem.registerAction(
'gameplay.jump',
'Jump',
InputActionType.DIGITAL,
['gameplay']
);
const moveAction = inputSystem.registerAction(
'gameplay.move',
'Move',
InputActionType.VECTOR2D,
['gameplay']
);
// Create default mappings
inputSystem.registerScheme({
id: 'default',
name: 'Default Controls',
actionMappings: [
{
actionId: 'gameplay.jump',
type: InputActionType.DIGITAL,
bindings: [
{ deviceId: 'keyboard', inputId: 'Space' }
]
},
{
actionId: 'gameplay.move',
type: InputActionType.VECTOR2D,
bindings: [
{ deviceId: 'keyboard', inputId: 'KeyW', axis: 'y', scale: 1 },
{ deviceId: 'keyboard', inputId: 'KeyS', axis: 'y', scale: -1 },
{ deviceId: 'keyboard', inputId: 'KeyA', axis: 'x', scale: -1 },
{ deviceId: 'keyboard', inputId: 'KeyD', axis: 'x', scale: 1 }
]
}
]
}, true);
// Initialize the system
inputSystem.initialize();
// In your game loop
function update(deltaTime) {
// Update input system
inputSystem.update(deltaTime);
// Check for jump
if (jumpAction.justActivated()) {
player.jump();
}
// Apply movement
const moveVector = moveAction.getVector2D();
player.move(moveVector.x, moveVector.y);
}Advanced Features
Input Contexts
Input contexts allow you to have different sets of active inputs based on the current game state:
// Register contexts
inputSystem.registerContext('gameplay', 'Gameplay', 50);
inputSystem.registerContext('ui', 'UI', 100);
// Activate a context
inputSystem.activateContext('gameplay');
// Deactivate a context
inputSystem.deactivateContext('ui');Input Recording
Record and playback input sequences:
// Start recording
inputSystem.startRecording();
// Stop recording and get the recording
const recording = inputSystem.stopRecording();
// Save recording to JSON
const json = JSON.stringify(recording);
// Load and play back a recording
inputSystem.loadRecording(recording);
inputSystem.startPlayback();Examples
Check out the examples in the apps/fred3d-testing/src/examples/camera-system/InputSystemExample.ts file for a complete implementation using the input system with a first-person camera.
Recent Improvements
Platform Independence
The input system now supports platform-agnostic initialization through the new PlatformAdapter abstraction:
// Create a platform adapter for a specific environment
const domAdapter = new DOMPlatformAdapter(containerElement);
// Initialize the input system with the adapter
const inputSystem = new InputSystem({
platformAdapter: domAdapter,
autoLoadMappings: true,
});
// Or create a custom adapter for non-DOM environments
class MyCustomPlatformAdapter implements PlatformAdapter {
// Implement the adapter methods for your platform
// ...
}This allows the input system to work in non-DOM environments while maintaining compatibility with existing code.
Performance Optimization
The mapping evaluation system has been optimized for better performance with large numbers of bindings:
- Only processes mappings relevant to active contexts
- Caches device values to avoid redundant lookups
- Uses more efficient filtering and value calculation
These optimizations significantly reduce the CPU overhead when using many input bindings, particularly important for complex control schemes.
Consistent Event-Based Usage Pattern
A new example demonstrates the recommended event-based usage pattern:
// Setup event handlers using the event-based API
const moveAction = inputSystem.getAction("move");
// Handle changes to the move vector
moveAction.on("changed", (value) => {
const vector = moveAction.getVector2D();
if (vector) {
// Update character position based on the new input
updateCharacterPosition(vector.x, vector.y);
}
});
// Handle activation events
jumpAction.on("activated", () => {
// Start jump animation
startJump();
});
// Handle deactivation events
sprintAction.on("deactivated", () => {
// Stop sprinting
stopSprint();
});See src/examples/EventBasedInputExample.ts for a complete example.
Improved Validation
The input system now provides comprehensive validation for edge cases:
- Validates inputs for NaN values and incorrect ranges
- Type-specific validation for vector inputs
- Automatic fixing of common input errors with warnings
- Better error recovery with detailed logging
These validations make the system more robust against incorrect usage and unexpected input values.
License
MIT
