HTML5 Phaser ECMAScript 6

Часть 11: Обрезка спраита sprite.crop и tween анимация прогресса (шаг 2)

Настоятельно рекомендую прочитать 10 часть, где я подробно разобрал сложности сделать prefeb на базе sprite и обнаружил, что group как нельзя лучше подходит по эти цели.

После создания группы, расположение спрайтов в нужной последовательности на заведомо известных координатах задача тривиальная. Главное тут учесть вот такой момент. После добавления в группу новых спраитов, размер (ширина и высота) группы будет меняться. Запомните, размер группы на момент добавления нового спраита, равен размеру минимального прямоугольника в который можно уместить все спраиты группы. Правда есть одна странность, константы centerX и centerY для группы считаются относительно точки 0, 0 а не относительно x, y значений группы. По этому новые спраиты позиционируете относительно друг друга, а не относительно группы. Как например в моем случае текст позиционируется относительно спраита кружка, а сам кружок относительно спраита фона. Если так не делать, то при перемещении группы размером 20х30 из координат 0, 0 в координаты 40, 50 центр будет не в точке 15, 20, а в точке 40+20/2=30, 30+50/2=40

Сложности начались когда надо было рисовать прогресс, так как он у меня снизу вверх. Я представления не имел, как вырезать кусок изображения. Подумав немного, я вспомнил, что Phaser умеет рисовать прогресс (сцена Preload) и начал анализировать исходники. Я нашел, что Phaser создает прямоугольник для метода sprite.crop() который и обрезает спраит.

генерация изображения прогресса

Сделав прогресс сверху вниз, я понял, что снизу вверх будет также просто. Достаточно было установить y координату у прямоугольника crop равной высоте всего спраита минус высота прогресса. Но тут сказалась моя усталость и после удачного выделения сектора, я не мог понять, почему он находиться вверху а не внизу, ведь я задал правильное значение y. Я не обратил внимание, что перемещая прямоугольник crop, я забыл переместить сам спраит. Для этого достаточно было установить значение y координаты равной высоте спраита, а после поднять anchor.setTo(0, 1).

позиционирование сектора которое сбило меня с толку

Последняя проблема возникла с позиционированием текста. Перепробовал много вариантов, пока не понял, что проблема в самом шрифте. Числа 1, 2, 3 находятся на линии baseline, а так как в шрифте есть буквы которые пишутся ниже baseline такие как g, y, j и т.д. то при выводе чисел, под baseline есть пространство, которое мы не видим и которое сбивает вертикальное позиционирование на несколько точек вверх центра.

Задачу можно решить просканировав изображение по пиксельно и найти реальную высоту текста… но это медленно. Намного легче воспользоваться bitmapFont-ом. Эта технология позволяет превратить шрифт в фото и решить проблему с вертикальным позиционированием. А также бонусом мы получаем возможность использовать в игре шрифты любого языка или дизайна, вне зависимости как их отображает конкретная система (где запущена игра). В следующем посте мы разберем Game.js сцену и попробуем создать bitmapFont своими руками.

Привожу содержимое Skill.js файла:

export default class Skill extends Phaser.Group {
  constructor(game, x, y, background_sprite, progress_sprite, level_sprite, icon_sprite) {
    super(game);

    this.x = x;
    this.y = y;

    this.background_sprite = this.create(0, 0, background_sprite);

    var progress = this.create(0, 0, progress_sprite);
    progress.y = progress.height;
    progress.anchor.setTo(0, 1);
    this.progress = {
      sprite: progress,
      width: progress.width,
      height: progress.height,
      rect: new Phaser.Rectangle(0, progress.height, progress.width, progress.height),
      max_value: 16,
      value: 1
    }
    this.progress.sprite.crop(this.progress.rect);

    this.level = this.create(this.background_sprite.centerX, this.background_sprite.height, level_sprite);
    this.level.anchor.setTo(0.5);

    var style = {font: 'bold 20px Arial', align: 'center', fill: '#ffffff', /*backgroundColor: "#ffff00"*/};
    this.number = new Phaser.Text(game, this.level.centerX, this.level.centerY, this.progress.value.toString(), style);
    this.number.anchor.setTo(0.5);
    this.add(this.number);

    this.icon = this.create(this.background_sprite.centerX, this.background_sprite.centerY, icon_sprite);
    this.icon.anchor.setTo(0.5);
  }

  update() {
    this.progress.sprite.updateCrop();
  }

  set_progress(value) {
    if (value <= this.progress.max_value) {
      this.progress.value = value;
      this.number.text = this.progress.value.toString();

      var new_y = this.progress.height - Math.floor((this.progress.height/this.progress.max_value)*this.progress.value);
      if (this.tween) this.tween.stop();
      this.tween = this.game.add.tween(this.progress.rect).to({y: new_y}, 2000, Phaser.Easing.Bounce.Out, true);
    }
  }
}

Мы забыли обсудить принцип работы tween анимации. Но если вы знаете как работает анимация в jQuery, то достаточно сказать, что tween построена по тому же алгоритму, но имеет ряд дополнительных полезных плюшек. Предлагаю разобрать tween когда мы будем оживлять кнопки меню в нижней части сцены.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *