Обнаружение столкновений
Это 7 шаг из 10 в Gamedev Canvas tutorial. Вы можете найти исходный код, как он будет выглядеть после завершения этого урока, тут Gamedev-Canvas-workshop/lesson7.html.
У нас уже есть кирпичи, появляющиеся на экране, но игра все ещё не так интересна, ведь мяч проходит сквозь них. Нам нужно подумать о добавлении обнаружения столкновений, чтобы он мог отскакивать от кирпичей и ломать их.
Конечно, это наше решение, как реализовать это, но может быть сложно рассчитать, касается ли шар прямоугольника или нет, потому что в Canvas нет вспомогательных функций для этого. В этом уроке мы сделаем это самым простым способом. Мы проверим, сталкивается ли центр мяча с любым из данных кирпичей. Это не идеальное решение на все случаи жизни, и есть намного более сложные и эффективные способы обнаружения столкновений, но это научит вас основным понятиям.
Функция обнаружения столкновения
Мы хотим создать функцию обнаружения столкновений, которая будет перебирать все кирпичи и сравнивать позицию каждого кирпича с координатами шара при каждой отрисовке кадра. Для лучшей читаемости кода определим переменную b
, чтобы хранить объект кирпича в цикле обнаружения столкновения:
function collisionDetection() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
// calculations
}
}
}
Если центр шара находится внутри координат одного из наших кирпичей, мы изменим направление шара. Для того, чтобы центр шара находился внутри кирпича, все четыре из следующих утверждений должны быть верны:
- Координата X шара больше, чем координата X кирпича.
- Координата X шара меньше, чем X-координата кирпича плюс его ширина.
- Координата Y шара больше, чем Y-координата кирпича.
- Координата Y шара меньше, чем Y-координата кирпича плюс его высота.
Давайте напишем это в коде:
function collisionDetection() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (x > b.x && x < b.x + brickWidth && y > b.y && y < b.y + brickHeight) {
dy = -dy;
}
}
}
}
Добавьте вышеприведённый блок к вашему коду под keyUpHandler()
функцией .
Удаление кирпичей после их попадания
Вышеприведённый код будет работать, как и задумано, и мяч изменит своё направление. Проблема в том, что кирпичи остаются на своих местах. Мы должны придумать, как избавляться от тех, в которые мы уже попали мячом. Мы можем сделать это, добавив дополнительный параметр кирпичам, определяющий, будет ли кирпич отрисовываться на экране или нет. В той части кода, где мы инициализируем кирпичи, добавим свойство status
к каждому кирпичному объекту. Обновите следующую часть кода, как показано ниже:
var bricks = [];
for (var c = 0; c < brickColumnCount; c++) {
bricks[c] = [];
for (var r = 0; r < brickRowCount; r++) {
bricks[c][r] = { x: 0, y: 0, status: 1 };
}
}
Теперь мы будем проверять значение свойства status
каждого кирпича в функции drawBricks()
перед его рисованием - если status
равен 1
, нарисуем его, а если равен 0
, то значит в него попал мяч и он не должен больше отрисовываться. Отредактируйте drawBricks()
следующим образом:
function drawBricks() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
if (bricks[c][r].status == 1) {
var brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
var brickY = r * (brickHeight + brickPadding) + brickOffsetTop;
bricks[c][r].x = brickX;
bricks[c][r].y = brickY;
ctx.beginPath();
ctx.rect(brickX, brickY, brickWidth, brickHeight);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
}
}
}
Отслеживание и обновление состояния в функции обнаружения столкновений
Теперь нам нужно задействовать свойство status
кирпича в функции collisionDetection()
: если кирпич активен (его статус равен 1
), мы проверяем, было ли столкновение; если да, мы устанавливаем статус данного кирпича равным 0
, чтобы он не был нарисован на экране. Отредактируйте функцию collisionDetection()
, как показано ниже:
function collisionDetection() {
for (var c = 0; c < brickColumnCount; c++) {
for (var r = 0; r < brickRowCount; r++) {
var b = bricks[c][r];
if (b.status == 1) {
if (
x > b.x &&
x < b.x + brickWidth &&
y > b.y &&
y < b.y + brickHeight
) {
dy = -dy;
b.status = 0;
}
}
}
}
}
Активация нашего обнаружения столкновений
Последнее, что нужно сделать, это добавить вызов функции collisionDetection()
в нашу основную функцию draw()
. Добавьте следующую строку в функцию draw()
, чуть ниже drawPaddle()
:
collisionDetection();
Сравните свой код
Обнаружение столкновения шара теперь выполняется на каждом кадре и для каждого кирпича. Теперь мы можем ломать кирпичи! : -
Примечание: Измените цвет шара, когда он ударит по кирпичу.
Следующие шаги
Мы уверенно движемся вперёд! Поехали! В восьмой главе мы будем учиться отслеживать счёт и выигрывать.