// 输入:IWBT 经典键位(Shift 跳 / Z 跳 / X 射击 / R 重来) const BIND = { left: ['ArrowLeft', 'KeyA'], right: ['ArrowRight', 'KeyD'], up: ['ArrowUp', 'KeyW'], down: ['ArrowDown', 'KeyS'], jump: ['ShiftLeft', 'ShiftRight', 'Space', 'KeyZ', 'KeyN'], shoot: ['KeyX', 'KeyJ', 'KeyC', 'KeyM'], suicide: ['KeyR'], // IWBT 标准:自杀并回到最近存档点 restart: ['Backspace'], // 整关从头再来(放弃所有存档点) pause: ['Escape', 'KeyP'], menu: ['KeyQ'], }; const down = new Set(); // 当前按住的原始 code const now = {}; // action 是否按下 const prev = {}; // 上一帧 const blocked = new Set(['Space', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Tab']); export const Input = { enabled: true, /** 是否按下 */ is(action) { return !!now[action]; }, /** 本帧刚按下 */ hit(action) { return !!now[action] && !prev[action]; }, /** 本帧刚松开 */ released(action) { return !now[action] && !!prev[action]; }, raw(code) { return down.has(code); }, anyHit() { for (const k in now) if (now[k] && !prev[k]) return true; return false; }, clear() { down.clear(); for (const k in now) now[k] = false; for (const k in prev) prev[k] = false; }, /** 每逻辑帧末尾调用 */ endFrame() { for (const k in now) prev[k] = now[k]; }, }; function refresh() { for (const act in BIND) { let v = false; for (const c of BIND[act]) if (down.has(c)) { v = true; break; } now[act] = Input.enabled ? v : false; } } addEventListener('keydown', e => { if (blocked.has(e.code)) e.preventDefault(); if (e.repeat) return; down.add(e.code); refresh(); }); addEventListener('keyup', e => { down.delete(e.code); refresh(); }); addEventListener('blur', () => { down.clear(); refresh(); }); // 初始化 for (const act in BIND) { now[act] = false; prev[act] = false; } export const ACTIONS = Object.keys(BIND);