Добрый день, уважаемые читатели!
Сегодня мы продолжаем писать нашу игру на canvas. И теперь мы переходим к самому интересному — атаке.
В данной статье мы сделаем:
- Анимацию игрока во время атаки
- Добавим возможность атаковать
- Добавим сам снаряд, которым атакует игрок
- Местами поправим наш код
Поехали!
Анимация игрока во время атаки
Прежде всего я обновил файл с анимациями игрока и добавил новые кадры атаки, а заодно и стрелу, которой будет атаковать наш игрок:

Теперь пропишем анимацию атаки в коде.
animationsPlayer = {
...
attackRight: [
371, 20, 50, 51,
435, 20, 50, 51,
547, 20, 50, 51
],
attackLeft: [
378, 79, 50, 51,
435, 79, 50, 51,
488, 79, 50, 51
]
};
Готово.
Внесем сразу несколько переменных, которые нам понадобятся для стрельбы:
var canvasWidth = 600,//window.innerWidth; canvasHeight = 500,//window.innerHeight; direction = 'right', // изменили начальное значение arrowDirection = '', arrowSpeed = 6, wizardSpeed = 0.5, wizards = [], lights = [], // массив объектов молний arrows = [], health = 100, lastFire = Date.now(); // для расчета стрельбы
Переменная lastFire понадобится для того, чтобы ограничить стрельбу игрока по времени.
Добавим игроку стрел:
player.speed = 3; player.sizeX = 50; player.sizeY = 50; player.arrows = 100;
Выведем на экран количество стрел:
var gameLoop = new Konva.Animation(function(frame) {
...
simpleText.setAttr('text', 'Молний: ' + lights.length + ", Магов на карте: " + wizards.length + ' Здоровье: ' + Math.floor(health) + ", Стрел: " + player.arrows);
...
}, layer);
Добавим возможность атаковать
Добавим возможность стрельбы по нажатию пробела. Здесь ничего сложного, если у игрока есть стрелы и с последнего выстрела прошло больше 500 мсек, то производим выстрел.
Для определения куда, полетит стрела мы добавим условие на проверку direction.
function handleInput() {
if (player.attrs.animation == 'attackRight' ||
player.attrs.animation == 'attackLeft') {
animationAttack();
return;
}
...
if (direction == 'left') {
player.attrs.animation = 'idleLeft';
}
if(input.isDown('DOWN') || input.isDown('s')) {
if (player.attrs.y + player.speed < canvasHeight - player.sizeY) {
...
direction = 'right';
}
}
if(input.isDown('UP') || input.isDown('w')) {
if (player.attrs.y - player.speed > 0) {
...
direction = 'left';
}
}
...
if(input.isDown('SPACE') &&
Date.now() - lastFire > 500 && player.arrows > 0) {
player.attrs.animation = 'attackLeft';
if (direction == 'right') {
player.attrs.animation = 'attackRight';
}
player.frameIndex(0);
}
}
В самом начале фунции мы проверяем, если игрок уже атакует, то мы запрещаем ему двигаться и выходим из функции по return. Сейчас займемся написанием функции animationAttack.
function animationAttack() {
if (player.frameIndex() >= 2) {
makeBullet('arrow');
}
}
Здесь по наступлению 3 фрейма анимации мы создаем стрелу.
Код для создания стрелы ниже:
function makeBullet(type, x, y) {
if (type == 'light') {
...
// add the shape to the layer
layer.add(light);
// add the layer to the stage
stage.add(layer);
// start sprite animation
light.start();
}
if (type == 'arrow') {
var x = player.attrs.x;
var y = player.attrs.y;
var arrow = new Konva.Image({
x: player.attrs.x + 25,
y: player.attrs.y + 20,
image: playerImg,
width: 30,
height: 10
});
// вырезаем стрелу из изображения игрока
arrow.crop({
x: 7,
y: 150,
width: 30,
height: 10
});
arrow.direction = 'left';
player.attrs.animation = 'idleLeft';
if (direction == 'right') {
arrow.direction = 'right';
player.attrs.animation = 'idleRight';
arrow.crop({
x: 7,
y: 137,
width: 30,
height: 10
});
}
player.arrows--;
player.frameIndex(0);
arrows.push(arrow);
// add the shape to the layer
layer.add(arrow);
// add the layer to the stage
stage.add(layer);
lastFire = Date.now();
}
}
В начале мы внесли код добавления молнии в условие if (type == ‘light’). Далее дописали добавление стрелы. Механизм такой же, как и для молнии. Только, чтобы получить статическое изображение стрелы, мы обрезали изображение игрока и оставили только область со стрелой. Причем в зависимости от направления стрелы меняется область для вырезания.
По направлению игрока мы определяем направление полета стрелы. Далее уменьшаем количество стрел у игрока и добавляем стрелы в массив стрел.
И самое важное, чтобы игрок не стрелял, как из пулемета мы обновляем переменную lastFire, которую объявляли ранее. Вот тут она и пригодилась.
Летящая стрела
Когда мы создали стрелу, ее необходимо анимировать.
function moveBullet() {
...
// Update all the arrows
for(var i = 0; i < arrows.length; i++) {
var arrow = arrows[i];
switch(arrow.direction) {
case 'right': arrow.setX(arrow.attrs.x + arrowSpeed);
break;
default:
arrow.setX(arrow.attrs.x - arrowSpeed);
}
// удаляем стрелы за экраном
if (arrow.attrs.x < 0 || arrow.attrs.x > canvasWidth) {
arrows.splice(i, 1);
arrow.setX(-1000);
i--;
}
}
}
Тут по сути ничего сложного. Каждый игровой цикл вызывается функция moveBullet, которая перебирает все стрелы и обновляет их координаты в зависимости от направления полета стрелы.
Если стрелы вышла за пределы экрана, то мы ее удаляем из массива стрел и забываем про нее.
Вот, что у нас получилось в итоге:

Как вы заметили выше, я убрал зеленый фон у молний 🙂 Так гораздо лучше 🙂

На сегодня на этом остановимся. И в следующий раз мы займемся попаданием стрел во врага.
Подписывайтесь на рассылку 😉 Дальше интересней!
Если вопросы/пожелания? Пишите в комментарии.
Всем спасибо за внимание.