JavaScript библиотека для работы покадровой анимацией

в 12:01, , рубрики: animation, game development, Gamedev, javascript, метки: , ,

Здравствуйте, читатели.
Хочу предоставить Вашему вниманию новую JavaScript библиотеку для работы покадровой анимацией. Занимался флеш-разработкой, сейчас все больше и больше пишу на JavaScript-e (только не будем здесь разводить холивар на эту тему). После долгих поисков чего либо для работы с анимацией и таймлайном, решил написать свою библиотеку. Получилась лёгкой, но достаточно функциональной, решила те моменты, которые отсутствовали в JavaScript, но были очень полезны в AS3.0 (Flash) и были там стандартными методами.

Библиотека была названа JS_Mc (долго над названием не думал, по этому как то так), Mc от MovieClip -типа даных во Flash, в котором и присутствует таймлайн и различные методы по управления им. Работает в браузерах Chrome (22.0.1229.2 dev-m), Opera (11.61), Firefox (14.0.1), IE (8.0) — это те версии, которые установлены у меня, на них тестировал. Сама библиотека находиться здесь, там есть документация, демо и туториалы.

По одному из них
imageimageimageimageimage

я пройдусь здесь и расскажу о основной функциональности.

Начинаем работу с JS_Mc


Для создания анимации мы можем использовать много изображений (отдельных файлов), или же одно длинное изображение (горизонтально или вертикально ориентированное) на которому подряд изображены кадры. За это отличие отвечает свойство 'imgs_way' передаваемого в конструктор объекта, 'one_img' или 'many_imgs' соответственно. Если вы используете одно изображения, вы должны указать ориентацию (ход кадров, горизонтально или вертикально): 'h' или 'v', также нужно указать количество кадров на этом длинном изображении, это свойство 'q_of_frames'. Путь к файлам изображений — 'urls_of_imgs', для множества файлов передаем массив, или одну строку — для одного длинного изображения.
Посмотрим, что у нас уже есть (чтобы было всё понятно, на сайте библиотеки скачайте файлы данного урока):

hero_init_data  = {
   //-- 'many_imgs' - defult value, maybe skip if you use array of images
   imgs_way: 'many_imgs', 
  //-- array of images for frames                
  urls_of_imgs: f_get_Urls_arr('hero_1'),
  //-- labels, for comfy work with frames, n_frame - show on position on timeline, label - name                 
  labels_in_frames: [ { n_frame: '0', label: 'start_sword'}, 
                                    { n_frame: '2', label:'start_slow_motion_sword'}, 
                                    {n_frame: '3', label:'slow_sword_also'},                                   
                                    { n_frame: '5', label: 'end_sword'},
                                    { n_frame: '6', label: 'start_run_explosion'},                                                                        
                                    { n_frame: '14', label: 'place_for_explosion'},
                                    { n_frame: '16', label: 'end_run_explosion'}
                                    ],
  //--  n_frame - show on position on timeline, act - actions with timeline, func - function, which will be run when  
  //-- this frame will be current                
  codes_in_frame: [ { n_frame: 'start_slow_motion_sword', func: f_start_Slow_motion_Sword },                                  
                                  { n_frame: 'end_sword', act: 'goto_and_stop#start_sword'},         
                                  { n_frame: '11', func: f_start_Slow_motion_explosion },
                                  { n_frame: 'end_run_explosion', act: 'stop'}]                              
 }                               
        
  //-- create hero_1      
  hero_1 = new JS_Mc(hero_init_data);

Как видите, я создал отдельный объект и потом его уже передаю в конструктор. Метод f_get_Urls_arr('hero_1') — внешняя функция, просто возвращает массив, часть её:

