class Ball { constructor(game, cx, cy, v, dir) { this.game = game; this.id = this.game.balls.length; this.cx = cx; this.cy = cy; this.vx = v * Math.cos(dir); this.vy = v * Math.sin(dir); this.collide = true; } update(stepCount = 10) { if (!this.game.isMoving) return; for (let i = 0; i < stepCount; i++) { this.cx += this.vx / stepCount; this.cy -= this.vy / stepCount; if (this.cx - this.game.ballRadius <= 0 || this.cx + this.game.ballRadius >= this.game.canvas.width) { this.vx *= -1; } if (this.cy - this.game.ballRadius <= 0) { this.vy *= -1; } if (this.cy >= this.game.originY && this.vy < 0) { this.vy = 0; this.cy = this.game.originY; if (this.game.newOriginX === null || this.cx === this.game.newOriginX) { this.game.newOriginX = this.cx; this.vy = 0; this.remove(); } else { this.vx = (this.game.newOriginX - this.cx) / 60 * 2; setTimeout(() => { this.vx = 0; this.remove(); }, 500); } } if (this.collide) { this.game.rects.forEach(rect => { this.checkHitRect(rect); }); this.game.powerUps.forEach(powerUp => { this.checkHitPowerUp(powerUp); }); } } } remove() { this.game.balls.splice(this.game.balls.findIndex(ball => ball === this), 1); if (this.game.isMoving && this.game.balls.length === 0) { this.game.roundOver(); } } checkHitRect(rect) { const closestX = Math.clamp(this.cx, rect.x, rect.x + this.game.rectSize); const closestY = Math.clamp(this.cy, rect.y, rect.y + this.game.rectSize); const distX = this.cx - closestX; const distY = this.cy - closestY; const distSquared = (distX ** 2) + (distY ** 2); if (distSquared < this.game.ballRadius ** 2) { const collBottom = rect.y + this.game.rectSize - (this.cy - this.game.ballRadius); const collTop = (this.cy + this.game.ballRadius) - rect.y; const collLeft = (this.cx + this.game.ballRadius) - rect.x; const collRight = rect.x + this.game.rectSize - (this.cx - this.game.ballRadius); if ((collTop <= collLeft && collTop <= collRight) || (collBottom <= collLeft && collBottom <= collRight)) { this.vy *= -1; } else { this.vx *= -1; } rect.hit(this); } } checkHitPowerUp(powerUp) { const distX = this.cx - powerUp.cx; const distY = this.cy - powerUp.cy; const distSquared = (distX ** 2) + (distY ** 2); if (distSquared < (this.game.ballRadius + this.game.powerUpRadius) ** 2) { powerUp.hit(); } } draw() { this.game.ctx.fillStyle = '#fff'; this.game.ctx.beginPath(); this.game.ctx.arc(this.cx, this.cy, this.game.ballRadius, 0, 2 * Math.PI); this.game.ctx.fill(); } }