Введение в spritesheet анимацию

Анимация, основанная на spritesheet’ах, используется в играх довольно продолжительное время. В том числе в таких популярных играх, как Legend of Zelda: A Link to the Past или Cut the Rope. В этой статье мы поговорим о том, как работает такая анимация и как ее запрограммировать. В качестве языка программирования будем использовать JavaScript, но вы можете выбрать любой удобный для вас.

Прежде чем говорить о том, как программировать spritesheet анимацию, нам следует определить три термина: анимация, спрайт и, собственно, spritesheet.

Анимация

В далеком 1872 году английскому и американскому фотографу Эдварду Мейбриджу было поручено узнать, поднимает ли лошадь все свои 4 ноги во время бега. Мейбридж для этого использовал несколько камер, которые делали снимок, когда лошадь с наездником пробегала мимо. В итоге фотограф получил 16 изображений лошади. Кстати говоря, в парочке из них все четыре ноги лошади действительно находятся в воздухе.

Muybridge_race_horse_sheet

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

Muybridge_race_horse_animated

Процесс быстрой смены изображений для создания иллюзии движения назвали анимацией.

Спрайт

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

sprite

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

Совсем не редкость, когда в игре существуют десятки, а то и сотни спрайтов. Загрузка каждого из них в качестве индивидуального и самостоятельного изображения будет потреблять много памяти и вычислительной мощности. Для того, чтобы избежать этих неудобств, и используют spritesheet’ы.

Spritesheet’ы

Когда вы кладете множество спрайтов в одно изображение, вы получаете spritesheet.

spritesheet

Spritesheet’ы используют для ускорения процесса отображения картинки на экране. Гораздо эффективнее и быстрее загрузить одно большое изображение и показать его часть, чем загрузить множество спрайтов и показать их.

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

Части spritesheet’а

Сам по себе spritesheet состоит из двух частей: кадров и циклов.

Кадр является обычным изображением (или спрайтом). На примере лошади Мейбриджа: каждое изображение лошади во всей анимации является кадром.

Если кадры поставить в правильном порядке, то получится непрерывное движение. Это и есть цикл.

Программирование spritesheet анимации

Существует 3 этапа создания spritesheet анимации:

  1. Создание изображения.
  2. Обновление изображения для каждого кадра анимации.
  3. Рисование анимации на экране.

Создание изображения

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

Так как spritesheet’ы могут иметь разные размеры, то, зная размер одного кадра, мы будем знать количество кадров в строке и столбце.

Очень важно, чтобы каждый кадр анимации имел один и тот же размер, иначе анимация получится не натуральная.

Обновление изображений

Чтобы обновить spritesheet анимацию, нам понадобится изменить тот кадр, который рисуется в данный момент. Ниже spritesheet разделен на кадры, каждый из которых пронумерован.

spritesheet_numbered

Менять текущий кадр на следующий нужно не моментально, а через какое-то время. То есть при показе одного из кадров требуется сделать определенную задержку перед тем, как поменять его.

Важно отметить, что не каждый spritesheet имеет доступный спрайт в каждом из своих кадров. Например, в spritesheet’е Мейбриджа 16-й спрайт отсутствует. Если бы мы не учли этого, то анимация получилась бы со вспышкой.

Избежать всплесков запросто: мы не будем отрисовывать эти пустые изображения:

При использовании операции по взятию остатка от деления (%) для currentFrame мы создаем непрерывный цикл чисел от 0 до endFrame. Таким образом мы воспроизводим только те кадры, изображения для которых у нас есть в spritesheet’е.

Рисование анимации

Вычисляем строку с нужным кадром, взяв остаток от деления номера текущего кадра на количество кадров в строке. Также вычисляем столбец с нужным кадром путем деления номера текущего кадра на количество кадров в строке.

Используя найденные величины мы можем найти координаты той рамки, внутри которой и находится искомый кадр:

Теперь мы готовы создать анимацию:

Несколько циклов в одном spritesheet

Приведенный выше код будет работать для любого spritesheet’а, содержащего ровно один цикл. Тем не менее, существуют spritesheet’ы с несколькими циклами (анимациями).

Для работы с несколькими анимациями в одном spritesheet’е, нам понадобится изменить наш принцип работы.

Создание изображения

Храним информацию об изображении и его размерах:

Обновление и рисование анимации

Функция Animation() будет отвечать за обновление и отрисовку картинки:

Поскольку spritesheet содержит множество кадров для различных анимаций, мы должны знать номера тех кадров, анимацию которых мы хотим сейчас воспроизводить.

Послесловие

Мы написали простенькую игру-раннер, используя ту самую анимацию, о которой говорилось в статье. Исходный код, приведенный в статье, вы можете увидеть, пройдя по этой ссылке.

Перевод статьи «An Introduction to Spritesheet Animation»