Snek/src/js/input.js

153 lines
3.1 KiB
JavaScript
Raw Normal View History

let currentInputs={};
let handlers=[];
let config;
const toAngleMagnitude=(x, y) => {
return {
angle: ((Math.atan2(x, y)+2*Math.PI)%(2*Math.PI))/Math.PI,
magnitude: Math.hypot(x, y)
};
};
const handleAngleMagnitude=(x, y, threshold=0, fn=null, clearBuffer=false) => {
const {angle, magnitude}=toAngleMagnitude(x, y);
if(magnitude>threshold) {
if(angle>.25 && angle <.75) inputs.right=true;
else if(angle>.75 && angle<1.25) inputs.up=true;
else if(angle>1.25 && angle<1.75) inputs.left=true;
else inputs.down=true;
if(clearBuffer) inputs.clearBuffer=true;
if(fn) fn(angle, magnitude);
}
}
const handleCrosspad=(() => {
const fn=e =>
handleAngleMagnitude(
e.touches[0].clientX-window.innerWidth/2,
e.touches[0].clientY-window.innerHeight/2,
0,
null,
!config.touchscreen.buffer
);
return {
touchstart: fn,
touchmove: fn
};
})();
const handleKeyboard={
keydown: e => {
let inputs=currentInputs;
if(e.key=='ArrowUp') inputs.up=true;
else if(e.key=='ArrowDown') inputs.down=true;
else if(e.key=='ArrowLeft') inputs.left=true;
else if(e.key=='ArrowRight') inputs.right=true;
if(!config.keyboard.buffer) inputs.clearBuffer=true;
}
};
const handleJoystick=(() => {
let center={
x: 0,
y: 0
};
return {
touchstart: e => {
center.x=e.touches[0].clientX;
center.y=e.touches[0].clientY;
},
touchmove: e =>
handleAngleMagnitude(
e.touches[0].clientX-center.x,
e.touches[0].clientY-center.y,
config.touchscreen.deadzone,
null,
!config.touchscreen.buffer
)
}
});
const handleSwipe=(() => {
let center={
x: 0,
y: 0
};
let resetCenter=e => {
center.x=e.touches[0].clientX;
center.y=e.touches[0].clientY;
};
return {
touchstart: resetCenter,
touchmove: e =>
handleAngleMagnitude(
e.touches[0].clientX-center.x,
e.touches[0].clientY-center.y,
config.touchscreen.deadzone,
() => resetCenter(e),
!config.touchscreen.buffer
)
}
});
const handleGamepads={
frame: () => {
const gp=navigator.getGamepads()[0];
let inputs=currentInputs;
if(!gp || !gp.axes) return;
handleAngleMagnitude(
gp.axes[0],
gp.axes[1],
config.gamepad.deadzone,
null,
!config.gamepad.buffer
);
}
};
const handleEvent=(type, evt) => {
for(let handler of handlers) {
let fn=handler[type];
if(fn) fn(evt);
}
};
const enableHandler=handler => {
if(!handlers.includes(handler)) handlers.push(handler);
};
const disableHandler=handler => {
let idx=handlers.indexOf(handler);
if(idx!=-1) handlers.splice(idx, 1);
};
const updateConfig=cfg =>
config=cfg;
const clear=() =>
Object
.keys(currentInputs)
.forEach(key => delete currentInputs[key]);
for(let type of ['keydown', 'touchstart', 'touchmove']) {
window.addEventListener(type, handleEvent.bind(null, type));
}
return module.exports={
inputs: currentInputs,
clear,
enableHandler, disableHandler,
framefn: handleEvent.bind(null, 'frame'),
availableHandlers: {
keyboard: handleKeyboard,
gamepad: handleGamepads,
touchscreenCrosspad: handleCrosspad,
touchscreenJoystick: handleJoystick,
touchscreenSwipe: handleSwipe
},
updateConfig
};