Содержание


Разработка 2D-игр на HTML5

Реализация гравитации и добавление звука

Анимация реалистичных падений; добавление музыки и звуковых эффектов

Comments

Серия контента:

Этот контент является частью # из серии # статей: Разработка 2D-игр на HTML5

Следите за выходом новых статей этой серии.

Этот контент является частью серии:Разработка 2D-игр на HTML5

Следите за выходом новых статей этой серии.

Теперь, когда игра Snail Bait способна обнаруживать столкновения — эта возможность была реализовано в предыдущей статье данного цикла, — необходимо научить ее обрабатывать важное событие, не относящееся к категории столкновений: ситуацию, когда бегун промахивается мимо платформы. В этом случае он начинает падать. В этой статье я покажу, как учесть гравитацию для реализации реалистичного падения. Гравитация и падения – это завершающие механические аспекты геймплея, необходимые игре Snail Bait. После этого я сменю тему и покажу, как включить в игру звук (в том числе музыку). Полный демонстрационный код для этой статьи можно загрузить поссылке.

Падение

В игре Snail Bait бегун падает в том случае, если забегает за край платформы или сталкивается с платформой снизу (см. рис. 1).

Рисунок 1. Падение с края платформы
Screen capture of Snail Bait with the runner falling off the edge of a platform
Screen capture of Snail Bait with the runner falling off the edge of a platform

Кроме того, бегун падает в том случае, если промахивается мимо платформы в конце фазы снижения при прыжке (см. рис. 2).

Рисунок 2. Падение в конце прыжка
Screen capture of Snail Bait with the runner falling at the end of a jump
Screen capture of Snail Bait with the runner falling at the end of a jump

Падение бегуна реализуется посредством объекта fall behavior (манипулятора падения). В листинге 1 показана реализация спрайта бегуна, специфицирующая массив "манипулятор" (behavior).

Листинг 1. Манипуляторы бегуна
Sprite = function () {
   ...
   this.runner = new Sprite('runner',           // type
                            this.runnerArtist,  // artist
                            [ this.runBehavior, // behaviors
                              this.jumpBehavior,
                              this.collideBehavior,
                              this.fallBehavior,
                            ]); 
};

Игра Snail Bait вызывает манипулятор падения бегуна — как и все другие манипуляторы спрайта — в каждом кадре анимации, в котором спрайт является видимым. Большую часть времени манипулятор падения ничего не делает. Пока атрибут falling бегуна имеет значение true, манипулятор падения инкрементно перемещает бегуна в вертикальном направлении на каждом кадре анимации, в результате чего создается впечатление его падения. Значение этому атрибуту присваивает метод fall() бегуна (см. Листинг 2).

Листинг 2. Метод fall() бегуна
SnailBait.prototype = {
   ...
   equipRunner: function () {
      ...
      this.equipRunnerForJumping();
      this.equipRunnerForFalling();
   },

   equipRunnerForFalling: function () {
      ...

      this.runner.fallAnimationTimer = new AnimationTimer();

      this.runner.fall = function (initialVelocity) {
         // set attributes for the runner's fall behavior and
         // start the fall animation timer

         this.velocityY = initialVelocity || 0;
         this.initialVelocityY = initialVelocity || 0;
         this.falling = true;

         this.fallAnimationTimer.start();
      }
   },
   ...
};

При запуске игры Snail Bait вызывает свой метод equipRunner(), который, помимо прочего, обеспечивает возможности для прыжков и падений бегуна. Метод equipRunnerForFalling() содержит реализацию метода fall() бегуна. Метод fall() задает начальную скорость бегуна, присваивает его атрибуту falling значение true и запускает таймер анимации для отслеживания времени, прошедшего с начала падения бегуна.

