Предыстория


Будучи в процессе разработки своей первой html5 игры я столкнулся с рядом трудностей, для большинства из них полно готовых решений в сети, однако грамотного ответа на вопрос:«Как сделать паузу в html5 игре?» — Я не нашел. Всех кому данная тема интересна или необходима — прошу далее…

Подробнее о решениях


Все решения найденные мной в интернете так или иначе действуют по принципу while.
Примеры ниже:

Пример 1

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

async function demo() {
  console.log('Taking a break...');
  await sleep(2000);
  console.log('Two second later');
}

demo();

В данном случае мы задаем паузу на какое-то время, по его прошествии игра продолжается…
Данное решение не подойдет в большинстве случаев хотя бы потому, что мы не знаем на сколько пользователь поставит паузу, а также во время выполнения функции пользователь не сможет взаимодействовать с меню.

Пример 2

function render(){
if(canRender == false){
requestAnimationFrame(render);
}else{
//some code
requestAnimationFrame(render);
}

Постоянный перезапуск и отслеживания действий пользователя, память тратится в пустую.

Мое решение


Итак, выделив основные проблемы найденных на просторах интернета решений, я, собрав все вместе, получил следующее:

Во-первых, объявим сам объект редеринга, глобальную переменную положения объекта и переменную для паузы, а также массив, для чего он узнаем чуть позже.

let sqrt=document.getElementById('sqrt'),rend=0,pause=false,functions=[];


Теперь объявим саму функцию рендеринга, которую и нужно ставить на паузу:


function render(){
rend+=1.5;
sqrt.style = 'bottom:' + rend +'vh';
if(rend<80){
requestAnimationFrame(render);
}else{
rend=0;
return;
}
}

Далее интегрируем код для паузы в функцию(в моем примере она одна, в Вашем случае функций может быть больше)


function render(){
if(pause!=false){
//Добавляем имя функции в массив для дальнейшего запуска
functions.push("render()");
//прекращаем выполнение функции
return;
}
rend+=1.5;
sqrt.style = 'bottom:' + rend +'vh';
if(rend<80){
requestAnimationFrame(render);
}else{
rend=0;
return;
}
}

Итак, дело за малым, добавляем функцию для обработки pause/unpause



function SetPause(){
if(pause==true){
UnPause();
}else{
pause=true;
}
}

function UnPause(){
pause=false;
//проходим по всем приостановленным функциям и запускаем их снова
for(i=0;i<functions.length;i++){
eval(functions[i]);
}
//обнуляем массив для дальнейшего использования
functions =[];
}

Все готово, мы получили механизм не кушающий память за зря и дающий возможность взаимодействия со страницей во время паузы.

Данная статья была написана в целях помощи. Если кто либо видел такое решение ранее — прошу прощения. Спасибо за внимание!

Комментарии (5)


  1. Sirion
    25.04.2019 13:10
    +4

    Это очень сильно зависит от архитектуры игры. При классической архитектуре с game loop мы просто добавляем туда флаг, при наличии которого большинство игровых механик перестают обрабатываться в теле основного цикла. У вас, судя по всему, архитектура отсутствует в принципе. Также у вас ужасный стиль кода и не менее ужасное его форматирование. Не хочу показаться грубым, но, возможно, вам пока не стоило бы пытаться чему-то научить других?

    Я бы рекомендовал вам почитать, например, вот это, если владеете аглицкой мовой. Ну или просто почитать что-нибудь)


    1. qnok
      25.04.2019 16:04

      Отвечу за автора огромным спасибо за наводку на книгу. Как раз то, что я искал/хотел почитать после паттернов от четы Фрименов.


  1. kireevmp
    25.04.2019 17:19

    В целом, если переносить методологию работы игр из нативных приложений (C++/C# и так далее) на js, то именно «ресуроемкий» (Пример 2) используется повсеместно, ведь именно там находится считывание кнопок управления.

    В случае игр на js следовало бы создать какой-то стейт, который в game loop рендерился бы, а пауза просто меняла логику внутри game loop так, чтобы реакции на кнопки управления не обрабатывались, рисовалось окно паузы и так далее. Хотелось бы всё равно иметь архитектуру.

    А про оформление кода тут уже сказали, не буду повторяться.


    1. SbWereWolf
      26.04.2019 02:52

      Вполне возможно что автор просто неправильно оформил статью, в смысле блоки с кодом.
      Что автор хотел рассказать, до меня не доехало. Коменты понятней статьи :)


  1. helg1978
    26.04.2019 15:42

    Автор, установите beautify plugin.
    По теме — да, как написали выше, стейт «пауза» поможет в game loop, рендер вообще не надо трогать, на состояние должен смотреть апдейтер, или аналогичная сущность управляющая логикой игры.