import { Ball } from '../../entities/ball/ball'; import { Paddle } from '../../entities/paddle/paddle'; import { toRadians } from '../toRadians/toRadians'; /** * Проверяет произошло ли столкновение ракетки и мяча * @param {Paddle} paddle * @param {Ball} ball * @returns {boolean} */ function didCollide(paddle, ball) { return ( ball.verticalSpeed > 0 && ball.y + ball.radius >= paddle.y && ball.x >= paddle.x && ball.x <= paddle.x + paddle.width ); } /** * Изменяет направление полета мяча в зависимости от места попадания в ракетку * @param {Paddle} paddle экземпляр класса ракетка * @param {Ball} ball экземпляр класса мяч * @param {number} paddleSectorAmount количество секторов ракетки, положительное целое число * @param {number} minAngle минимальный угол отскока мяча (от 0 до 180) * @param {number} maxAngle максимальный угол отскока мяча (от 0 до 180) * @param {number} ballSpeed константа скорости мяча, положительное число */ export function processReflection(paddle, ball, paddleSectorAmount, minAngle, maxAngle, ballSpeed) { try { if (!(paddle instanceof Paddle)) { throw new Error('Аргумерт paddle должен являться экземпляром класса Paddle'); } if (!(ball instanceof Ball)) { throw new Error('Аргумерт ball должен являться экземпляром класса Ball'); } if (typeof paddleSectorAmount !== 'number' || paddleSectorAmount <= 0 || paddleSectorAmount % 1 !== 0) { throw new Error('Аргумент paddleSectorAmount должен являться положительным целым числом'); } if (typeof minAngle !== 'number' || minAngle < 0 || minAngle > 180) { throw new Error('Аргумент minAngle должен являться числом в промежутке от 0 до 180'); } if (typeof maxAngle !== 'number' || maxAngle < 0 || maxAngle > 180) { throw new Error('Аргумент maxAngle должен являться числом в промежутке от 0 до 180'); } if (minAngle >= maxAngle) { throw new Error('Значение аргумента maxAngle должено быть строго больше значения аргумента minAngle'); } if (typeof ballSpeed !== 'number' || ballSpeed <= 0) { throw new Error('Значение аргумента ballSpeed должно быть положительным целым числом'); } if (!didCollide(paddle, ball)) { return; } const step = paddle.width / paddleSectorAmount; const sectorIndex = Math.floor((ball.x - paddle.x) / step); const normalizedSectorIndex = Math.min(Math.max(sectorIndex, 0), paddleSectorAmount - 1); const angleStep = (maxAngle - minAngle) / (paddleSectorAmount - 1); const angleInRadians = toRadians(maxAngle - angleStep * normalizedSectorIndex); ball.horizontalSpeed = ballSpeed * Math.cos(angleInRadians); ball.verticalSpeed = -1 * ballSpeed * Math.sin(angleInRadians); ball.y = paddle.y - ball.radius; } catch (err) { console.error(err); return null; } }