Когда метод fall() бегуна присваивает атрибуту falling бегуна значение true, он переключает триггер в манипуляторе падения бегуна. После этого бегун падает до тех пор, пока игра не присвоит атрибуту бегуна falling значение false. Остальная часть рассмотрения гравитации в рамках данной статьи посвящена реализации этого манипулятора.

Реализация гравитации

У поверхности Земли падающие объекты приобретают под действием гравитации ускорение 9,81 метров в секунду за секунду (м/с/c), то есть за каждую секунду скорость падающего объекта увеличивается почти на 10 м/с. С точки зрения разработчика игр реализация гравитации означает, что в дополнение к вычислению положений спрайтов исходя из их скорости необходимо также вычислять скорости спрайтов, когда они падают.

Математика вычисления скорости под влиянием гравитации достаточно проста: нужно умножить ускорение силы тяжести на время, прошедшее с начала падения спрайта, и добавить полученное значение к начальной скорости спрайта на тот момент, когда он начал падать. Как нередко бывает в вычислениях, сложность заключается не в математических формулах, а в единицах измерения, поскольку результат предыдущего уравнения выражается в метрах в секунду. Чтобы сделать этот результат осмысленным, Snail Bait преобразует его в пиксели в секунду, используя следующий алгоритм вычисления положения спрайта.

  • В начале игры:
    1. Определить ширину игры в пикселях.
    2. Задать ширину игровой зоны в метрах произвольным образом.
    3. Разделить ширину в пикселях на ширину в метрах для получения отношения "пиксели/метры"
  • Затем для каждого кадра анимации:
    1. На основе ускорения свободного падения (9,81 м/с/c) вычислить скорость в метрах в секунду (м/с).
    2. Умножить скорость в м/с на отношение пиксели/метры (вычисленное на шаге 3) для получения размерности "пиксели в секунду".
    3. Вычислить положение на основе значения скорости, выраженной в пикселях в секунду.

Теперь можно преобразовать приведенный только что алгоритм в программный код. Первый шаг состоит в задании для игры силы тяжести и отношения пиксели/метры (см. листинг 3).

Листинг 3. Константы, определяющие силу тяжести и скорость падения
var SnailBait = { // SnailBait constructor function
   ...
  
   this.GRAVITY_FORCE = 9.81,
   this.PIXELS_PER_METER = this.canvas.width / 10; // 10 meters, randomly selected width
   ...
}

Когда бегун забегает за конец платформы или сталкивается с платформой снизу, он начинает падать с нулевой вертикальной скоростью. Однако если бегун промахивается мимо платформы в конце прыжка, он начинает падение с вертикальной скоростью, которую он имел в конце фазы снижения этого прыжка. В листинге 4 показано, как манипулятор прыжка бегуна использует константы GRAVITY_FORCE и PIXELS_PER_METER (заданные в Листинге 3) для вычисления этой начальной скорости.

Листинг 4. Падение в конце прыжка
this.jumpBehavior = {
   ...

   finishDescent: function (sprite) {
      sprite.stopJumping();

      if (snailBait.isOverPlatform(sprite) !== -1) {
         sprite.top = sprite.verticalLaunchPosition;
      }
      else {
         // The argument passed to the sprite's fall() method
         // is the sprite's initial velocity when it begins to fall
   
         sprite.fall(snailBait.GRAVITY_FORCE *
                     (sprite.descendAnimationTimer.getElapsedTime()/1000) *
                     snailBait.PIXELS_PER_METER);
      }
   },
};

Вертикальная скорость бегуна в конце его снижения равна ускорению свободного падения, умноженному на время, прошедшее с начала снижения, и на заданное для игры отношение пиксели/метры:

(9.81 m/s/s) * (время снижения в секундах)* (800 пикселей / 10 m)

Результат этого вычисления имеет размерность пиксели в секунду и представляет собой вертикальную скорость бегуна в конце фазы снижения его прыжка (остальную часть реализации манипулятора прыжка можно посмотреть в шестой статье данного цикла).

