Если вы хотите писать казуальные игры, используя элемент HTML5 Canvas, вам нужно найти способ обработки ваших спрайтов. Есть несколько библиотек, которые помогут вам писать игры, такие как ImpactJS , CraftyJS и так далее. Со своей стороны, я решил использовать EaselJS, который использовался для написания PiratesLoveDaisies : HTML5 Tower Defense. В этом уроке мы увидим, как использовать существующие элементы спрайта и анимировать их .
Вы знаете, что я делаю это на языке мольеров, а также на французском языке: Jeux HTML5: анимация, дизайн, холст и легкость
Эта статья является первой из серии из 3:
— HTML5 Gaming: анимация спрайтов в Canvas с EaselJS
— HTML5 Gaming: создание основных объектов и обработка коллизий с EaselJS
— HTML5 Platformer: полный порт игры XNA для <canvas> с EaselJS
Вступление
На официальном сайте EaselJS вы найдете несколько интересных примеров и базовую документацию . Мы будем использовать образец спрайтов в качестве базы. Мы также будем использовать ресурсы, доступные в образце XNA 4.0 Platformer . Для тех из вас, кто читает мой блог, вы, возможно, помните, что я люблю играть с этим образцом. Вот предыдущие прикрепленные статьи:
— Начальный комплект платформера Windows Phone 7 для XNA Studio 4.0
— Редактор уровня платформера XNA Silverlight 4 для Windows Phone 7
Тем временем образец платформера был обновлен нашей командой XNA и доступен здесь для Xbox 360, ПК и Windows Phone 7: App Hub — платформер . Вы можете скачать его, чтобы поиграть с ним и извлечь спрайты, чтобы использовать их с EaselJS.
В этой статье мы будем использовать эти 2 PNG-файла в качестве источника последовательности спрайтов:
Наш монстр бежит:
который содержит 10 разных спрайтов.
Наш монстр в режиме ожидания:
который содержит 11 различных спрайтов.
Примечание: эти примеры не работают должным образом в Firefox 5.0 из- за ошибки в их реализации canvas . Он был хорошо протестирован в IE9 / IE10 / Chrome 12 / Opera 11 и Firefox Aurora 7.0.
Урок 1: создание SpriteSheet и BitmapSequence
Мы начнем с перемещения бегущего монстра между началом и концом ширины нашего холста.
Первый шаг — загрузить полную последовательность, содержащуюся в файле PNG, с помощью этого кода:
var imgMonsterARun = new Image();
function init() {
//find canvas and load images, wait for last image to load
canvas = document.getElementById("testCanvas");
imgMonsterARun.onload = handleImageLoad;
imgMonsterARun.onerror = handleImageError;
imgMonsterARun.src = "img/MonsterARun.png";
}
Этот код будет вызываться первым для инициализации содержимого нашей игры. После загрузки мы можем начать игру. EaselJS предоставляет объект SpriteSheet для обработки спрайта. Таким образом, используя этот код:
var spriteSheet = new SpriteSheet(
imgMonsterARun, //image to use
64, //width of each sprite
64, //height of each sprite
{
walk_left: [0, 9]
});
Мы указываем, что мы хотели бы создать новую последовательность с именем walk_left, которая будет состоять из изображения imgMonsterARun . Это изображение будет разбито на 10 кадров размером 64х64 пикселя. Это основной объект для загрузки нашего спрайта и создания наших последовательностей. При желании может быть создано несколько последовательностей из одного и того же файла PNG, например, в примере спрайтов крыс сайта EaselJS.
После этого нам нужно использовать объект BitmapSequence . Это помогает нам анимировать нашу последовательность и позиционировать наши спрайты на экране. Давайте рассмотрим код инициализации этой BitmapSequence:
// create a BitmapSequence instance to display and play back the sprite sheet:
bmpSeq = new BitmapSequence(spriteSheet);
// set the registration point (the point it will be positioned and rotated around)
// to the center of the frame dimensions:
bmpSeq.regX = bmpSeq.spriteSheet.frameWidth/2|0;
bmpSeq.regY = bmpSeq.spriteSheet.frameHeight / 2 | 0;
// start playing the first sequence:
bmpSeq.gotoAndPlay("walk_left"); //animate
// set up a shadow. Note that shadows are ridiculously expensive. You could display hundreds
// of animated rats if you disabled the shadow.
bmpSeq.shadow = new Shadow("#454", 0, 5, 4);
bmpSeq.name = "monster1";
bmpSeq.speed = 1;
bmpSeq.direction = 90;
bmpSeq.vX = 3|0.5;
bmpSeq.vY = 0;
bmpSeq.x = 16;
bmpSeq.y = 32;
// have each monster start at a specific frame
bmpSeq.currentFrame = 0;
stage.addChild(bmpSeq);
Конструктор BitmapSequence объекта просто нуждается в SpriteSheet элемент в качестве параметра. Затем мы даем имя последовательности, устанавливая некоторые параметры, такие как скорость и начальная позиция нашего первого кадра. Наконец, мы добавляем эту последовательность в список отображения с помощью объекта Stage и его метода addChild () .
Следующий шаг — решить, что бы мы хотели сделать в нашем цикле анимации. Этот цикл анимации вызывается каждые xxx миллисекунды и позволяет вам обновлять положение ваших спрайтов. Для этого EaselJS предоставляет объект Ticker, который обеспечивает централизованную передачу тика или пульса с заданным интервалом. Все, что вам нужно сделать, это подписаться на событие tick и реализовать метод .tick (), который будет вызываться обратно. Этот код, например, регистрирует событие:
Ticker.addListener(window); // Best Framerate targeted (60 FPS) Ticker.setInterval(17);
А вот код, который будет вызываться каждые 17 мс (когда это возможно), чтобы обновить положение нашего монстра:
function tick() {
// Hit testing the screen width, otherwise our sprite would disappear
if (bmpSeq.x >= screen_width - 16) {
// We've reached the right side of our screen
// We need to walk left now to go back to our initial position
bmpSeq.direction = -90;
}
if (bmpSeq.x < 16) {
// We've reached the left side of our screen
// We need to walk right now
bmpSeq.direction = 90;
}
// Moving the sprite based on the direction & the speed
if (bmpSeq.direction == 90) {
bmpSeq.x += bmpSeq.vX;
bmpSeq.y += bmpSeq.vY;
}
else {
bmpSeq.x -= bmpSeq.vX;
bmpSeq.y -= bmpSeq.vY;
}
// update the stage:
stage.update();
}
Вы можете проверить окончательный результат здесь :
Вы также можете просмотреть этот пример здесь: easelJSSpritesTutorial01, если вы хотите просмотреть полный исходный код.
Но ждать! В этой анимации есть 2 проблемы:
1 — шаги анимации странные, так как персонаж, кажется, слишком быстро
проходит по последовательности различных спрайтов 2 — персонаж может нормально ходить только справа налево, в противном случае похоже, что он пытается достичь своего рода лунного танца.
Давайте посмотрим, как это исправить во втором уроке.
Урок 2: управление скоростью анимации и переключение спрайтов
Чтобы зафиксировать скорость анимации, я нашел самый простой способ — использовать оператор модуля, чтобы избежать рисования / обновления моей последовательности во время каждого тика. В настоящее время существует открытая проблема по этой теме: https://github.com/gskinner/EaselJS/issues/60 с EaselJS 0.3.2.
Чтобы добавить новые кадры анимации, чтобы персонаж мог нормально ходить слева направо, нам нужно перевернуть каждый кадр. EaselJS предоставляет объект SpriteSheetUtils для этого и метод flip () . Вот код, который их использует:
// {nameOfFlippedSequence:["derivativeSequence", flipHorizontally, flipVertically, optionNameOfNextSequence]}
spriteSheet = SpriteSheetUtils.flip(
spriteSheet,
{
walk_right: ["walk_left", true, false, null]
});
Мы создаем производную последовательность с именем « walk_right » на основе последовательности «walk_left» , что мы переворачивать горизонтально. Наконец, вот код, который замедляет скорость анимации и обрабатывает последовательность воспроизведения на основе позиции персонажа:
function tick() {
// To slow down the animation loop of the sprite, we're not redrawing during each tick
// With a Modulo 4, we're dividing the speed by 4
var speedControl = Ticker.getTicks() % 4;
if (speedControl == 0) {
// Hit testing the screen width, otherwise our sprite would disappear
if (bmpSeq.x >= screen_width - 16) {
// We've reached the right side of our screen
// We need to walk left now to go back to our initial position
bmpSeq.direction = -90;
bmpSeq.gotoAndPlay("walk_left")
}
if (bmpSeq.x < 16) {
// We've reached the left side of our screen
// We need to walk right now
bmpSeq.direction = 90;
bmpSeq.gotoAndPlay("walk_right");
}
// Moving the sprite based on the direction & the speed
if (bmpSeq.direction == 90) {
bmpSeq.x += bmpSeq.vX;
bmpSeq.y += bmpSeq.vY;
}
else {
bmpSeq.x -= bmpSeq.vX;
bmpSeq.y -= bmpSeq.vY;
}
// update the stage:
stage.update();
}
}
Вы можете проверить окончательный результат здесь :
Вы также можете просмотреть этот пример здесь: easelJSSpritesTutorial02, если вы хотите просмотреть полный исходный код.
Урок 3: загрузка нескольких спрайтов и игра с несколькими анимациями
Пришло время загрузить состояние простоя монстра. Идея здесь состоит в том, чтобы воспроизвести состояние анимации для достижения единственного кругового обхода. Когда мы достигнем этого, мы будем играть в состоянии ожидания
Затем мы будем загружать несколько файлов PNG с веб-сервера. Тогда очень важно дождаться загрузки всех ресурсов, в противном случае вы можете попытаться нарисовать еще не загруженные ресурсы. Вот очень простой способ сделать это:
var numberOfImagesLoaded = 0;
var imgMonsterARun = new Image();
var imgMonsterAIdle = new Image();
function init() {
//find canvas and load images, wait for last image to load
canvas = document.getElementById("testCanvas");
imgMonsterARun.onload = handleImageLoad;
imgMonsterARun.onerror = handleImageError;
imgMonsterARun.src = "img/MonsterARun.png";
imgMonsterAIdle.onload = handleImageLoad;
imgMonsterAIdle.onerror = handleImageError;
imgMonsterAIdle.src = "img/MonsterAIdle.png";
}
function handleImageLoad(e) {
numberOfImagesLoaded++;
// We're not starting the game until all images are loaded
// Otherwise, you may start to draw without the resource and raise
// this DOM Exception: INVALID_STATE_ERR (11) on the drawImage method
if (numberOfImagesLoaded == 2) {
numberOfImagesLoaded = 0;
startGame();
}
}
Этот код очень прост. Например, он не обрабатывает ошибки должным образом, пытаясь повторно загрузить изображение в случае первого сбоя. Если вы создаете игру, вам нужно написать собственный менеджер загрузки контента, если используемая вами библиотека JS не реализует его.
Чтобы добавить последовательность простоя и установить параметры положения, нам просто нужно использовать тот же код, который мы видели ранее:
var spriteSheetIdle = new SpriteSheet(
imgMonsterAIdle, //image to use
64, //width of each sprite
64, //height of each sprite
{
idle: [0, 10]
});
bmpSeqIdle = new BitmapSequence(spriteSheetIdle);
bmpSeqIdle.name = "monsteridle1";
bmpSeqIdle.speed = 1;
bmpSeqIdle.direction = 0;
bmpSeqIdle.x = 16;
bmpSeqIdle.y = 32;
Теперь в методе tick () нам нужно остановить анимацию ходьбы, как только мы дойдем до левой стороны экрана, и вместо этого воспроизвести анимацию простоя. Вот код, который делает это:
if (bmpSeq.x < 16) {
// We've reached the left side of our screen
// We need to walk right now
bmpSeq.direction = 90;
bmpSeq.gotoAndStop("walk_left");
stage.removeChild(bmpSeq);
bmpSeqIdle.gotoAndPlay("idle");
stage.addChild(bmpSeqIdle);
}
Вы можете проверить окончательный результат здесь :
Вы также можете просмотреть этот образец здесь: easelJSSpritesTutorial03, если вы хотите просмотреть полный исходный код.
Это все, ребята! Но если вы хотите пойти дальше, вы можете прочитать следующую часть здесь: HTML5 Gaming: создание основных объектов и обработка коллизий с EaselJS
Дэвид

