Skip to content

Instantly share code, notes, and snippets.

@EncodeTheCode
Created February 18, 2026 08:57
Show Gist options
  • Select an option

  • Save EncodeTheCode/6c80cd0d06971c5c470ead2366c5aad3 to your computer and use it in GitHub Desktop.

Select an option

Save EncodeTheCode/6c80cd0d06971c5c470ead2366c5aad3 to your computer and use it in GitHub Desktop.
// ===============================
// RAW XBOX CONTROLLER (Hardware)
// ===============================
class XboxController {
constructor(index = 0, deadzone = 0.15) {
this.index = index;
this.deadzone = deadzone;
// ---- RAW BUTTON STATES ----
this.A = this.A_Pressed = this.A_Released = 0;
this.B = this.B_Pressed = this.B_Released = 0;
this.X = this.X_Pressed = this.X_Released = 0;
this.Y = this.Y_Pressed = this.Y_Released = 0;
this.LB = this.LB_Pressed = this.LB_Released = 0;
this.RB = this.RB_Pressed = this.RB_Released = 0;
this.View = this.View_Pressed = this.View_Released = 0;
this.Menu = this.Menu_Pressed = this.Menu_Released = 0;
this.LS = this.LS_Pressed = this.LS_Released = 0;
this.RS = this.RS_Pressed = this.RS_Released = 0;
this.DPadUp = this.DPadUp_Pressed = this.DPadUp_Released = 0;
this.DPadDown = this.DPadDown_Pressed = this.DPadDown_Released = 0;
this.DPadLeft = this.DPadLeft_Pressed = this.DPadLeft_Released = 0;
this.DPadRight = this.DPadRight_Pressed = this.DPadRight_Released = 0;
// Analog triggers
this.LT = 0;
this.RT = 0;
// Sticks
this.leftX = 0;
this.leftY = 0;
this.rightX = 0;
this.rightY = 0;
// Previous states
this._prev = new Uint8Array(16);
}
update() {
const gp = navigator.getGamepads()[this.index];
if (!gp) return;
const b = gp.buttons;
const a = gp.axes;
const p = this._prev;
// Digital buttons
this._btn(0, b[0].pressed, "A");
this._btn(1, b[1].pressed, "B");
this._btn(2, b[2].pressed, "X");
this._btn(3, b[3].pressed, "Y");
this._btn(4, b[4].pressed, "LB");
this._btn(5, b[5].pressed, "RB");
this._btn(8, b[8].pressed, "View");
this._btn(9, b[9].pressed, "Menu");
this._btn(10, b[10].pressed, "LS");
this._btn(11, b[11].pressed, "RS");
this._btn(12, b[12].pressed, "DPadUp");
this._btn(13, b[13].pressed, "DPadDown");
this._btn(14, b[14].pressed, "DPadLeft");
this._btn(15, b[15].pressed, "DPadRight");
// Analog triggers
this.LT = b[6].value;
this.RT = b[7].value;
// Sticks with deadzone
const dz = this.deadzone;
let lx = a[0], ly = a[1], rx = a[2], ry = a[3];
this.leftX = (lx > dz || lx < -dz) ? lx : 0;
this.leftY = (ly > dz || ly < -dz) ? ly : 0;
this.rightX = (rx > dz || rx < -dz) ? rx : 0;
this.rightY = (ry > dz || ry < -dz) ? ry : 0;
}
_btn(i, pressed, name) {
const curr = pressed ? 1 : 0;
const prev = this._prev[i];
this[name] = curr;
this[name + "_Pressed"] = curr & (prev ^ 1);
this[name + "_Released"] = (curr ^ 1) & prev;
this._prev[i] = curr;
}
}
// ===============================
// PLAYER ACTION MAPPING LAYER
// ===============================
class PlayerInput {
constructor(controller) {
this.controller = controller;
// ---- GAME ACTIONS ----
this.jump = 0;
this.jump_Pressed = 0;
this.jump_Released = 0;
this.shoot = 0;
this.reload = 0;
this.pause = 0;
this.moveX = 0;
this.moveY = 0;
this.lookX = 0;
this.lookY = 0;
}
update() {
const c = this.controller;
// Map hardware → gameplay
this.jump = c.A;
this.jump_Pressed = c.A_Pressed;
this.jump_Released = c.A_Released;
this.shoot = c.RT > 0.5;
this.reload = c.X;
this.pause = c.Menu_Pressed;
this.moveX = c.leftX;
this.moveY = c.leftY;
this.lookX = c.rightX;
this.lookY = c.rightY;
}
}
// ===============================
// EXAMPLE GAME LOOP
// ===============================
const controller = new XboxController(0);
const input = new PlayerInput(controller);
// Example mock objects
const player = {
x: 0,
y: 0,
speed: 5,
jump() { console.log("Jump"); },
fire() { console.log("Shoot"); }
};
const camera = {
look(x, y) {
console.log("Look:", x.toFixed(2), y.toFixed(2));
}
};
const game = {
togglePause() {
console.log("Paused");
}
};
function gameLoop() {
controller.update();
input.update();
if (input.jump_Pressed) player.jump();
if (input.shoot) player.fire();
if (input.pause) game.togglePause();
player.x += input.moveX * player.speed;
player.y += input.moveY * player.speed;
camera.look(input.lookX, input.lookY);
requestAnimationFrame(gameLoop);
}
gameLoop();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment