Files
novafarma/old_logic/src_backup_1768938138/systems/GamepadController.js
2026-01-21 01:08:21 +01:00

179 lines
4.6 KiB
JavaScript

/**
* GAMEPAD CONTROLLER SYSTEM
* Xbox/PlayStation controller support with haptic feedback
*/
class GamepadController {
constructor(scene) {
this.scene = scene;
this.gamepad = null;
this.deadzone = 0.15;
// Button mappings (Xbox layout)
this.buttons = {
A: 0, // Interact
B: 1, // Menu
X: 2, // Gronk Vape Shield
Y: 3, // Whistle to Susi
LB: 4,
RB: 5,
LT: 6,
RT: 7,
SELECT: 8,
START: 9,
L_STICK: 10,
R_STICK: 11,
DPAD_UP: 12,
DPAD_DOWN: 13,
DPAD_LEFT: 14,
DPAD_RIGHT: 15
};
this.lastVibration = 0;
this.init();
}
init() {
// Check for gamepad connection
window.addEventListener('gamepadconnected', (e) => {
console.log('🎮 Gamepad connected:', e.gamepad.id);
this.gamepad = e.gamepad;
this.scene.events.emit('gamepad-connected', e.gamepad);
});
window.addEventListener('gamepaddisconnected', (e) => {
console.log('🎮 Gamepad disconnected');
this.gamepad = null;
this.scene.events.emit('gamepad-disconnected');
});
}
update() {
// Refresh gamepad state
const gamepads = navigator.getGamepads();
this.gamepad = gamepads[0] || gamepads[1] || gamepads[2] || gamepads[3];
if (!this.gamepad) return null;
return {
leftStick: this.getLeftStick(),
rightStick: this.getRightStick(),
buttons: this.getButtons()
};
}
getLeftStick() {
if (!this.gamepad) return { x: 0, y: 0 };
let x = this.gamepad.axes[0];
let y = this.gamepad.axes[1];
// Apply deadzone
if (Math.abs(x) < this.deadzone) x = 0;
if (Math.abs(y) < this.deadzone) y = 0;
return { x, y };
}
getRightStick() {
if (!this.gamepad) return { x: 0, y: 0 };
let x = this.gamepad.axes[2];
let y = this.gamepad.axes[3];
// Apply deadzone
if (Math.abs(x) < this.deadzone) x = 0;
if (Math.abs(y) < this.deadzone) y = 0;
return { x, y };
}
getButtons() {
if (!this.gamepad) return {};
const pressed = {};
Object.keys(this.buttons).forEach(key => {
const index = this.buttons[key];
pressed[key] = this.gamepad.buttons[index]?.pressed || false;
});
return pressed;
}
isButtonPressed(buttonName) {
if (!this.gamepad) return false;
const index = this.buttons[buttonName];
return this.gamepad.buttons[index]?.pressed || false;
}
isButtonJustPressed(buttonName) {
// Track button state changes for single press detection
if (!this.gamepad) return false;
const index = this.buttons[buttonName];
const pressed = this.gamepad.buttons[index]?.pressed || false;
if (!this.lastButtonState) this.lastButtonState = {};
const wasPressed = this.lastButtonState[buttonName] || false;
this.lastButtonState[buttonName] = pressed;
return pressed && !wasPressed;
}
/**
* HAPTIC FEEDBACK (Rumble)
* intensity: 0.0 - 1.0
* duration: milliseconds
*/
vibrate(intensity = 0.5, duration = 200) {
if (!this.gamepad || !this.gamepad.vibrationActuator) return;
// Prevent spam
const now = Date.now();
if (now - this.lastVibration < 100) return;
this.lastVibration = now;
try {
this.gamepad.vibrationActuator.playEffect('dual-rumble', {
startDelay: 0,
duration: duration,
weakMagnitude: intensity * 0.5,
strongMagnitude: intensity
});
} catch (e) {
console.warn('Vibration not supported:', e);
}
}
/**
* COLLISION RUMBLE
* Light vibration for hitting obstacles
*/
collisionRumble() {
this.vibrate(0.3, 150);
}
/**
* ZOMBIE ENCOUNTER RUMBLE
* Heavy vibration for enemy appearance
*/
zombieRumble() {
this.vibrate(0.8, 300);
}
/**
* VAPE SHIELD RUMBLE
* Medium pulse for Gronk's ability
*/
vapeShieldRumble() {
this.vibrate(0.5, 200);
}
destroy() {
window.removeEventListener('gamepadconnected', this.init);
window.removeEventListener('gamepaddisconnected', this.init);
}
}
export default GamepadController;