Наверх

Урок 9. Добавляем плавность. Устраняем зависимость от скорости повтора нажатия клавишы

Сейчас при управлении с клавиатуры движение фигур происходят не плавно. Это из-за того, что у меня, например, в системе стоит довольно высокая скорость повтора символов. Когда я нажимаю и держу кнопку «Вниз», события keydown начинают генерироваться быстрее, чем весь код будет отработан (в том числе и из-за тормозов нашего кода) — браузеру нужно время, чтобы отрисовать DOM. Когда он не успевает, фигура «исчезает» с поля и резко оказывается внизу, а новая фигура появляется уже на середине игрового поля.

Вторая проблема, связанная с настройками повтора символов в системе — это задержка перед началом повтора. То есть, когда я нажимаю кнопку, сначала генерируется только одно событие keydown, потом следует пауза (заданная в настройках системы), и только после паузы события начинают генерироваться быстро.

Так же это будет нечестно по отношению к некоторым пользователям. Если у пользователя низкая скорость повтора символов или большая задержка перед повтором, он может просто не успеть быстро переместить фигуру, напирмер, к краю поля. Будет обидно, наверное.

Переделаем наш код следующим образом. При нажатии на кнопку «Вниз», мы будем увеличивать скорость падения фигур, а не вызывать самостоятельно метод tick. А когда пользователь отпустит кнопку — будем возвращать значение скорости на прежний уровень.
var Tetris = {
  config: {
    // ...
    speed: 500
    }
  },
  init: function() {
    // ...
    window.onkeydown = function (event) {
      var direction = '';
      if (event.keyCode == 39) {
        direction = 'right';
      } else if(event.keyCode == 37) {
        direction = 'left';
      }
      if (direction) {
        Tetris.figure.sideStep(direction);
      } else if(event.keyCode == 40) {
        // Увеличиваем скорость до 30
        Tetris.setSpeed(30);
      }
    }
    // А когда пользователь отпустил клавишу
    window.onkeyup = function (event) {
      // Возвращаем значение скорости по умолчанию
      if(event.keyCode == 40) {
        Tetris.setSpeed();
      }
    }
  },
  tick: function() {
    console.log('tick');
    Tetris.figure.go();
    Tetris.draw();
    if (Tetris.tickHandler === undefined) {
      // Чтобы суметь изменять скорость, придется вынести функционал
      // в отдельный метод
      Tetris.setSpeed();
    }
  },
  currentSpeed: 0, // Чтобы всегда знать, какая скорость сейчас
  setSpeed: function(speed) {
    // Если скорость не указана, ставим значение из конфига
    if (!speed) var speed = Tetris.config.speed;
    // Если текущая скорость не равна требуемой
    if (speed != this.currentSpeed) {
      // Проверяем - не начало ли это игры
      if (Tetris.tickHandler !== undefined) {
        // Если нет, надо сначала очистить текущий setInterval
        clearInterval(Tetris.tickHandler);
      }
      // Ну и назначаем интервал
      Tetris.tickHandler = setInterval(function(){
        Tetris.tick();
      }, speed);
      // Записываем текущую скорость
      this.currentSpeed = speed;
    }
  }
};
Tetris.init();
Провернём то же самое и с кнопками «Влево»/«Вправо»
//...
  figure: {
    // ...
    rollback: false,
    sideStepSpeed: 0, // Текущая скорость перемещения вбок
    sideStepStart: function(direction) {
      // Если мы и так уже перемещаемся, не будем ничего делать
      if (!this.sideStepSpeed) {
        // Устанавливаем скорость движения влево или вправо
        this.sideStepSpeed = 50;
        // Указываем интервал для совершения шага
        this.sideStepHandler = setInterval(function(){
          Tetris.figure.sideStep(direction);
        }, this.sideStepSpeed);
      }
    },
    // Когда пользователь отпустит клавишу, движение вбок надо остановить
    sideStepStop: function() {
      if (this.sideStepHandler != undefined || !this.sideStepHandler) {
        this.sideStepSpeed = 0;
        clearInterval(this.sideStepHandler);
      }
    },
    // ...
  },
  init: function() {
    // ...
    window.onkeydown = function (event) {
      var direction = '';
      if (event.keyCode == 39) {
        direction = 'right';
      } else if(event.keyCode == 37) {
        direction = 'left';
      }
      if (direction) {
        // Запускаем движение в нужную сторону
        Tetris.figure.sideStepStart(direction);
      } else if(event.keyCode == 40) {
        Tetris.setSpeed(30);
      }
    }
    window.onkeyup = function (event) {
      var direction = '';
      if (event.keyCode == 39) {
        direction = 'right';
      } else if(event.keyCode == 37) {
        direction = 'left';
      }
      if (direction) {
        // Останавливаем движение
        Tetris.figure.sideStepStop();
      } else if(event.keyCode == 40) {
        Tetris.setSpeed();
      }
    }
  },
// ...

Ну вот, теперь наш код, хоть и тормозит, но зато не глючит: http://jsfiddle.net/ilyautkin/aavju3jd/19/ — браузер отрисовывает каждый шаг, и уже нет никаких «телепортаций» фигур.


2 комментария

  1. Алекс 27 декабря 2015, 14:57 # 0
    1. А где кнопка «пауза», представь, что захотелось попить чаю, а тут нужно прерывать игру.
    2. Влево и право понятно, но как вертеть фигуры?
    3. Когда произошло «game over», где кнопка «повторить заново» или «start»?
    4. joxi.ru/D2PBg1pCRjQvr3
    5. «game over» после некоторого времени снова выскакивает.
    1. Илья Уткин 27 декабря 2015, 17:12 # 0
      Игра еще не закончена)) Просто я сейчас в отпуске. Возможно, завтра опубликую новый урок.

    Авторизация

    через сервис Loginza:


    Шаблоны MODX

    1 2 Дальше »

    Объектная
    модель
    MODX