function f_get_Urls_arr(_name) {
	var _arr = new Array();
        
        switch (_name) {
            case 'hero_1':
                var max = 17;
                for (var i = 0; i < max; i+=1) {
                    _arr[i] = 'images/hero_1/' + i.toString()+'.png';         
                }        
            break;

на всякий случай.
Также мы увидели свойства' labels_in_frames' и' codes_in_frame'. Это первые из полезных вещей, и так, поехали.

Массив 'labels_in_frames' — метки для удобной работы з таймлайном, здесь долго говорить не буду, чтобы не запоминать номера кадров, удобно ставить метки и переходить по ним. Например { n_frame: '14', label: 'place_for_explosion'} — в 14-ой кадр мы установили метку 'place_for_explosion', это место где позднее в руке у ниндзи будет взрыв, если вы уже посмотрели примеры.

Массив 'codes_in_frame' — действия которые будет происходить по ходу таймлайна. Пример { n_frame: 'end_sword', act: 'goto_and_stop#start_sword'} — в кадр с ранее установленной меткой 'end_sword' мы пишем act: 'goto_and_stop#start_sword', то есть, когда ролик доиграет до кадра 'end_sword' произойдет переход к кадру 'start_sword'.

Здесь уже можно огласить доступные методы:

  • goto_and_stop#frame — переходит к frame (может быть метка или номер кадра) и останавливается на нем
  • goto_and_play#frame — переходит к кадру frame и играет с него
  • stop — останнавливает анимацию
  • play — продолжает анимацию

Также в 'codes_in_frame' вы видите { n_frame: '11', func: f_start_Slow_motion_explosion } 'func' — здесь мы устанавливаем функцию которая будет вызываться, когда данный кадр будет текущим. На 11-ом кадре мы вызвем функцию f_start_Slow_motion_explosion. Ясно, кадр можно указывать и меткой, старался писать разными способами.
После hero_1 = new JS_Mc(hero_init_data) вызиваем функцию f_Load, параметр которой функция, что будет вызвана по окончанию загрузки. Часть функции:

//-- method f_Load will start creating your obj, parameter of this method - function, which will be run on complete loading                         
        hero_1.f_Load(function() {
             f_on_load_Complete_h1(this);   

Чтобы было чистей, тут также внешняя функция f_on_load_Complete_h1, вот она:

function f_on_load_Complete_h1(self) {
            //-- append hero to stage, body - is HTMLDivElement, use it for set html properties 
            container_anim.append(self.body);
            self.fps = 20;
            self.body.style.top = '50px'; 
            self.body.style.left = '150px';
            
            //-- our btns for controll hero
            f_Init_btns(self);        
        }  

Важный момент container_anim.append(self.body) то есть свойство body указывает на HTMLDivElement, это контейнер в котором происходит анимация. container_anim.append — объект и метод jQuery то есть по окончанию загрузки нашего JS_Mc объекта мы добавили его в container_anim. Сама загрузка — это загрузка в кеш всех изображений для анимации. Также мы видим self.fps = 20, понятно, устанавливаем фпс, это можно делать только один раз, в функции по завершении загрузки, по дефолту фпс = 10, для каждого JS_Mc объекта можно установить свой фпс.

Далее (если вы смотрите код урока, здесь я весь ясно не привожу, а лишь важные моменты) hero_1.f_add_Child_To('place_for_explosion', explosion), то есть в любой кадр мы можем добавить элемент, там массивы, то есть можно в каждый кадр по сколько угодно дочерних элементов. Помните только, что это повлияят на производительность, так что если в элемента не будет дочерних элементов советую установить allow_child = false. Чтобы удалить дочерний элемент из родителя — f_remove_Child(child). Добавлять можно как другие JS_Mc обекты так и html элементы.

Можно еще рассказать о методах объекта по работе з таймланом, это скорее всего самое часто используемое:

  • f_Goto_and_Stop(frame) -переходит к frame (может быть метка или номер кадра) и останавливается на нем
  • f_Goto_and_Play(frame) — переходит к кадру frame и играет с него
  • f_Stop() — останнавливает анимацию
  • f_Play() — продолжает анимацию

Чтобы добавить какие-то свои данные к объекту существует свойство user_data, например: object.user_data.name = 'object_1'. Чтобы удалить объект (полностью) — f_Remove().
Ну пожалуй всё. Остальное всё можно посмотреть в документации.

Автор: bob_lyashenko

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js