Разработка игры на Canvas, часть 6. Смерть врагам

Здравствуйте, уважаемые читатели!Html5_canvas_logo

Продолжаем делать нашу игру на canvas. Осталось уже совсем немного.

В этой статье мы рассмотрим следующие моменты:

  1. Добавим немного декораций
  2. Создадим возможность подбирать стрелы и аптечки
  3. Научим наших врагов умирать от наших стрел
  4. Создадим простой скрипт усложнения игры

Поехали!

 

Смерть врагов

Начнем с самого интересного на мой взгляд. Добавим новую анимацию для врагов и заставим их умирать при попадании в них стрелы. А так же добавим анимацию атаки в левую сторону.

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
  ]
};

wizard-die

 

Так как враги могут теперь умереть, то изменим код для движения врагов. Если враг умирает, то он не может двигаться. Логика 🙂

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';

А вот, как это будет выглядеть:

js-canvas-arrows-hearts

 

Создадим функцию для добавления наших аптечек и стрел.

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('Вы умерли');
	}
	
}

 

Немного декораций

Напоследок добавим немного украшений на наше поле боя.

js-canvas-arrows-hearts-grass

 

В функцию 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));
}

 

Пожалуй, на этом остановимся.

По сути уже все готово. Осталось лишь доделать смерть игрока.

Жду Вас в следующей, завершающей, статье.

 

Прикладываю исходники и ссылку на демо.

 

 

 

Автор статьи: Alex. Категория: JavaScript
Дата публикации: 14.10.2015