Add player input bindings for gamepad and keyboard

This commit is contained in:
2026-04-11 12:12:57 +02:00
parent 119ca52b75
commit 3b2e3326e8

View File

@@ -0,0 +1,128 @@
import type {
PlayerStartGamepadBinding,
PlayerStartInputBindings
} from "../entities/entity-instances";
const GAMEPAD_AXIS_DEADZONE = 0.18;
export interface PlayerStartMovementActionState {
moveForward: number;
moveBackward: number;
moveLeft: number;
moveRight: number;
}
function clampUnitInterval(value: number): number {
return Math.max(0, Math.min(1, value));
}
function readGamepadButtonStrength(button: GamepadButton | undefined): number {
if (button === undefined) {
return 0;
}
return clampUnitInterval(button.pressed ? Math.max(button.value, 1) : button.value);
}
function readPositiveAxisStrength(value: number | undefined): number {
if (value === undefined || !Number.isFinite(value) || value <= 0) {
return 0;
}
if (value <= GAMEPAD_AXIS_DEADZONE) {
return 0;
}
return clampUnitInterval(
(value - GAMEPAD_AXIS_DEADZONE) / (1 - GAMEPAD_AXIS_DEADZONE)
);
}
function readNegativeAxisStrength(value: number | undefined): number {
return readPositiveAxisStrength(
value === undefined || !Number.isFinite(value) ? value : -value
);
}
function readSingleGamepadBinding(
gamepad: Gamepad,
binding: PlayerStartGamepadBinding
): number {
switch (binding) {
case "leftStickUp":
return readNegativeAxisStrength(gamepad.axes[1]);
case "leftStickDown":
return readPositiveAxisStrength(gamepad.axes[1]);
case "leftStickLeft":
return readNegativeAxisStrength(gamepad.axes[0]);
case "leftStickRight":
return readPositiveAxisStrength(gamepad.axes[0]);
case "dpadUp":
return readGamepadButtonStrength(gamepad.buttons[12]);
case "dpadDown":
return readGamepadButtonStrength(gamepad.buttons[13]);
case "dpadLeft":
return readGamepadButtonStrength(gamepad.buttons[14]);
case "dpadRight":
return readGamepadButtonStrength(gamepad.buttons[15]);
}
}
function readGamepadBindingStrength(
gamepads: ArrayLike<Gamepad | null> | null | undefined,
binding: PlayerStartGamepadBinding
): number {
if (gamepads === undefined || gamepads === null) {
return 0;
}
let strength = 0;
for (let index = 0; index < gamepads.length; index += 1) {
const gamepad = gamepads[index];
if (gamepad === null || gamepad === undefined || gamepad.connected === false) {
continue;
}
strength = Math.max(strength, readSingleGamepadBinding(gamepad, binding));
}
return strength;
}
export function getAvailableGamepads(): ArrayLike<Gamepad | null> | undefined {
if (
typeof navigator === "undefined" ||
typeof navigator.getGamepads !== "function"
) {
return undefined;
}
return navigator.getGamepads();
}
export function resolvePlayerStartMovementActions(
pressedKeys: ReadonlySet<string>,
bindings: PlayerStartInputBindings,
gamepads: ArrayLike<Gamepad | null> | null | undefined = getAvailableGamepads()
): PlayerStartMovementActionState {
return {
moveForward: Math.max(
pressedKeys.has(bindings.keyboard.moveForward) ? 1 : 0,
readGamepadBindingStrength(gamepads, bindings.gamepad.moveForward)
),
moveBackward: Math.max(
pressedKeys.has(bindings.keyboard.moveBackward) ? 1 : 0,
readGamepadBindingStrength(gamepads, bindings.gamepad.moveBackward)
),
moveLeft: Math.max(
pressedKeys.has(bindings.keyboard.moveLeft) ? 1 : 0,
readGamepadBindingStrength(gamepads, bindings.gamepad.moveLeft)
),
moveRight: Math.max(
pressedKeys.has(bindings.keyboard.moveRight) ? 1 : 0,
readGamepadBindingStrength(gamepads, bindings.gamepad.moveRight)
)
};
}