feat: Добавлена обработка столкновения ракетки и бонуса, логика обработки бонусов подключена в tick
This commit is contained in:
@@ -4,11 +4,16 @@ import {
|
||||
MAX_PADDLE_REFLECTION_ANGLE,
|
||||
MIN_PADDLE_REFLECTION_ANGLE,
|
||||
PADDLE_SECTOR_AMOUNT,
|
||||
PERK_DROP_CHANCE,
|
||||
PERK_HEIGHT,
|
||||
PERK_WIDTH,
|
||||
} from '../../config';
|
||||
import { Game } from '../../game';
|
||||
import { calculateCollision } from '../calculateCollision/calculateCollision';
|
||||
import { calculateDirection } from '../calculateDirection/calculateDirection';
|
||||
import { processReflection } from '../processReflection/processReflection';
|
||||
import { spawnRandomPerk } from '../spawnRandomPerk/spawnRandomPerk';
|
||||
import { updatePerks } from '../updatePerks/updatePerks';
|
||||
|
||||
/**
|
||||
* Функция для вычисления взаимодействий сущностей игры в зависимости от времени из Ticker
|
||||
@@ -39,6 +44,9 @@ export function tick(game, containerWidth, containerHeight, deltaTime) {
|
||||
|
||||
ball.moveForward(deltaTime);
|
||||
|
||||
// Бонусы падают и ловятся ракеткой каждый кадр
|
||||
updatePerks(game, containerHeight, deltaTime);
|
||||
|
||||
const leftBoundary = ball.radius;
|
||||
const rightBoundary = containerWidth - ball.radius;
|
||||
const topBoundary = ball.radius;
|
||||
@@ -92,6 +100,17 @@ export function tick(game, containerWidth, containerHeight, deltaTime) {
|
||||
ball.horizontalSpeed *= directions[0];
|
||||
ball.verticalSpeed *= directions[1];
|
||||
brick.kill();
|
||||
|
||||
if (!brick.alive) {
|
||||
if (Math.random() < PERK_DROP_CHANCE) {
|
||||
const perk = spawnRandomPerk(
|
||||
brick.x + brick.width / 2 - PERK_WIDTH / 2,
|
||||
brick.y + brick.height / 2 - PERK_HEIGHT / 2,
|
||||
);
|
||||
game.perks.push(perk);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import { PERK_BALL_SPEED_DECREASE } from '../../config';
|
||||
import { Game } from '../../game';
|
||||
import { calculateCollision } from '../calculateCollision/calculateCollision';
|
||||
|
||||
/**
|
||||
* Обновляет состояние бонусов, меняет положение, проверяет столкновение с ракеткой и выход за границу поля
|
||||
* @param {Game} game экземпляр класса игры
|
||||
* @param {number} containerHeight высота игрового контейнера в пикселях
|
||||
* @param {number} deltaTime изменение времени из Ticker
|
||||
*/
|
||||
export function updatePerks(game, containerHeight, deltaTime) {
|
||||
try {
|
||||
if (!(game instanceof Game)) {
|
||||
throw new Error('Аргумент game должен быть экземпляром класса игры');
|
||||
}
|
||||
|
||||
if (typeof containerHeight !== 'number' || containerHeight <= 0) {
|
||||
throw new Error('Высота игрового контейнера должна быть положительным числом');
|
||||
}
|
||||
|
||||
if (typeof deltaTime !== 'number' || deltaTime <= 0) {
|
||||
throw new Error('Значение изменения времени должно быть положительным числом');
|
||||
}
|
||||
|
||||
const { paddle } = game;
|
||||
|
||||
for (const perk of game.perks) {
|
||||
perk.moveForward(deltaTime);
|
||||
|
||||
const perkObject = {
|
||||
left: perk.x,
|
||||
right: perk.x + perk.width,
|
||||
top: perk.y,
|
||||
bottom: perk.y + perk.height,
|
||||
};
|
||||
const paddleObject = {
|
||||
left: paddle.x,
|
||||
right: paddle.x + paddle.width,
|
||||
top: paddle.y,
|
||||
bottom: paddle.y + paddle.height,
|
||||
};
|
||||
|
||||
const isCollided = calculateCollision(perkObject, paddleObject);
|
||||
|
||||
if (isCollided) {
|
||||
switch (perk.type) {
|
||||
case 'slow':
|
||||
if (game.ball.speed - PERK_BALL_SPEED_DECREASE > 0) {
|
||||
game.ball.increaseSpeed(-1 * PERK_BALL_SPEED_DECREASE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
perk.alive = false;
|
||||
} else if (perk.y > containerHeight) {
|
||||
perk.alive = false;
|
||||
}
|
||||
}
|
||||
|
||||
game.perks = game.perks.filter((perk) => perk.alive);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { Perk } from '../../entities/perk/perk';
|
||||
import { Game } from '../../game';
|
||||
import { updatePerks } from './updatePerks';
|
||||
|
||||
describe('updatePerks', () => {
|
||||
it('Возвращает корректное значение при неверных типах аргументов', () => {
|
||||
const game = new Game([[[1]]]);
|
||||
|
||||
expect(updatePerks(null, 100, 1)).toBeNull();
|
||||
expect(updatePerks(game, null, 1)).toBeNull();
|
||||
expect(updatePerks(game, -1, 1)).toBeNull();
|
||||
expect(updatePerks(game, 100, null)).toBeNull();
|
||||
expect(updatePerks(game, 100, -1)).toBeNull();
|
||||
});
|
||||
|
||||
it('Двигает бонус вниз в зависимости от времени', () => {
|
||||
const game = new Game([[[1]]]);
|
||||
const perk = new Perk(500, 10, 10, 10, 'slow', 3);
|
||||
game.perks.push(perk);
|
||||
|
||||
updatePerks(game, 600, 1);
|
||||
|
||||
expect(perk.y).toBe(13);
|
||||
expect(game.perks).toContain(perk);
|
||||
});
|
||||
|
||||
it('Ловит бонус ракеткой, применяет эффект и убирает его', () => {
|
||||
const game = new Game([[[1]]]);
|
||||
const speedBefore = game.ball.speed;
|
||||
const { paddle } = game;
|
||||
game.perks.push(new Perk(paddle.x, paddle.y - 1, 10, 10, 'slow', 0));
|
||||
|
||||
updatePerks(game, 600, 1);
|
||||
|
||||
expect(game.perks).toHaveLength(0);
|
||||
expect(game.ball.speed).toBeLessThan(speedBefore);
|
||||
});
|
||||
|
||||
it('Убирает бонус, улетевший за нижнюю границу', () => {
|
||||
const game = new Game([[[1]]]);
|
||||
game.perks.push(new Perk(0, 601, 10, 10, 'slow', 0));
|
||||
|
||||
updatePerks(game, 600, 1);
|
||||
|
||||
expect(game.perks).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user