Compare commits

..

2 commits

6 changed files with 103 additions and 14 deletions

View file

@ -1,7 +1,7 @@
{ {
"touchscreen": { "touchscreen": {
"enabled": true, "enabled": true,
"mode": "swipe", "mode": "crosspad",
"deadzone": 50, "deadzone": 50,
"buffer": false "buffer": false
}, },

View file

@ -19,6 +19,7 @@
<main> <main>
<nav></nav> <nav></nav>
<canvas class="hidden"></canvas> <canvas class="hidden"></canvas>
<div id="hud" class="hidden"></div>
</main> </main>
<footer> <footer>
<img src="assets/icon32.png"> <img src="assets/icon32.png">

View file

@ -1,6 +1,7 @@
let currentInputs={}; let currentInputs={};
let handlers=[]; let handlers=[];
let config; let config;
let hud;
const toAngleMagnitude=(x, y) => { const toAngleMagnitude=(x, y) => {
return { return {
@ -25,6 +26,26 @@ const handleAngleMagnitude=(x, y, threshold=0, fn=null, clearBuffer=false) => {
} }
const handleCrosspad=(() => { const handleCrosspad=(() => {
const ns='http://www.w3.org/2000/svg';
const cross=document.createElementNS(ns, 'svg');
cross.classList.add('crosspadOverlay');
cross.setAttribute('width', 1000);
cross.setAttribute('height', 1000);
let dr=document.createElementNS(ns, 'line');
dr.setAttribute('x1', 0);
dr.setAttribute('y1', 0);
dr.setAttribute('x2', 1000);
dr.setAttribute('y2', 1000);
dr.setAttribute('stroke', 'black');
cross.appendChild(dr);
let dl=document.createElementNS(ns, 'line');
dl.setAttribute('x1', 1000);
dl.setAttribute('y1', 0);
dl.setAttribute('x2', 0);
dl.setAttribute('y2', 1000);
dl.setAttribute('stroke', 'black');
cross.appendChild(dl);
const fn=e => const fn=e =>
handleAngleMagnitude( handleAngleMagnitude(
e.touches[0].clientX-window.innerWidth/2, e.touches[0].clientX-window.innerWidth/2,
@ -35,7 +56,9 @@ const handleCrosspad=(() => {
); );
return { return {
touchstart: fn, touchstart: fn,
touchmove: fn touchmove: fn,
init: () => hud.appendChild(cross),
fini: () => hud.removeChild(cross)
}; };
})(); })();
@ -112,22 +135,29 @@ const handleGamepads={
const handleEvent=(type, evt) => { const handleEvent=(type, evt) => {
for(let handler of handlers) { for(let handler of handlers) {
console.log(type, handler);
let fn=handler[type]; let fn=handler[type];
if(fn) fn(evt); if(fn) fn(evt);
} }
}; };
const enableHandler=handler => { const enableHandler=handler => {
if(!handlers.includes(handler)) handlers.push(handler); if(!handlers.includes(handler)) {
handlers.push(handler);
if(handler.init) handler.init();
}
}; };
const disableHandler=handler => { const disableHandler=handler => {
let idx=handlers.indexOf(handler); let idx=handlers.indexOf(handler);
if(idx!=-1) handlers.splice(idx, 1); if(idx!=-1) {
handlers.splice(idx, 1);
if(handler.fini) handler.fini();
}
}; };
const updateConfig=cfg => const updateConfig=cfg =>
config=cfg; config=cfg;
const setHud=elem =>
hud=elem;
const clear=() => const clear=() =>
Object Object
@ -150,5 +180,5 @@ return module.exports={
touchscreenJoystick: handleJoystick, touchscreenJoystick: handleJoystick,
touchscreenSwipe: handleSwipe touchscreenSwipe: handleSwipe
}, },
updateConfig updateConfig, setHud
}; };

View file

@ -15,6 +15,7 @@
const main=document.querySelector('main'); const main=document.querySelector('main');
const nav=main.querySelector('nav'); const nav=main.querySelector('nav');
const canvas=main.querySelector('canvas'); const canvas=main.querySelector('canvas');
const hud=main.querySelector('#hud');
// load config // load config
const config=assets.get('config'); //TODO use an actual config module const config=assets.get('config'); //TODO use an actual config module
@ -26,7 +27,7 @@
let currentGame=null; let currentGame=null;
// forward-declare functions // forward-declare functions
let resizeCanvas, getLevel, startGame, handleWin, handleDeath, menu, help; let resizeCanvas, getLevel, startGame, handleWin, handleDeath, menu, help, restart;
// handle window resize and fullscreen // handle window resize and fullscreen
resizeCanvas=() => { resizeCanvas=() => {
@ -119,6 +120,7 @@
// setup the DOM // setup the DOM
nav.classList.add('hidden'); nav.classList.add('hidden');
canvas.classList.remove('hidden'); canvas.classList.remove('hidden');
hud.classList.remove('hidden');
// push some userdata to the snake // push some userdata to the snake
snek.userdata={ snek.userdata={
@ -142,12 +144,13 @@
// setup the DOM // setup the DOM
nav.classList.remove('hidden'); nav.classList.remove('hidden');
canvas.classList.add('hidden'); canvas.classList.add('hidden');
hud.classList.add('hidden');
}; };
// display the win popup // display the win popup
handleWin=async snek => { handleWin=async snek => {
// get userdata back // hide the HUD
const {category, levelId, filename}=snek.userdata; hud.classList.add('hidden');
// create and configure popup // create and configure popup
let popup=new Popup("Finished!"); let popup=new Popup("Finished!");
@ -171,10 +174,11 @@
// act on it // act on it
if(result=='retry') { if(result=='retry') {
startGame(category, levelId, filename); restart();
} else if(result=='menu') { } else if(result=='menu') {
location.hash='menu'; location.hash='menu';
} else if(result=='next') { } else if(result=='next') {
const {category, levelId}=snek.userdata;
let nextId=(+levelId)+1; let nextId=(+levelId)+1;
let {levelString}=getLevel(category, nextId) let {levelString}=getLevel(category, nextId)
location.hash=levelString; location.hash=levelString;
@ -183,8 +187,8 @@
// display the death popup // display the death popup
handleDeath=async snek => { handleDeath=async snek => {
// get userdata back // hide the HUD
const {category, levelId, filename}=snek.userdata; hud.classList.add('hidden');
// create and configure popup // create and configure popup
let popup=new Popup("Finished!"); let popup=new Popup("Finished!");
@ -204,12 +208,29 @@
// act on it // act on it
if(result=='retry') { if(result=='retry') {
startGame(category, levelId, filename); restart();
} else if(result=='menu') { } else if(result=='menu') {
location.hash='menu'; location.hash='menu';
} }
}; };
// quick restart
restart=() => {
if(currentGame && currentGame.playing) {
const {category, levelId, filename}=currentGame.userdata;
startGame(category, levelId, filename);
}
}
window.addEventListener('keydown', e => {
if(e.key=='r') restart();
});
(() => {
let restartbtn=hud.appendChild(document.createElement('span'));
restartbtn.classList.add('restart');
restartbtn.addEventListener('click', restart);
restartbtn.addEventListener('touchend', restart);
})();
// handle page navigation // handle page navigation
window.addEventListener('hashchange', () => { window.addEventListener('hashchange', () => {
const hash=location.hash.substr(1); const hash=location.hash.substr(1);
@ -222,6 +243,7 @@
}); });
// enable input methods according to config // enable input methods according to config
input.setHud(hud);
if(config.keyboard.enabled) { if(config.keyboard.enabled) {
input.enableHandler(input.availableHandlers.keyboard); input.enableHandler(input.availableHandlers.keyboard);
} }

34
src/less/hud.less Normal file
View file

@ -0,0 +1,34 @@
#hud {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
pointer-events: none;
& > * {
position: fixed;
pointer-events: auto;
}
.restart {
top: 0;
right: 0;
&::before {
content: '⟳';
font-size: 3rem;
opacity: .5;
color: @accentfg;
}
}
.crosspadOverlay {
pointer-events: none;
top: 50vh;
left: 50vw;
transform: translate(-50%, -50%);
opacity: .5;
}
}

View file

@ -105,3 +105,5 @@ p {
// setup the popups // setup the popups
@import 'popup'; @import 'popup';
// setup the hud
@import 'hud';