Наверх

Урок 8. Реализуем управление. Реакция на нажатие клавиш в JavaScript

Думаю, пора уже дать пользователю возможность взаимодействовать с нашим тетрисом. Все-таки это игра, а не мультик.

JavaScript позволяет реагировать на нажатия клавиш. Мы будем использовать стрелки.

Для начала дадим пользователю возможность ускорить падение блоков. Тем более, что для этого нам нужно только вызвать метод tick.
var Tetris = {
  // ...
  init: function() {
    // ...
    window.onkeydown = function (event) {
      if(event.keyCode == 40) { // это код кнопки «Вниз»
        Tetris.tick();
      }
    }
  },
  // ...
};
Кроме ускорения, в тетрисе можно перемещать фигуры влево и вправо.
//...
    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) {
        Tetris.tick();
      }
    }
// ...
Теперь нужно создать метод sideStep у объекта figure
// ...
  figure: {
    // ...
    sideStep: function(direction) {
      // Менять координату нужно у каждого кирпичика в составе фигуры
      Tetris.each(this.coords, function(i,j){
        if (direction == 'right') {
          Tetris.figure.coords[i][j][1]++;
        } else {
          Tetris.figure.coords[i][j][1]--;
        }
      });
    }
// ...
Но так пользователь может «увести» фигуру за пределы поля. Нужно как-то это предотвратить. Я предлагаю сделать так. Мы меняем координаты, после этого проверяем, все ли кирпичики фигуры находятся в пределах игрового поля, и не попали ли они на занятую клетку. Если что-то не так, мы меняем координаты в обратную сторону.

Но так как координаты мы меняем внутри callback-функции, область видимости переменных не позволит нам провернуть всё гладко. Нам нужен «флаг» — свойство объекта, которое предназначено для временного хранения результатов условий. На словах сложновато. На практике это значит, что мы создаем свойство у объекта figure, называем его, к примеру, rollback, и с помощью него будем указывать — нужно ли сделать откат координат или нет:
// ...
  figure: {
    rollback: false, // пока ничего не случилось, откатывать ничего не надо
    sideStep: function(direction) {
      Tetris.each(this.coords, function(i,j){
        if (direction == 'right') {
          Tetris.figure.coords[i][j][1]++;
        } else {
          Tetris.figure.coords[i][j][1]--;
        }
      });
      // проверяем - не нарушены ли правила
      Tetris.each(this.coords, function(i,j){
        var coord = Tetris.figure.coords[i][j];
        var brick;
        // у тех кирпичиков, которые уже появились на поле (у которых
        // неотрицательная координата), проверяем - не уткнулись ли мы в стену
        if (coord[0] >= 0) {
          brick = Tetris.pitch.bricks[coord[0]][coord[1]];
          // если клеточки не существует, значит, кирпичик «вылез» за пределы поля
          if (brick == undefined) {
            // устанавливаем флаг «откатить»
            Tetris.figure.rollback = true;
          }
        }
        // даже если мы не пересекли границы поля, мы могли все равно «уткнуться»,
        // например, в кирпичик, который уже занимает клетку на поле
        if (Tetris.pitch.bricks[coord[0]] != undefined) {
          brick = Tetris.pitch.bricks[coord[0]][coord[1]];
          if (brick == 1) {
            // в таком случае также устанавливаем флаг в true
            Tetris.figure.rollback = true;
          }
        }
      });
      // Проверяем - был ли ранее установлен флаг
      if (this.rollback) {
        // Если да, то меняем координаты в обратную сторону
        Tetris.each(this.coords, function(i,j){
          if (direction == 'right') {
            Tetris.figure.coords[i][j][1]--;
          } else {
            Tetris.figure.coords[i][j][1]++;
          }
        });
        // Не забываем переключить флаг обратно, чтобы не заблокировать
        // все последующие перемещения
        this.rollback = false;
      } else {
        // если же откатываться не надо, спокойно нарисуем новую позицию фигуры
        Tetris.draw();
      }
    }
  }
  // ...
На JSFiddle наш тетрис немного подтормаживает, как вы, наверное, успели заметить. Я думаю, это из-за частой перерисовки DOM. Плюс у самого JSFiddle какие-то скрипты работают параллельно с нашими. Если вынести код в файл и просто открыть в браузере — будет пошустрее работать.

Тормоза сейчас, думаю, не страшно — на одном из последующих уроков, мы попробуем оптимизировать отрисовку. Ну и тем более — мы пока только учимся.

Я продолжу давать ссылки на JSFiddle, так как там удобно сразу смотреть и код, и результат его выполнения.

Вот, что получилось у меня на данный момент: http://jsfiddle.net/ilyautkin/aavju3jd/16/


6 комментариев

  1. Алекс 27 декабря 2015, 14:49(Комментарий был изменён) # 0
    дел
    1. Алекс 28 декабря 2015, 05:21 # 0
      Илья, у тебя косяк joxi.ru/LmG3gZNHYRZDml не хорошо как-то ))
      1. Илья Уткин 09 января 2016, 14:06 # 0
        Дам-с… Ну я не дизайнер, но что-нибудь придумаю, спасибо)
      2. Denis Efremov 27 октября 2017, 06:52 # 0
        А VueJS удалось опробовать уже, Илья?
        1. Илья Уткин 27 октября 2017, 08:03 # 0
          Неа, я о нём даже не слышал)
          1. Denis Efremov 27 октября 2017, 08:12 # 0

        Авторизация

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


        Шаблоны MODX

        1 2 Дальше »

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