Другое место, где игра Snail Bait вычисляет скорость бегуна с использованием констант GRAVITY_FORCE и PIXELS_PER_METER, — это манипулятор падения бегуна (см. листинг 5).

Листинг 5. Задание скорости спрайта и вычисление вертикальной скорости бегуна для текущего кадра
this.fallBehavior = {
   ...
   setSpriteVelocity: function (sprite) {
      sprite.velocityY = sprite.initialVelocityY + 

                         snailBait.GRAVITY_FORCE *
                         (sprite.fallAnimationTimer.getElapsedTime()/1000) *
                         snailBait.PIXELS_PER_METER;
   },

   calculateVerticalDrop: function (sprite, fps) {
      return sprite.velocityY / fps;
   },
};

Метод setSpriteVelocity() манипулятора падения устанавливает скорость бегуна в зависимости от того, сколько времени он падал. Этот метод учитывает начальную скорость бегуна, которая могла быть установлена манипулятором прыжка в листинге 2.

Метод calculateVerticalDrop() использует движение, зависящее от времени — которое я рассматриваю в разделе Движение на основе времени второй статьи этого цикла — для вычисления вертикального падения бегуна на основе скорости, которая была вычислена методом setSpriteVelocity() и текущей частоты кадров.

Как я подробно описал в пятой статье этого цикла, на каждом кадре анимации игра Snail Bait перебирает все свои спрайты. Для каждого видимого спрайта Snail Bait проходит по всем манипуляторам этого спрайта и поочередно вызывает метод execute() для каждого из этих манипуляторов. В листинге 6 показан метод execute() для манипулятора падения бегуна.

Листинг 6. Метод execute() манипулятор падения
this.fallBehavior = {
      execute: function (sprite, time, fps) { // sprite is the runner
         var deltaY;

         if (sprite.jumping) {
            return;
         }

         if (this.isOutOfPlay(sprite) || sprite.exploding) {
            if (sprite.falling) {
               sprite.stopFalling();
            }
            return;
         }
         
         if (!sprite.falling) {
            if (!sprite.exploding && !this.isPlatformUnderneath(sprite)) {
               sprite.fall();
            }
            return;

         }

         this.setSpriteVelocity(sprite);
         deltaY = this.calculateVerticalDrop(sprite, fps);
               
         if (!this.willFallBelowCurrentTrack(sprite, deltaY)) {
            sprite.top += deltaY;
         }
         else { // will fall below current track
            if (this.isPlatformUnderneath(sprite)) {
               this.fallOnPlatform(sprite);
               sprite.stopFalling();
            }
            else {
               sprite.top += deltaY;
               sprite.track--;
            }
         }
      }
   },

Когда бегун прыгает, выпадает из игры или взрывается, метод execute() манипулятора падения инициирует или останавливает падение, а затем возвращает управление. Если бегун выпадает из игры или взрывается при падении, то метод execute() вызывает метод stopFalling(). Если в настоящий момент времени бегун не падает, не взрывается и не имеет под собой платформы, то метод execute() осуществляет вызов метода fall() бегуна.

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

Метод execute() манипулятора падения использует четыре вспомогательных метода. Два метода в листинге 7 определяют, не выпал ли бегун из игры или не упадет ли он ниже своей текущей дорожки.

Листинг 7. Выявление выпадения бегуна из игры или падения бегуна ниже его текущей дорожки
this.fallBehavior = {
   isOutOfPlay: function (sprite) {
      return sprite.top > snailBait.TRACK_1_BASELINE;
   },

   willFallBelowCurrentTrack: function (sprite, deltaY) {
      return sprite.top + sprite.height + deltaY >
             snailBait.calculatePlatformTop(sprite.track);
   },
   ...
};

Вспомогательные методы в листинге 8 определяют, находится ли под бегуном какая-либо платформа, и приземляют бегуна на такую платформу.

