Pull to refresh

Создание спрайтового движка

Reading time4 min
Views9.9K
Когда то давно, в своем дебютном посте, я обещал рассказать о создании спрайтовой анимации с сортировкой по глубине… Ну, обещания нужно сдерживать:)


И так, сегодня я расскажу про создание простенького спрайтового движка, с поддержкой сортировки по глубине.
Для начала давайте создадим класс Sprite:

Copy Source | Copy HTML
  1. function Sprite(_img, _frames) {
  2.     this.img = _img;
  3.     this.frames = _frames;
  4.     this.frameWidth = _img.width/_frames;
  5. }


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

Copy Source | Copy HTML
  1. var loaded =  0;
  2. var allImgs = 3;
  3. function imgonload() {
  4.     loaded++;
  5.     if (loaded == allImgs) {
  6.         afterLoad();
  7.     }
  8. }
  9. var img1 = new Image();
  10. img1.src = 'img1.png';
  11. img1.onload = imgonload;
  12. var img2 = new Image();
  13. img2.src = 'img2.png';
  14. img2.onload = imgonload;
  15. var img3 = new Image();
  16. img3.src = 'img3.png';
  17. img3.onload = imgonload;
  18. var spr1, spr2, spr3;
  19. function afterLoad() {
  20.     spr1 = new Sprite(img1, 3);
  21.     spr2 = new Sprite(img2, 3);
  22.     spr3 = new Sprite(img3, 3);
  23. }


Данный код тоже очень простой, на нем останавливаться я не буду.
Теперь создаем SpriteEngine — именно он будет отвечать за рендер наших спрайтов.

Copy Source | Copy HTML
  1. function SpriteEngine(_layers){
  2.     this.layers = _layers;
  3.     this.renderList = []; //Массив очереди для рендера
  4.     this.ctx;
  5.     this.startRender = function(_ctx) {
  6.         this.ctx = _ctx;
  7.         this.renderList.length =  0;
  8.         for (var i =  0; i < this.layers; i++) {
  9.             this.renderList[i] = [];
  10.         }
  11.     }
  12.     this.drawSprite = function(_s, _x, _y, _frame, _layer) {
  13.         //Просчитываем какой кусок нужно отрисовать и добавляем 
  14.         //это в очередь для рендера
  15.         if (_frame <= _s.frames) {
  16.             this.renderList[_layer-1].push({
  17.                 img: _s.img,
  18.                 x: _x, y: _y,
  19.                 xonimg: _frame*_s.frameWidth,
  20.                 yonimg:  0,
  21.                 imgwidth: _s.frameWidth,
  22.                 imgheight: _s.img.height
  23.             });
  24.         }
  25.     }
  26.     this.endRender = function() {
  27.         //Тут собственно и отрисовываем
  28.         for (var i =  0; i < this.layers; i++) {
  29.             for (var j =  0; j < this.renderList[i].length; j++) {
  30.                 var e = this.renderList[i][j];
  31.                 this.ctx.drawImage(e.img, e.xonimg, e.yonimg, e.imgwidth, e.imgheight, e.x, e.y, e.imgwidth, e.imgheight);
  32.             }
  33.         }
  34.     }
  35. }


Могут возникнуть вопросы по поводу renderList, который по сути является «массивом массивов» (тобиш двумерным). Первый массив хранит слой, второй — объекты с параметрами для рендера.
Теперь добавлю создание SpriteEngin'a, отрисовку наших спрайтов и регулярно увеличивающеюся переменную frame которая отвечает за текущий кадр анимации:

Copy Source | Copy HTML
  1. ...
  2. var frame =  0;
  3. setInterval(function() {
  4.     if (frame < 2) {
  5.         frame++;
  6.     } else {
  7.         frame =  0;
  8.     }
  9. }, 500);
  10. var ctx = document.getElementById('c').getContext('2d');
  11. var se = new SpriteEngine(3);
  12. ...
  13. function afterLoad() {
  14.         ...
  15.     setInterval(function() {
  16.         ctx.fillStyle = '#007F46';
  17.         ctx.fillRect( 0,  0, 640, 480);
  18.         se.startRender(ctx);
  19.         se.drawSprite(spr1, 100, 100, frame, 3);
  20.         se.drawSprite(spr2, 116, 116, frame, 2);
  21.         se.drawSprite(spr3, 132, 132, frame, 1);
  22.         se.endRender();
  23.     }, 25);
  24. }


Сохраняем, ловим баги и вуаля:) Нужно заметить, что нумерация слоев начинается с 1, причем, чем больше номер слоя, тем «дальше» он от нас находится. Максимально количество слоев мы передаем при создании SpriteEngine.

Исходники — тык.
P. S.: Если кто-нибудь куда-нибудь зальет — буду благодарен:)
Tags:
Hubs:
+2
Comments10

Articles

Change theme settings