Здравствуйте, уважаемые читатели!
Продолжаем делать нашу игру на 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)); }
Пожалуй, на этом остановимся.
По сути уже все готово. Осталось лишь доделать смерть игрока.
Жду Вас в следующей, завершающей, статье.
Прикладываю исходники и ссылку на демо.