среда, 12 октября 2011 г.

[Из песочницы] Анимация спрайтов при помощи CSS, JS и Canvas


Всем привет. Пару дней назад совершенно случайно наткнулся в залежах дисков на «Космические рейнджеры 2: Доминаторы». Устанавливать не стал, так как сейчас не хватает времени, чтобы как следует в неё погрузиться. А решил посмотреть, что на диске находится. Посмотрел «Фан-Арт» и там увидел программку для ковыряния ресурсов рейнджеров. Вот и решил посмотреть, из чего же сделаны наши доминаторы. Покликав немного, нашел файлики с анимацией в формате GAI. Начал любоваться той анимацией. Захотел их сохранить в «гифки», но не как не давала та программка сохранить анимацию? Можно либо сохранить текущий кадр, либо все файлы в PNG. Я решил сохранить все кадры, а их было — 150. Картинки все есть, а почему бы не сделать с ними ту же анимацию.



Спрайт



Для того чтобы порадовать себя такой анимацией взял в помощь CSS + JS. А что мне делать со 150-ю файлами изображений? Их вес не критичен, хоть и весят они в сумме больше мегабайта. Главные проблемы с их одновременной загрузкой и манипуляцией. Поэтому я решил «склеить» их в одну. Грузить только одну, да и при помощи CSS + JS придется только правильно позиционировать её.

Осталось выбрать метод «склейки». Я же программист, а мы все ленивые:), поэтому я сразу отбросил ручную склейку в графическом редакторе. Первым делом я бросился, как обычно, к PHP и библиотеке GD. Но она оставляет желать лучшего по работе с полупрозрачными PNG. Дальше я подумал, а чем же ещё можно «склеить» картинки? И остановился на том, что сейчас у всех на слуху, что считается сейчас модным — HTML5. За работу с графикой у него отвечает — Canvas, причем мне очень нравится эта «вкусняшка». Вот поэтому все же решил «клеить» на «холсте».

И так добавлю я ка этот тег в HTML:



<canvas id="sprite">Не поддерживается</canvas>


В JS укажу маску для имени картинки, первую картинку и номер последней (мне не пришлось переименовывать картинки, так как они все идут по порядку). Это должно выглядеть примерно так:



var first = '000';  //номерная часть имени первой картинки
var last  = 49;     //номер последней картинки
var num   = 0;      //итератор

var maskFileName = ['2HULL_PEOPLE_P_A_', '.png'];//маска имени картинки
var dir = 'ship';   //директория, в которой лежат картинки




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



var canvas = document.getElementById("sprite"); //выберем наш канвас
canvas.width  = (last + 1) * 75; //задаем ширину, в зависимости от количества
canvas.height = 75;
var width = 0;  //переменная, в которую будем записывать сдвиг
var context = canvas.getContext("2d"); //получаем контекст




Для облегчения перевода из числа в строку (аналог str_pad из PHP) написал функцию-преобразователь с диким названием — zerofikator():



function zerofikator(int, length) { //на вход получаем число и длину строки
 var prefix = '';
 for (var i = num.toString().length; i < length; i++) {
  prefix += '0';
 }
 return prefix + num;
}




Далее для рисования на «холсте» нашими картинками, т.е. создания спрайта, вот такая незатейливая функция:



function draw() {
 var img = document.createElement('img'); /* каждый раз при вызове этой функции мы создаем новый обьект-изображение */
 img.onload = function () {
      //когда изображение загрузится рисуем им на канвасе
      context.drawImage(img, width, 0);
      width += 75; 
//при этом каждый раз сдвигаем на ширину изображения, чтобы рисовать справа от предыдущего рисунка, а не на нем
      if (zerofikator(num, first.length) != zerofikator(last, first.length)) {
//проверяем достигли ли мы последнего рисунка
       num++; //увиличуем итератор
       draw(); //и запускаем функцию вновь
      }      
 }
 img.src = dir + '/' + maskFileName[0] + zerofikator(num, first.length) + maskFileName[1]; //собираем имя файла картинки для загрузки
}

draw(); //вызываем функцию впервые




После запуска такой страницы мы увидим широкое покадровое изображение, которое если мы сохраним, то сможем называть спрайтом. Кстати, сохраненный спрайт весит 615 KB, а 150 картинок 1 189 KB, хм, вот и ещё один плюс:).



image



Демо



Анимация



Ну а теперь, можно приступить и к анимации.

В HTML добавляем пару «дивчиков», с которыми мы дальше будем работать:



<div id="gun"></div>
<div id="ship"></div>




Дальше я написал функцию, которая анимирует спрайты, но настройки решил вынести отдельно, для того чтобы можно было его использовать сразу для нескольких «анимашек»:



var styles = {};
styles.cursor = 'pointer'; //чтобы видно было что это наш элемент, меняем курсор
styles.width = '75px'; //размеры элемента
styles.height = '75px';
var elementId = 'gun';   // id элемента, в котором будет анимация
var imgName = 'canvas.png'; // имя файла спрайта




А далее сама функция:



function spriteAnimation(elementId, imgName, styles) {
 
 var img = document.createElement('img');
 var offset = 0;
 img.onload = function () { //как только спрайт загружается
  var element = document.getElementById(elementId);
  element.style.cursor     = styles.cursor;
  element.style.width      = styles.width;
  element.style.height     = styles.height;
  element.style.background = "url('" + imgName + "') " + offset + "px 50%"; //меняем стили для нашего элемента
  var i = 0;
  element.onmouseover = function() { //вешаем обработчик на наведение мыши
   interval = setInterval(function() { //запускаем интервал
    if (offset < img.width) { //для смены позиции изображения
     i++; // если дошли до конца спрайта
    } else {
     i = 0; // то возвращаемся к началу
    }
    offset = 75 * i; //сдвиг по слайду
    element.style.background = "url('" + imgName + "') " + offset + "px 50%"; 
//меняем позиционирование спрайта
   } , 1000/24) //24 кадра в секунду
  }
  element.onmouseout = function(){ //вешаем обработчик на убирание курсора мыши
   clearInterval(interval) //удаляем интервал (прекращаем анимацию)
  }
 }
 img.src = imgName; //даем имя нашего спрайта
}




Ах да, нужно ведь ещё вызвать эту функцию:



spriteAnimation(elementId, imgName, styles);
spriteAnimation('ship', 'ship.png', styles);




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



<img src="fon.png" />
<div class="conteiner"><div id="gun"></div></div>




image



Демо



Исходники



Как говорится «Just for fun». А как вы проводите своё время дождливыми осенними вечерами?




Источник: Хабрахабр - Веб-разработка
Оригинальная страница: [Из песочницы] Анимация спрайтов при помощи CSS, JS и Canvas

Комментариев нет:

Отправить комментарий