Feature/advanced game mechanics #5

Merged
ilia merged 30 commits from feature/advanced-game-mechanics into main 2026-07-19 15:09:22 +00:00
5 changed files with 33 additions and 9 deletions
Showing only changes of commit b7e16f86ea - Show all commits
+2
View File
@@ -2,6 +2,7 @@ export const CONTAINER_WIDTH = 800;
export const CONTAINER_HEIGHT = 600; export const CONTAINER_HEIGHT = 600;
export const PADDLE_WIDTH = 50; export const PADDLE_WIDTH = 50;
export const PADDLE_WIDE_WIDTH = 100;
export const PADDLE_HEIGHT = 10; export const PADDLE_HEIGHT = 10;
export const MIN_PADDLE_REFLECTION_ANGLE = 20; export const MIN_PADDLE_REFLECTION_ANGLE = 20;
export const MAX_PADDLE_REFLECTION_ANGLE = 160; export const MAX_PADDLE_REFLECTION_ANGLE = 160;
@@ -24,3 +25,4 @@ export const PERK_HEIGHT = 16;
export const PERK_FALL_SPEED = 3; export const PERK_FALL_SPEED = 3;
export const PERK_DROP_CHANCE = 0.3; export const PERK_DROP_CHANCE = 0.3;
export const PERK_BALL_SPEED_DECREASE = 2; export const PERK_BALL_SPEED_DECREASE = 2;
export const PERK_TYPES = ['slow', 'wide'];
+2 -7
View File
@@ -1,11 +1,6 @@
import { PERK_FALL_SPEED, PERK_HEIGHT, PERK_WIDTH } from '../../config'; import { PERK_FALL_SPEED, PERK_HEIGHT, PERK_TYPES, PERK_WIDTH } from '../../config';
import { Perk } from '../../entities/perk/perk'; import { Perk } from '../../entities/perk/perk';
/**
* Типы бонусов
*/
const DROPPABLE_PERKS = ['slow'];
/** /**
* Создает случайный бонус в заданной точке * Создает случайный бонус в заданной точке
* @param {number} x координата бонуса по оси X * @param {number} x координата бонуса по оси X
@@ -18,7 +13,7 @@ export function spawnRandomPerk(x, y) {
throw new Error('Координаты бонуса должны являться числами'); throw new Error('Координаты бонуса должны являться числами');
} }
const type = DROPPABLE_PERKS[Math.floor(Math.random() * DROPPABLE_PERKS.length)]; const type = PERK_TYPES[Math.floor(Math.random() * PERK_TYPES.length)];
return new Perk(x, y, PERK_WIDTH, PERK_HEIGHT, type, PERK_FALL_SPEED); return new Perk(x, y, PERK_WIDTH, PERK_HEIGHT, type, PERK_FALL_SPEED);
} catch (err) { } catch (err) {
+5 -1
View File
@@ -1,4 +1,4 @@
import { PERK_BALL_SPEED_DECREASE } from '../../config'; import { CONTAINER_WIDTH, PADDLE_WIDE_WIDTH, PERK_BALL_SPEED_DECREASE } from '../../config';
import { Game } from '../../game'; import { Game } from '../../game';
import { calculateCollision } from '../calculateCollision/calculateCollision'; import { calculateCollision } from '../calculateCollision/calculateCollision';
@@ -49,6 +49,10 @@ export function updatePerks(game, containerHeight, deltaTime) {
game.ball.increaseSpeed(-1 * PERK_BALL_SPEED_DECREASE); game.ball.increaseSpeed(-1 * PERK_BALL_SPEED_DECREASE);
} }
break; break;
case 'wide':
paddle.width = PADDLE_WIDE_WIDTH;
paddle.moveTo(paddle.x, 0, CONTAINER_WIDTH);
break;
default: default:
break; break;
} }
+12
View File
@@ -1,3 +1,4 @@
import { PADDLE_WIDE_WIDTH } from '../../config';
import { Perk } from '../../entities/perk/perk'; import { Perk } from '../../entities/perk/perk';
import { Game } from '../../game'; import { Game } from '../../game';
import { updatePerks } from './updatePerks'; import { updatePerks } from './updatePerks';
@@ -36,6 +37,17 @@ describe('updatePerks', () => {
expect(game.ball.speed).toBeLessThan(speedBefore); expect(game.ball.speed).toBeLessThan(speedBefore);
}); });
it('Ловит бонус wide, расширяет ракетку до фиксированной ширины', () => {
const game = new Game([[[1]]]);
const { paddle } = game;
game.perks.push(new Perk(paddle.x, paddle.y - 1, 10, 10, 'wide', 0));
updatePerks(game, 600, 1);
expect(game.perks).toHaveLength(0);
expect(paddle.width).toBe(PADDLE_WIDE_WIDTH);
});
it('Убирает бонус, улетевший за нижнюю границу', () => { it('Убирает бонус, улетевший за нижнюю границу', () => {
const game = new Game([[[1]]]); const game = new Game([[[1]]]);
game.perks.push(new Perk(0, 601, 10, 10, 'slow', 0)); game.perks.push(new Perk(0, 601, 10, 10, 'slow', 0));
+12 -1
View File
@@ -51,6 +51,8 @@ function createPerkView(perk) {
switch (perk.type) { switch (perk.type) {
case 'slow': case 'slow':
return perkView.fill('#00ffff'); return perkView.fill('#00ffff');
case 'wide':
return perkView.fill('#0f0f0f');
default: default:
return perkView.fill('#ffffff'); return perkView.fill('#ffffff');
} }
@@ -75,11 +77,13 @@ export function createGameView(game, container) {
return brickView; return brickView;
}); });
const perks = new Map();
return { return {
ball, ball,
paddle, paddle,
bricks, bricks,
perks: new Map(), perks,
}; };
} catch (err) { } catch (err) {
console.error(err); console.error(err);
@@ -94,6 +98,13 @@ export function createGameView(game, container) {
* @param {Container} container экземпляр класса контейнер Pixi.js * @param {Container} container экземпляр класса контейнер Pixi.js
*/ */
export function managePerkViewsLifetime(views, game, container) { export function managePerkViewsLifetime(views, game, container) {
if (views.paddle.width !== game.paddle.width) {
container.removeChild(views.paddle);
views.paddle.destroy();
views.paddle = createPaddleView(game.paddle);
container.addChild(views.paddle);
}
for (const [perk, perkView] of views.perks) { for (const [perk, perkView] of views.perks) {
if (!game.perks.includes(perk)) { if (!game.perks.includes(perk)) {
container.removeChild(perkView); container.removeChild(perkView);