Листинг 8. Определение наличия платформы под бегуном и приземление бегуна на платформу
this.fallBehavior = {
   isPlatformUnderneath: function (sprite) {
      return snailBait.isOverPlatform(sprite) !== -1;
   },

   fallOnPlatform: function (sprite) {
      sprite.top = snailBait.calculatePlatformTop(sprite.track) - sprite.height;
      sprite.stopFalling();
   },
   ...
};

Необходимо осознавать, что метод execute() манипулятора падения перемещает бегуна по вертикали только в том случае, когда его атрибут falling имеет значение true. Метод бегуна stopFalling() присваивает этому атрибуту значение false (см. листинг 9), присваивает вертикальной скорости бегуна значение 0 и останавливает таймер анимации падения бегуна:

Листинг 9. Метод stopFalling() манипулятора падения
SnailBait.prototype = {
   ...

   equipRunnerForFalling: function () {
      ...

      this.runner.stopFalling = function () {
         this.falling = false;
         this.velocityY = 0;
         this.fallAnimationTimer.stop();
      }
   },
   ...
};

Приостановка при падении бегуна

Как было описано в разделе Приостановка манипуляторов седьмой статьи данного цикла, в манипуляторах должны быть реализованы методы pause() и unpause(), которые позволяют приостанавливать и возобновлять манипуляторы в соответствии с игрой в целом. Манипулятор падения бегуна соответствует этому требованию (см. листинг 10).

Листинг 10. Приостановка и возобновление манипулятора падения
 var SnailBait = function () {
   ...

   this.fallBehavior = {
      pause: function (sprite) {
         sprite.fallAnimationTimer.pause();
      },

      unpause: function (sprite) {
         sprite.fallAnimationTimer.unpause();
      },
   }
   ...
}

Манипулятор падения отслеживает прошедшее время падения с помощью таймера анимации падения бегуна. На основании этой величины методы pause() и unpause() этого манипулятора просто приостанавливают или вновь запускают этот таймер.

Теперь, когда вы узнали, как в игре Snail Bait реализуется падение бегуна, рассмотрим совершенно иной аспект игры — звуковые эффекты и музыку.

Управление звуковыми эффектами и музыкой

Игра Snail Bait может одновременно воспроизводить музыкальное сопровождение и генерировать звуковые эффекты. В нижнем левом углу рисунка 3 расположены флажки Sound (звук) и Music (музыка), которые позволяют пользователю включать в игре звуковые эффекты и/или музыку.

Рисунок 3. Органы управления звуком и музыкой
Screen capture of Snail Bait that shows the check boxes used to control sound and music
Screen capture of Snail Bait that shows the check boxes used to control sound and music

В листинге 11 показан HTML-код для флажков.

Листинг 11. Флажки Sound и Music игры Snail Bait
<div id='sound-and-music'>
   <div class='checkbox-div'>
      Sound <input id='sound-checkbox' type='checkbox' checked/>
   </div>
          
   <div class='checkbox-div'>
      Music <input id='music-checkbox' type='checkbox'/>
   </div>
</div>

Для управления первоначальной установкой флажка можно использовать атрибут checked флажка (без значения). Если этот атрибут имеется, то флажок исходно присутствует, в противном случае, он отсутствует (см. рис. 3 и листинг 11).

В листинге 12 игра Snail Bait программным способом обращается к элементам флажков и поддерживает две переменные — soundOn и musicOn — которые синхронизируются с флажками посредством обработчиков событий. Кроме того, обработчик событий флажка Music воспроизводит или приостанавливает музыкальное сопровождение игры, которое (в отличие от звуковых эффектов) непрерывно воспроизводится в фоновом режиме.

Листинг 12. Обработчики событий флажков Sound и Music
var SnailBait = function () {
   ...
   this.soundCheckbox = document.getElementById('sound-checkbox');
   this.musicCheckbox = document.getElementById('music-checkbox');

   this.soundOn = this.soundCheckbox.checked;
   this.musicOn = this.musicCheckbox.checked;
   ... 
};
...

