Ball.js 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import { BALL_RADIUS, BALL_COLOR } from '../constants.js';
  2. /**
  3. * Ball - 小球实体
  4. * 由玩家发射,碰撞方块和边缘时反弹
  5. */
  6. export class Ball {
  7. /**
  8. * @param {number} x - 初始 x 坐标
  9. * @param {number} y - 初始 y 坐标
  10. * @param {number} [radius=BALL_RADIUS] - 半径
  11. * @param {string} [color=BALL_COLOR] - 颜色
  12. */
  13. constructor(x, y, radius = BALL_RADIUS, color = BALL_COLOR) {
  14. this.x = x;
  15. this.y = y;
  16. this.radius = radius;
  17. this.color = color;
  18. this.vx = 0;
  19. this.vy = 0;
  20. this.active = true;
  21. }
  22. /**
  23. * 每帧更新位置(子步移动,fraction 为 0~1 的比例)
  24. * 处理左/右/顶部边缘反弹,底部停止
  25. * @param {number} _deltaTime - 未使用,保留接口兼容
  26. * @param {number} boardWidth - 面板宽度
  27. * @param {number} boardHeight - 面板高度
  28. * @param {number} [fraction=1] - 移动比例(用于子步进防穿透)
  29. */
  30. update(_deltaTime, boardWidth, boardHeight, fraction = 1) {
  31. if (!this.active) return;
  32. // 移动 fraction 比例的距离
  33. this.x += this.vx * fraction;
  34. this.y += this.vy * fraction;
  35. // 左侧边缘反弹
  36. if (this.x - this.radius <= 0) {
  37. this.x = this.radius;
  38. this.reflect('x');
  39. }
  40. // 右侧边缘反弹
  41. if (this.x + this.radius >= boardWidth) {
  42. this.x = boardWidth - this.radius;
  43. this.reflect('x');
  44. }
  45. // 顶部边缘反弹
  46. if (this.y - this.radius <= 0) {
  47. this.y = this.radius;
  48. this.reflect('y');
  49. }
  50. // 底部:停止运动
  51. if (this.isAtBottom(boardHeight)) {
  52. this.y = boardHeight - this.radius;
  53. this.active = false;
  54. }
  55. }
  56. /**
  57. * 反射:反转指定轴的速度分量
  58. * @param {'x'|'y'} axis - 'x' 反转 vx,'y' 反转 vy
  59. */
  60. reflect(axis) {
  61. if (axis === 'x') {
  62. this.vx = -this.vx;
  63. } else if (axis === 'y') {
  64. this.vy = -this.vy;
  65. }
  66. }
  67. /**
  68. * 判断球是否到达底部
  69. * @param {number} boardHeight - 面板高度
  70. * @returns {boolean}
  71. */
  72. isAtBottom(boardHeight) {
  73. return this.y + this.radius >= boardHeight;
  74. }
  75. /**
  76. * 获取碰撞矩形(AABB)
  77. * @returns {{ x: number, y: number, width: number, height: number }}
  78. */
  79. getRect() {
  80. const diameter = this.radius * 2;
  81. return {
  82. x: this.x - this.radius,
  83. y: this.y - this.radius,
  84. width: diameter,
  85. height: diameter
  86. };
  87. }
  88. }