Выбрать главу

Спрайты для нашей игры

Клетки фона 20×20 пикселей, так как мы используем ту же шкалу, что была в DOMDisplay. Значит, сдвиг клеток лавы 20 (значение переменной scale), а сдвиг стен 0.

Мы не ждём загрузки спрайта. Вызов drawImage с незагруженной пока картинкой ничего не сделает. Поэтому, на нескольких первых кадрах игра может быть отрисована неверно, но это не так уж критично. Так как мы обновляем экран, правильная сцена появится сразу после окончания загрузки.

Наш персонаж будет использован в качестве игрока. Код его отрисовки должен выбирать правильный спрайт и направление, зависящее от текущего движения игрока. Первые восемь спрайтов содержат анимацию ходьбы. Когда игрок передвигается по полу, мы перебираем их в зависимости от свойства animationTime объекта display. Оно измеряется в секундах, а нам надо менять кадры 12 раз в секунду, поэтому мы умножаем время на 12. Когда игрок стоит, мы рисуем девятый спрайт. В прыжках, которые мы распознаём по тому, что вертикальная скорость отлична от нуля, мы рисуем десятый, самый правый спрайт.

Поскольку спрайты чуть шире ширины объекта игрока – 24 пикселя вместо 16, чтобы было место для рук и ног, метод должен подправлять координату x и ширину на заданное число (playerXOverlap).

var playerSprites = document.createElement("img");

playerSprites.src = "img/player.png";

var playerXOverlap = 4;

CanvasDisplay.prototype.drawPlayer = function(x, y, width,

                                              height) {

  var sprite = 8, player = this.level.player;

  width += playerXOverlap * 2;

  x -= playerXOverlap;

  if (player.speed.x != 0)

    this.flipPlayer = player.speed.x < 0;

  if (player.speed.y != 0)

    sprite = 9;

  else if (player.speed.x != 0)

    sprite = Math.floor(this.animationTime * 12) % 8;

  this.cx.save();

  if (this.flipPlayer)

    flipHorizontally(this.cx, x + width / 2);

  this.cx.drawImage(playerSprites,

                    sprite * width, 0, width, height,

                    x,              y, width, height);

  this.cx.restore();

};

Метод drawPlayer вызывается через drawActors, который рисует всех актёров в игре.

CanvasDisplay.prototype.drawActors = function() {

  this.level.actors.forEach(function(actor) {

    var width = actor.size.x * scale;

    var height = actor.size.y * scale;

    var x = (actor.pos.x - this.viewport.left) * scale;

    var y = (actor.pos.y - this.viewport.top) * scale;

    if (actor.type == "player") {

      this.drawPlayer(x, y, width, height);

    } else {

      var tileX = (actor.type == "coin" ? 2 : 1) * scale;

      this.cx.drawImage(otherSprites,

                        tileX, 0, width, height,

                        x,     y, width, height);

    }

  }, this);

};

При отрисовке чего-либо кроме игрока мы смотрим на его тип, чтобы найти смещение для нужного спрайта. Лава находится по смещению 20, монета – 40.

Нужно вычитать позицию окна просмотра при подсчёте позиции актёра, так как точка (0, 0) нашего холста соответствует левой верхней точке окна просмотра, а не левой верхней точке уровня. Ещё мы могли бы использовать для этой цели translate.

Следующий маленький документ подключает новый display в runGame:

<body>

  <script>

    runGame(GAME_LEVELS, CanvasDisplay);

  </script>

</body>

Выбор графического интерфейса

Когда вам нужно создавать графику в браузере, у вас есть выбор – HTML, SVG и холст. Не существует идеального подхода для всех ситуаций. У каждого варианта есть плюсы и минусы.

Чистый HTML прост. Он хорошо сочетается с текстом. SVG и холст позволяют рисовать текст, но не помогают в его расположении и не делают переносов, когда он занимает более одной линии. В HTML просто включать блоки текста.

SVG можно использовать для создания чёткой графики, которая выглядит хорошо при любом увеличении. Он сложнее обычного HTML, но и гораздо мощнее.

SVG и HTML строят структуру данных (DOM), которая представляет картинку. Это позволяет изменять элементы после того, как они нарисованы. Если вам надо периодически менять небольшую часть большой картинки в ответ на действия пользователя или в качестве анимации, на холсте это будет делать очень затратно. DOM позволяет регистрировать обработчики событий мыши на любом элементе картинки (даже на формах, нарисованных через SVG). С холстом это не пройдёт.