snailBait.soundCheckbox.onchange = function (e) {
   snailBait.soundOn = snailBait.soundCheckbox.checked;
};

snailBait.musicCheckbox.onchange = function (e) {
   snailBait.musicOn = snailBait.musicCheckbox.checked;

   if (snailBait.musicOn) {
      snailBait.soundtrack.play();
   }
   else {
      snailBait.soundtrack.pause();
   }
};

Метод startGame() игры Snail Bait воспроизводит музыку при установленном флажке Music (см. листинг 13).

Листинг 13. Запуск игры
SnailBait.prototype = {
SnailBait.prototype = {
   ...

   startGame: function () {
      if (this.musicOn) {
         this.soundtrack.play();
      }
      requestNextAnimationFrame(this.animate);
   },
   ...

Кроме того, я изменил метод togglePaused() игры таким образом, чтобы приостанавливать и возобновлять воспроизведение музыки в зависимости от того, приостановлена ли сама игра (см. листинг 14).

Листинг 14. Приостановка воспроизведения музыки
SnailBait.prototype = {
   ...

   togglePaused: function () {
      ...

      if (this.paused && this.musicOn) {
         this.soundtrack.pause();
      }
      else if ( ! this.paused && this.musicOn) {
         this.soundtrack.play();
      }
   },
};

Реализация звуковых эффектов

Игра Snail Bait генерирует звуковые эффекты в различные моменты игры, — например, когда бегун сталкивается с пчелой или с летучей мышью, — и иногда должна воспроизводить несколько звуков одновременно. Для реализации звуковых эффектов в игре Snail Bait используются HTML5-элементы audio.

HTML-элементы audio

Snail Bait создает элемент audio для каждого из своих звуков (см. листинг 15).

Листинг 15. Элементы audio игры Snail Bait
<!DOCTYPE html>
<html>
   <head>
      <title>Snail Bait</title>
      <link rel='stylesheet' href='game.css'/>
   </head>
 
   <body>
      <audio id='soundtrack'>
        <source src='sounds/soundtrack.mp3' type='audio/mp3'>
        <source src='sounds/soundtrack.ogg' type='audio/ogg'>
      </audio>

      <audio id='plop-sound' >
        <source src='sounds/plop.mp3' type='audio/mp3'>
        <source src='sounds/plop.ogg' type='audio/ogg'>
      </audio>

      <audio id='chimes-sound' >
        <source src='sounds/chimes.mp3' type='audio/mp3'>
        <source src='sounds/chimes.ogg' type='audio/ogg'>
      </audio>

      <audio id='whistle-down-sound' >
        <source src='sounds/whistledown.mp3' type='audio/mp3'>
        <source src='sounds/whistledown.ogg' type='audio/ogg'>
      </audio>

      <audio id='thud-sound' >
        <source src='sounds/thud.mp3' type='audio/mp3'>
        <source src='sounds/thud.ogg' type='audio/ogg'>
      </audio>

      <audio id='jump-sound' >
        <source src='sounds/jump.mp3' type='audio/mp3'>
        <source src='sounds/jump.ogg' type='audio/ogg'>
      </audio>

      <audio id='coin-sound' >
        <source src='sounds/coin.mp3' type='audio/mp3'>
        <source src='sounds/coin.ogg' type='audio/ogg'>
      </audio>

      <audio id='explosion-sound' >
        <source src='sounds/explosion.mp3' type='audio/mp3'>
        <source src='sounds/explosion.ogg' type='audio/ogg'>
      </audio>
      ...

  </body>
</html>

Внутри каждого элемента audio я определяю два звуковых файла в разных форматах; браузер выбирает тот из этих форматов, который он способен воспроизводить. Форматы MP3 и OGG охватывают все варианты современных браузеров; в разделе Ресурсы приведены ссылки на дополнительную информацию о форматах HTML5 audio.

Кроме того, Snail Bait обращается к каждому элементу audio в JavaScript-коде посредством метода getElementById() в объекте document (см. Листинг 16).

Листинг 16. Обращение к элементам audio игры Snail Bait в JavaScript-коде
SnailBait = function () {
   ...

   this.coinSound           = document.getElementById('coin-sound'),
   this.chimesSound         = document.getElementById('chimes-sound'),
   this.explosionSound      = document.getElementById('explosion-sound'),
   this.fallingWhistleSound = document.getElementById('whistle-down-sound'),
   this.plopSound           = document.getElementById('plop-sound'),
   this.jumpWhistleSound    = document.getElementById('jump-sound'),
   this.soundtrack          = document.getElementById('soundtrack'),
   this.thudSound           = document.getElementById('thud-sound'),
   ...

};

Уровень громкости

Для каждого воспроизводимого звука игра Snail Bait определяет уровень громкости в диапазоне от 0.0 (нет звука) до 1.0 (максимальная громкость). В листинге 17 показаны константы, заданные в игре Snail Bait для разных звуков (я подобрал их опытным путем).

Листинг 17. Задание уровней громкости для звуков игры Snail Bait
SnailBait = function () {
   // Sound-related constants

   this.COIN_VOLUME            = 1.0,
   this.CHIMES_VOLUME          = 1.0,
   this.EXPLOSION_VOLUME       = 0.25,
   this.FALLING_WHISTLE_VOLUME = 0.10,
   this.JUMP_WHISTLE_VOLUME    = 0.05,
   this.PLOP_VOLUME            = 0.20,
   this.SOUNDTRACK_VOLUME      = 0.12,
   this.THUD_VOLUME            = 0.20,
   ...

};

При запуске игры Snail Bait производится инициализация элементов audio с использованием ссылок на эти элементы и констант, представляющих уровни громкости (см. листинг 18).

Листинг 18. Задание уровней громкости для звуков Snail Bat
SnailBait.prototype = {
   ...

   initializeSounds: function () {
      this.coinSound.volume           = this.COIN_VOLUME;
      this.chimesSound.volume         = this.CHIMES_VOLUME;
      this.explosionSound.volume      = this.EXPLOSION_VOLUME;
      this.fallingWhistleSound.volume = this.FALLING_WHISTLE_VOLUME;
      this.plopSound.volume           = this.PLOP_VOLUME;
      this.jumpWhistleSound.volume    = this.JUMP_WHISTLE_VOLUME;
      this.soundtrack.volume          = this.SOUNDTRACK_VOLUME;
      this.thudSound.volume           = this.LANDING_VOLUME;
   },

   start: function () {
      this.createSprites();
      this.initializeImages();
      this.initializeSounds();
      this.equipRunner();
      this.splashToast('Good Luck!');
      ...
   },
   ...   
   
};

Одновременное воспроизведение нескольких звуков

HTML5-элементы audio имеют простой API-интерфейс, в том числе следующие методы, которые используются в игре Snail Bat для воспроизведения звуков:

  • play()
  • pause()
  • load()

Кроме того, в игре Snail Bait используются следующие атрибуты элемента audio:

  • currentTime
  • ended

В листинге 19 можно увидеть использование всех предыдущих методов и атрибутов (за исключением метода pause(), который используется в листинге 12 и в листинге 14):

Листинг 19. Воспроизведение звуков с помощью аудиотреков Snail Bat
SnailBait = function () {
   ...
   this.soundOn = true,

   this.audioTracks = [ // 8 tracks is more than enough
      new Audio(), new Audio(), new Audio(), new Audio(), 
      new Audio(), new Audio(), new Audio(), new Audio()
   ],
   ...

   // Playing sounds.......................................................

   soundIsPlaying: function (sound) {
      return !sound.ended && sound.currentTime > 0;
   },

   playSound: function (sound) {
      var track, index;

      if (this.soundOn) {
         if (!this.soundIsPlaying(sound)) {
            sound.play();
         }
         else {
            for (i=0; index < this.audioTracks.length; ++index) {
               track = this.audioTracks[index];
            
               if (!this.soundIsPlaying(track)) {
                  track.src = sound.currentSrc;
                  track.load();
                  track.volume = sound.volume;
                  track.play();

                  break;
               }
            }
         }              
      }
   },
   ...
};

Чтобы воспроизводить несколько звуков одновременно, игра Snail Bait создает массив из восьми элементов audio. Метод playSound() игры Snail Bait выполняет обход этого массива и активизирует первый элемент audio, который в настоящий момент не занят воспроизведением звука.

Необходимо понимать, что игра Snail Bait никогда не воспроизводит звуковые эффекты с помощью исходных элементовaudio специфицированных в HTML-коде в листинге 15. Вместо этого игра воспроизводит звуковые эффекты посредством восьми элементов audio, которые она создает программным способом в листинге 19. Игра загружает звук из исходного элемента audio в программно созданный элемент, а затем воспроизводит этот программно созданный элемент.

Воспроизведение звуковых эффектов в игре Snail Bat

В листингах 20 - 23 показаны фрагменты кода, которые воспроизводят звуковые эффекты игры Snail Bat в различных ее точках. Я уже описал весь код этих листингов в предшествующих статьях данного цикла, поэтому сейчас не буду повторять эти описания. Для контекста я оставил достаточную часть логики, окружающей вызовы playSound().

Когда бегун прыгает, игра Snail Bat играет свистящий звук (см. листинг 20).

Листинг 20. Звук, производимый бегуном при прыжке
var SnailBait = function () {
   ...

   this.equipRunnerForJumping: function() {
       ...
      this.runner.jump = function () {
         if (this.jumping) // 'this' is the runner
            return;

         this.runAnimationRate = 0;
         this.jumping = true;
         this.verticalLaunchPosition = this.top;
         this.ascendAnimationTimer.start();

         snailBait.playSound(snailBait.jumpWhistleSound);
      };
   },

При взрыве спрайта игра Snail Bait воспроизводит звук explosionSound (см. листинг 21).

Листинг 21. Взрывы
SnailBait.prototype = {
   ...

   explode: function (sprite, silent) {
      if (sprite.runAnimationRate === 0) {
         sprite.runAnimationRate = this.RUN_ANIMATION_RATE;
      }
               
      sprite.exploding = true;

      this.playSound(this.explosionSound);
      this.explosionAnimator.start(sprite, true);  // true means sprite reappears
   },
   ...
};

Когда спрайты приземляются на платформу, они издают глухой звук, а при падении под дорожки — свистящий звук (не такой, как свист при прыжке).

Листинг 22. Звуки, ассоциированные с падениями
SnailBait = function () {
   ...

   this.fallBehavior = {
      ...

      fallOnPlatform: function (sprite) {
         sprite.top = snailBait.calculatePlatformTop(sprite.track) - sprite.height;
         sprite.stopFalling();
         snailBait.playSound(snailBait.thudSound);
      },

      execute: function (sprite, time, fps) {
         var deltaY;

         if (!this.willFallBelowCurrentTrack(sprite, deltaY)) {
            sprite.top += deltaY;
         }
         else { // will fall below current track
            if (this.isPlatformUnderneath(sprite)) {
               this.fallOnPlatform(sprite);
               sprite.stopFalling();
            }
            else {
               sprite.track--;

               sprite.top += deltaY;

               if (sprite.track === 0) {
                  snailBait.playSound(snailBait.fallingWhistleSound);
               }
            }
         }
         ...
      }
   };
   ...
};

При столкновениях спрайтов воспроизводятся различные звуки в зависимости от того, какие спрайты вовлечены в это столкновение (см. листинг 23).

Листинг 23. Звуки столкновения
var SnailBait =  function () {
   ...

   this.collideBehavior = {
      ...

      processCollision: function (sprite, otherSprite) {
         if (otherSprite.value) { // Modify Snail Bait sprites so they have values
            // Keep score...
         }

         if ('coin'  === otherSprite.type    ||
             'sapphire' === otherSprite.type ||
             'ruby' === otherSprite.type     || 
             'button' === otherSprite.type   ||
             'snail bomb' === otherSprite.type) {
            otherSprite.visible = false;

            if ('coin' === otherSprite.type) {
               snailBait.playSound(snailBait.coinSound);
            }
            if ('sapphire' === otherSprite.type || 'ruby' === otherSprite.type) {
               snailBait.playSound(snailBait.chimesSound);
            }
         }

         if ('bat' === otherSprite.type   ||
             'bee' === otherSprite.type   ||
             'snail' === otherSprite.type || 
             'snail bomb' === otherSprite.type) {
            snailBait.explode(sprite);
         }

         if (sprite.jumping && 'platform' === otherSprite.type) {
            this.processPlatformCollisionDuringJump(sprite, otherSprite);
         }
      },
   },

   processPlatformCollisionDuringJump: function (sprite, platform) {
      var isDescending = sprite.descendAnimationTimer.isRunning();

      sprite.stopJumping();

      if (isDescending) {
         sprite.track = platform.track; 
         sprite.top = snailBait.calculatePlatformTop(sprite.track) - sprite.height;
      }
      else { // Collided with platform while ascending
         snailBait.playSound(snailBait.plopSound);
         sprite.fall(); 
      }
   },
   ...
};

В следующей статье данного цикла

В следующей статье этого цикла я завершу цикл Разработка 2D-игр на HTML5. В частности, я опишу итоговый геймплей и добавлю завершающие штрихи, такие как переходы между жизнями бегуна и анимация в конце игры.


Ресурсы для скачивания


Похожие темы

  • Оригинал статьи: HTML5 2D game development: Implement gravity and add sound.
  • Форматы HTML5 Audio: официальная документация.
  • Core HTML5 Canvas: (David Geary, Prentice Hall, 2012): в книге Дэвида Джири приведен подробный обзор API Canvas и методов разработки игр. Посетите также сопутствующий веб-сайт и блог.
  • Snail Bait: игра Snail Bait работает в онлайновом режиме в любом браузере с поддержкой HTML5 (лучше всего подойдет Chrome версии 18 и выше).
  • Mind-blowing apps with HTML5 Canvas (Умопомрачительные приложения с применением HTML5 Canvas): выступление Дэвида Джири на конференции Strange Loop 2011.
  • HTML5 Game Development (Разработка HTML5-игр): выступление Дэвида Гири на конференции норвежских разработчиков NDC-2011.
  • Platform games статья в Википедии об играх-платформерах.
  • Side-scroller video games статья в Википедии об играх-сайдскроллерах.
  • Strategy статья в Википедии об этом шаблоне проектирования.
  • Основы HTML5: изучите основы HTML5 в рамках учебной программы developerWorks.
  • Replica Island: загрузите открытый исходный код этого популярного платформера для Android. Большая часть спрайтов Snail Bait взята из Replica Island (используется с разрешения).
  • Раздел для веб-разработчиков на ресурсе developerWorks. статьи по различным веб-решениям. Читайте также материалы по веб-разработке в технической библиотеке: обширный ассортимент технических статей, рекомендаций, руководств, учебных пособий и стандартов, а также руководств серии IBM Redbook.

Комментарии

Войдите или зарегистрируйтесь для того чтобы оставлять комментарии или подписаться на них.

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=Web-архитектура, Технология Java
ArticleID=954797
ArticleTitle=Разработка 2D-игр на HTML5: Реализация гравитации и добавление звука
publish-date=11272013