HTML5 Phaser ECMAScript 6

Часть 18: Прокрутка с инерцией и резиновым стартом

Для реализации прокрутки с инерцией надо было подсчитать скорость swipe жеста. А для этого нужно расстояние и время. Расстояние это дельта, а вот продолжительность нажатия храниться в свойстве input.activePointer.duration:

if (this.swipe !== null && this.game.input.activePointer.isUp) {
  var speed = this.swipe.delta_y/this.swipe.duration;
  if (Math.abs(speed) > 0.3) {
    var distance = speed * 300;
    if (this.scroll_tween) this.scroll_tween.stop();
    this.scroll_tween = this.game.add.tween(this.lesson).to({y: this.lesson.y + distance}, 1000, Phaser.Easing.Quartic.Out, true);
  }
  this.swipe = null;
}

Как только палец отжат, я высчитываю скорость и прокручиваю на расстояние, эквивалентное расстоянию которое пользователь успел бы прокрутить не отпустив палец еще 300 миллисекунд (число подобрал экспериментально). Тут я еще прибег к такой вот хитрости: если скорость прокрутки слишком низкая, то я отменяю инерцию.

Но даже такой сложный подход оказался ошибочным. Если попробовать переместить палец слишком быстро, а перед тем как отпустить — сделать задержку на месте, инерция у объекта исчезает. Эту задачу я решил высчитав среднюю скорость за последние 300 миллисекунд. Для этого я создал массив, в котором сохранял координаты пальца каждые 100 миллисекунд во время swipte жеста. В результате я получил нужные мне эффект:

if (this.game.input.activePointer.isDown) {
  if (this.scroll_tween) this.scroll_tween.stop();
  if (this.swipe === null) this.swipe = {start: {y: this.lesson.y}, delta_y: 0, duration: 0, position_list: {}};
  this.swipe.delta_y = this.game.input.activePointer.position.y - this.game.input.activePointer.positionDown.y;
  if (this.swipe.delta_y < 0) {
    this.lesson.y = this.swipe.start.y - Math.abs(this.swipe.delta_y);
  } else {
    this.lesson.y = this.swipe.start.y + Math.abs(this.swipe.delta_y);
  }
  this.swipe.duration = this.game.input.activePointer.duration;
  this.swipe.position_list[Math.round(this.swipe.duration/100)] = this.game.input.activePointer.position.y;
}
if (this.swipe !== null && this.game.input.activePointer.isUp) {
  var position_list = [];
  for (var i in this.swipe.position_list)
    position_list.push(this.swipe.position_list[i]);
  position_list = position_list.slice(-4);

  var speed = 0;
  for (var i=0; i<position_list.length-1; i++) speed += (position_list[i+1] - position_list[i]) / 100; speed = speed/3; if (Math.abs(speed) > 0.3) {
    var distance = speed * 300;
    if (this.scroll_tween) this.scroll_tween.stop();
    this.scroll_tween = this.game.add.tween(this.lesson).to({y: this.fix_scroll_y(this.lesson.y + distance)}, 1000, Phaser.Easing.Quartic.Out, true);
  }
  if (this.lesson.y > 0 || this.lesson.y < this.mask.min) {
    if (this.scroll_tween) this.scroll_tween.stop();
    this.scroll_tween = this.game.add.tween(this.lesson).to({y: this.fix_scroll_y(this.lesson.y)}, 750, Phaser.Easing.Elastic.Out, true);
  }
  this.swipe = null;
}

Что бы пост не получился слишком длинным, я сразу опубликовал последний вариант. В нем я добавил метод this.fix_scroll_y() который не позволяет списку уроков выходить за пределы экрана. А также добавил красивый эффект резинки… если пользователь попытается оттянуть пункты меню ниже чем это возможно, то они как привязанные на резинке вернуться назад. Мелочь а красиво =)

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

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

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