diff --git a/web/game.html b/web/game.html index a87994a3..c2e81398 100644 --- a/web/game.html +++ b/web/game.html @@ -115,6 +115,7 @@ + @@ -124,13 +125,13 @@ + + + - - - diff --git a/web/js/controller.js b/web/js/controller.js index a61ba3b5..9026992a 100644 --- a/web/js/controller.js +++ b/web/js/controller.js @@ -175,11 +175,11 @@ input.poll().enable(); }; - // !to add debounce - const popup = (msg) => { - popupBox.html(msg); - popupBox.fadeIn().delay(0).fadeOut(); - }; + const saveGame = utils.debounce(socket.saveGame, 1000); + const loadGame = utils.debounce(socket.loadGame, 1000); + + const _popup = (message) => popupBox.html(message).fadeIn().fadeOut(); + const popup = utils.throttle(_popup, 1000); const _dpadArrowKeys = [KEY.UP, KEY.DOWN, KEY.LEFT, KEY.RIGHT]; @@ -329,10 +329,10 @@ popup('You are already in menu screen!'); break; case KEY.LOAD: - popup('Lets play to load game!'); + popup('Loading the game.'); break; case KEY.SAVE: - popup('Lets play to save game!'); + popup('Saving the game.'); break; case KEY.STATS: event.pub(STATS_TOGGLE); @@ -366,10 +366,10 @@ popup('Copy link to clipboard!'); break; case KEY.SAVE: - socket.saveGame(); + saveGame(); break; case KEY.LOAD: - socket.loadGame(); + loadGame(); break; case KEY.FULL: env.display().toggleFullscreen(gameScreen.height() !== window.innerHeight, gameScreen[0]); @@ -464,4 +464,4 @@ // initial app state setState(app.state.eden); -})($, document, event, env, gameList, input, KEY, log, room, settings, stats); +})($, document, event, env, gameList, input, KEY, log, room, settings, socket, stats, utils); diff --git a/web/js/utils.js b/web/js/utils.js new file mode 100644 index 00000000..28f557ab --- /dev/null +++ b/web/js/utils.js @@ -0,0 +1,58 @@ +/** + * Utility module. + * @version 1 + */ +const utils = (() => { + return { + /** + * A decorator that passes the call to function at maximum once per specified milliseconds. + * @param f The function to call. + * @param ms The amount of time in milliseconds to ignore the function calls. + * @returns {Function} + * @example + * const showMessage = () => { alert('00001'); } + * const showOnlyOnceASecond = debounce(showMessage, 1000); + */ + debounce: (f, ms) => { + let wait = false; + + return function () { + if (wait) return; + + f.apply(this, arguments); + wait = true; + setTimeout(() => wait = false, ms); + }; + }, + + /** + * A decorator that blocks and calls the last function until the specified amount of milliseconds. + * @param f The function to call. + * @param ms The amount of time in milliseconds to ignore the function calls. + * @returns {Function} + */ + throttle: (f, ms) => { + let lastCall; + let lastTime; + + return function () { + // could be a stack + const lastContext = this; + const lastArguments = arguments; + + if (!lastTime) { + f.apply(lastContext, lastArguments); + lastTime = Date.now() + } else { + clearTimeout(lastCall); + lastCall = setTimeout(() => { + if (Date.now() - lastTime >= ms) { + f.apply(lastContext, lastArguments); + lastTime = Date.now() + } + }, ms - (Date.now() - lastTime)) + } + } + } + } +})();