California gets roads, traffic, and a car to follow
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
/** Device adapters for the renderer-independent vehicle action contract. */
|
||||
|
||||
import {
|
||||
normalizeVehicleActions,
|
||||
type VehicleActionSnapshot,
|
||||
} from "../transport/vehicleController.ts";
|
||||
|
||||
export interface GamepadButtonLike {
|
||||
pressed: boolean;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface GamepadLike {
|
||||
axes: readonly number[];
|
||||
buttons: readonly GamepadButtonLike[];
|
||||
}
|
||||
|
||||
export interface GamepadButtonState {
|
||||
assist: boolean;
|
||||
reset: boolean;
|
||||
}
|
||||
|
||||
export interface GamepadVehicleSample {
|
||||
actions: VehicleActionSnapshot;
|
||||
buttons: GamepadButtonState;
|
||||
}
|
||||
|
||||
function axis(value: number | undefined, deadzone = 0.12): number {
|
||||
if (!Number.isFinite(value)) return 0;
|
||||
const clamped = Math.max(-1, Math.min(1, value ?? 0));
|
||||
if (Math.abs(clamped) <= deadzone) return 0;
|
||||
return Math.sign(clamped) * ((Math.abs(clamped) - deadzone) / (1 - deadzone));
|
||||
}
|
||||
|
||||
function button(pad: GamepadLike, index: number): number {
|
||||
const found = pad.buttons[index];
|
||||
if (!found) return 0;
|
||||
return Math.max(0, Math.min(1, Number.isFinite(found.value) ? found.value : found.pressed ? 1 : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Standard-layout mapping: left stick steers, triggers brake/throttle, B is
|
||||
* handbrake, Y resumes assistance, and X resets. Mode/reset are rising edges.
|
||||
*/
|
||||
export function sampleStandardGamepad(
|
||||
pad: GamepadLike,
|
||||
previous: GamepadButtonState = { assist: false, reset: false },
|
||||
): GamepadVehicleSample {
|
||||
const buttons = {
|
||||
assist: button(pad, 3) > 0.5,
|
||||
reset: button(pad, 2) > 0.5,
|
||||
};
|
||||
return {
|
||||
actions: normalizeVehicleActions({
|
||||
steering: axis(pad.axes[0]),
|
||||
brake: button(pad, 6),
|
||||
throttle: button(pad, 7),
|
||||
handbrake: button(pad, 1) > 0.5,
|
||||
modeRequest: buttons.assist && !previous.assist ? "assisted" : "none",
|
||||
reset: buttons.reset && !previous.reset,
|
||||
}),
|
||||
buttons,
|
||||
};
|
||||
}
|
||||
|
||||
/** Keyboard/touch and gamepad may be used together; strongest intent wins. */
|
||||
export function mergeVehicleActions(
|
||||
primary: Partial<VehicleActionSnapshot>,
|
||||
secondary: Partial<VehicleActionSnapshot>,
|
||||
): VehicleActionSnapshot {
|
||||
const a = normalizeVehicleActions(primary);
|
||||
const b = normalizeVehicleActions(secondary);
|
||||
return normalizeVehicleActions({
|
||||
throttle: Math.max(a.throttle, b.throttle),
|
||||
brake: Math.max(a.brake, b.brake),
|
||||
steering: Math.abs(b.steering) > Math.abs(a.steering) ? b.steering : a.steering,
|
||||
handbrake: a.handbrake || b.handbrake,
|
||||
modeRequest: b.modeRequest !== "none" ? b.modeRequest : a.modeRequest,
|
||||
reset: a.reset || b.reset,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user