Здравствуйте, уважаемые читатели!
Продолжаем делать нашу игру на canvas. Осталось уже совсем немного.
В этой статье мы рассмотрим следующие моменты:
- Добавим немного декораций
- Создадим возможность подбирать стрелы и аптечки
- Научим наших врагов умирать от наших стрел
- Создадим простой скрипт усложнения игры
Поехали!
Смерть врагов
Начнем с самого интересного на мой взгляд. Добавим новую анимацию для врагов и заставим их умирать при попадании в них стрелы. А так же добавим анимацию атаки в левую сторону.
var animationsWizard = {
...
attackLeft: [
25, 327, 48, 67,
123, 327, 48, 67,
221, 327, 48, 67,
319, 327, 48, 67,
417, 327, 48, 67,
515, 327, 48, 67,
613, 327, 48, 67,
711, 327, 48, 67,
809, 327, 48, 67,
907, 327, 48, 67,
1005, 327, 48, 67,
1103, 327, 48, 67
],
attackRight: [
25, 250, 48, 67,
123, 250, 48, 67,
221, 250, 48, 67,
319, 250, 48, 67,
417, 250, 48, 67,
515, 250, 48, 67,
613, 250, 48, 67,
711, 250, 48, 67,
809, 250, 48, 67,
907, 250, 48, 67,
1005, 250, 48, 67,
1103, 250, 48, 67
],
die: [
2, 460, 48, 50,
54, 460, 48, 50,
104, 460, 48, 50,
154, 460, 48, 50,
204, 460, 48, 50,
254, 460, 48, 50
]
};
![]()
Так как враги могут теперь умереть, то изменим код для движения врагов. Если враг умирает, то он не может двигаться. Логика 🙂
function moveEnemies() {
wizards.forEach(function(wizard) {
if (wizard.action != 'makeLight' && wizard.action != 'die') {
...
}
В начале игры теперь сделаем только 1 врага:
makeEnemy('wizard', -30, 200);
А так же уберем начальные молнии:
//makeBullet('light', 100, 100);
//makeBullet('light', 400, 100);
Далее преобразуем наш код для столкновения стрелы с врагом. Правки существенны, поэтому полностью заменяем нашу функцию checkCollisions() на следующую:
function checkCollisions() {
var i, j,
pos = [],
posPlayer = [],
size = [],
sizePlayer = [],
enemyPos = [],
enemySize = [];
posPlayer[0] = player.attrs.x;
posPlayer[1] = player.attrs.y;
enemySize[0] = 50;
enemySize[1] = 50;
sizePlayer[0] = 50; // размер игрока
sizePlayer[1] = 50;
for(i = 0; i < lights.length; i++) {
enemyPos[0] = lights[i].attrs.x;
enemyPos[1] = lights[i].attrs.y;
if (lights[i].frameIndex() > 3) {
if (boxCollides(enemyPos, enemySize, posPlayer, sizePlayer)) {
getHealth(-1);
}
}
}
size[0] = 20; // размер стрелы
size[1] = 20;
if (arrows.length) {
for(i = 0; i < arrows.length; i++) {
pos[0] = arrows[i].attrs.x; // позиция стрелы
pos[1] = arrows[i].attrs.y;
for (j = 0; j < wizards.length; j++) {
enemyPos[0] = wizards[j].attrs.x; // позиция мага
enemyPos[1] = wizards[j].attrs.y;
if (wizards[j].action != 'die') {
if (boxCollides(enemyPos, enemySize, pos, size)) {
console.log('Стрела задела мага');
arrows[i].setX(-1000);
arrows.splice(i, 1);
wizards[j].action = 'die';
wizards[j].attrs.animation = 'die';
wizards[j].frameIndex(0);
}
}
}
}
}
}
При любом попадании стрелы наш противник умирает. При этом его action переключается на die. И пока идет процесс его смерти мы будем видеть анимацию смерти мага.
Анимацию для смерти мага мы уже прописали выше 🙂
Теперь займемся именно смертью мага:
function actEnemies() {
for(i = 0; i < wizards.length; i++) {
wizards[i].mana++;
if (wizards[i].mana > 200 && wizards[i].attrs.animation == 'idleLeft') {
wizards[i].action = 'makeLight';
wizards[i].attrs.animation = 'attackLeft';
wizards[i].setY(wizards[i].attrs.y - 18);
wizards[i].mana -= 200;
wizards[i].frameIndex(0);
}
if (wizards[i].mana > 200 && wizards[i].attrs.animation == 'idleRight') {
wizards[i].action = 'makeLight';
wizards[i].attrs.animation = 'attackRight';
wizards[i].setY(wizards[i].attrs.y - 18);
wizards[i].mana -= 200;
wizards[i].frameIndex(0);
}
// кастование молнии
if (wizards[i].action == 'makeLight' && wizards[i].frameIndex() > 10) {
wizards[i].setY(wizards[i].attrs.y + 18);
makeBullet('light', Math.floor((Math.random() * 200) + player.attrs.x- 100), Math.floor((Math.random() * 200) + player.attrs.y - 100));
wizards[i].action = 'stay';
wizards[i].frameIndex(0);
}
if (wizards[i].action == 'die' && wizards[i].frameIndex() > 4) {
wizards[i].setX(-1000);
wizards.splice(i, 1);
score += 100;
updateDifficult();
}
}
}
Здесь мы добавили атакую магом влево и проверку анимации смерти. Если идет 4 кадр анимации, то мы убираем противника с поля и удаляем его из массива врагов.
Так же я добавил функцию сложности updateDifficult(). Ниже посмотрим, что она делает.
Скрипт усложнения игры
function updateDifficult () {
if (score > 300) {
countEnemies = 3;
}
if (score > 600) {
countEnemies = 5;
}
if (score > 1000) {
countEnemies = 7;
}
while (wizards.length < countEnemies) {
if (getRandomInt(0, 1)) {
makeEnemy('wizard', -50, getRandomInt(50, 450));
}
else {
makeEnemy('wizard', 600, getRandomInt(50, 450));
}
}
}
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
Функция в зависимости того, сколько мы заработали очков, изменяет определенное возможное количество магов на карте.
Только не забываем, что мы использовали новые переменные (например, score), которые нужно добавить в самом начале в блок переменных.
var canvasWidth = 600,//window.innerWidth;
...
lastFire = Date.now(), // для расчета стрельбы
score = 0,
countEnemies = 2,
hearts = [],
amos = []; // подбираемые стрелы
Подбираем стрелы и аптечки
Позаботимся теперь об амуниции. Добавим в игру аптечки для восстановления здоровья и стрелы для пополнения запаса.
Для стрел и аптечек я подготовил отдельные изображения. Загрузим их в коде:
var heartImg = new Image();
heartImg.src = 'heart.png';
var arrowImg = new Image();
arrowImg.src = 'arrows.png';
А вот, как это будет выглядеть:

Создадим функцию для добавления наших аптечек и стрел.
makeObject('heart', getRandomInt(20, 550), getRandomInt(20, 450));
makeObject('arrow', getRandomInt(20, 550), getRandomInt(20, 450));
function makeObject(type, x, y) {
var heart,
amo, // стрелы
grass;
if (type == 'heart') {
heart = new Konva.Image({
x: x,
y: y,
image: heartImg,
width: 35,
height: 27
});
hearts.push(heart);
// add the shape to the layer
layer.add(heart);
// add the layer to the stage
stage.add(layer);
}
if (type == 'arrow') {
amo = new Konva.Image({
x: x,
y: y,
image: arrowImg,
width: 30,
height: 15
});
amos.push(amo);
// add the shape to the layer
layer.add(amo);
// add the layer to the stage
stage.add(layer);
}
}
Все аналогично с добавлением врагов.
А теперь обновим функцию checkCollisition() и добавим возможность подбора игроком аптечек и стрел. Как только игрок что-то поднял, тут же на карте в случайном месте появляется еще 1 комплект предметов:
function checkCollision() {
...
size[0] = 35; // размер сердца
size[1] = 27;
if (hearts.length) {
for(i = 0; i < hearts.length; i++) {
pos[0] = hearts[i].attrs.x; // позиция стрелы
pos[1] = hearts[i].attrs.y;
if (boxCollides(pos, size, posPlayer, sizePlayer)) {
hearts[i].setX(-1000);
hearts.splice(i, 1);
getHealth(25);
makeObject('heart', getRandomInt(20, 550), getRandomInt(20, 450));
}
}
}
size[0] = 30; // размер стрелы на поле
size[1] = 15;
if (amos.length) {
for(i = 0; i < amos.length; i++) {
pos[0] = amos[i].attrs.x; // позиция стрелы
pos[1] = amos[i].attrs.y;
if (boxCollides(pos, size, posPlayer, sizePlayer)) {
amos[i].setX(-1000);
amos.splice(i, 1);
player.arrows += 2;
makeObject('arrow', getRandomInt(20, 550), getRandomInt(20, 450));
}
}
}
}
Функцию увеличения здоровья я так же немного поменял:
function getHealth(count) {
health += count;
if (health > 100) {
health = 100;
}
if (health <= 0) {
console.log('Вы умерли');
}
}
Немного декораций
Напоследок добавим немного украшений на наше поле боя.

В функцию makeObject добавим немного кода для добавления травы:
function makeObject(type, x, y) {
var heart,
amo, // стрелы
grass;
...
if (type == 'grass') {
grass = new Konva.Image({
x: x,
y: y,
image: grassImg,
width: 40,
height: 42
});
// add the shape to the layer
layer.add(grass);
// add the layer to the stage
stage.add(layer);
grass.moveToBottom();
layer.draw();
}
}
И при старте игры в цикле прогоним создание 10 кустов на поле в случайном месте.
for (var g = 0; g < 10; g++) {
makeObject('grass', getRandomInt(20, 550), getRandomInt(20, 450));
}
Пожалуй, на этом остановимся.
По сути уже все готово. Осталось лишь доделать смерть игрока.
Жду Вас в следующей, завершающей, статье.
Прикладываю исходники и ссылку на демо.