Saturday, October 29, 2011

Простая игра на HTML5 Canvas – часть 2


Персонаж

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

Давайте создадим объект, представляющий главного героя со всеми необходимыми атрибутами и методами. Назовем объект ‘player’ (англ. – игрок). Далее мной выбран не лучший способ описания объекта в JS, потому что все атрибуты являются доступными, а закрытые не применяются вообще. Но это простейшее решение, позволяющее уложиться в запланированные 10КБ, а главное что это работает. Если вам захочется узнать о закрытых атрибутах и методах, наследовании и т.п. прочитайте об этом в учебнике по JavaScript (на англ.языке можно прочитать тут - http://jibbering.com/faq/notes/closures/ ). Также важно помнить что если вы соберетесь уменьшить код с помощью онлайн инструментов, таких как ‘Closure Compiler’ (http://closure-compiler.appspot.com/home) что имена аргументов объектов он не сокращает. Именно поэтому я использую 2-х буквенные сокращения для описания объекта, например, ‘player.im’ вместо ‘player.image’. Итак, вот код, который добавляется в наш game.js:
var player = new (function(){
//создаем новый объект основанный на функции
//и присваиваем его переменной ‘player’

    var that = this;
//'that' – псевдоним этого объекта

//attributes
    that.image = new Image();
    that.image.src = "angel.png";
//создаем новый Image элемент и
//'angel.png' закачиваем в него

    that.width = 65;
//ширина одного кадра
    that.height = 95;
//высота одного кадра (рисунок в 2 раза выше, ведь в нем 2 кадра)

    that.X = 0;
    that.Y = 0;
//X&Y позиция объекта на холсте

//далее описываем методы
    that.setPosition = function(x, y){
    that.X = x;
    that.Y = y;
}

    that.draw = function(){
        try {
            ctx.drawImage(that.image, 0, 0, that.width, that.height, that.X, that.Y, that.width, that.height);
//отрисовываем наш персонаж функцией drawImage(объект-рисунок, X источника,
//Y источника, ширина источника, высота источника, X назначения (X позиция),
//Y назначения (Y позиция), ширина назначения, высота назначения)
        } catch (e) {
//Иногда, если изображение персонажа слишком велико и еще не успело
//загрузиться до вывода первого кадра, JavaScript выдаст ошибку и прекратит
//выполнение всего. Чтобы этого избежать, мы перехватываем ошибку и повторим
//попытку рисования в следующем кадре. Это незаметно для пользователей ведь
//частота кадров 50 в секунду.
        }
    }
})();
//мы сразу же применим функции описанные выше
//и создадим переменную ‘player’
//как новый объект

player.setPosition(~~((width-player.width)/2),  ~~((height - player.height)/2));
//наш персонаж готов, давайте переместим его
//в центр экрана,
//'~~' возвращает округленное вниз целое значение
//переменной с плавающей точкой, как это делает Math.floor()

Итак, теперь  необходимо перерисовывать нашего ангела на каждом кадре в игровом цикле с помощью  функции ‘player.draw’:
var GameLoop = function(){
    clear();
    MoveCircles(5);
    DrawCircles();
    player.draw();
    gLoop = setTimeout(GameLoop, 1000 / 50);
}

Ну а как насчет анимации? Спрайт (файл с изображением ангела) имеет 2 кадра, но только один из них перерисовывается на каждом кадре. Для того, чтобы анимировать наш персонаж потребуются дополнительные атрибуты и небольшие изменения метода ‘draw’:
var player = new (function(){
(...)
    that.frames = 1;
//нумерация кадров начинается с нуля
    that.actualFrame = 0;
//текущий кадр
    that.interval = 0;
//нам не прийдется переключать кадры
//в игровом цикле, ‘interval’ позаботится об этом

    that.draw = function(){
        try {
            ctx.drawImage(that.image, 0, that.height * that.actualFrame, that.width, that.height, that.X, that.Y, that.width, that.height);
//третий аргумент умножается на номер текущего кадра, чтобы показать нужную
//часть исходного изображения
        } catch (e) {};

        if (that.interval == 4 ) {
            if (that.actualFrame == that.frames) {
                that.actualFrame = 0;
            } else {
                that.actualFrame++;
            }
            that.interval = 0;
        }
    that.interval++;
//выше показана простая логика переключающая кадры каждые 4 итерации

    }
})();

Спасибо за внимание! Результат работы проделанной в данной части урока, как обычно, можно посмотреть по адресу: http://jsbin.com/orohe4/, а исходники скачать тут: http://github.com/michalbe/Simple-game-with-HTML5-Canvas/tree/master/part2/

КОПИРАЙТЫ.

Автор: Михал Будзинский https://twitter.com/#!/@michalbe
Автор перевода: Андрей Семенов https://twitter.com/#!/a_semenov79

No comments:

Post a Comment