class Ball { constructor() { this.size = 10; this.moving = false; this.speed = 7; // this.angle = 90; this.setAngle(180 + 60, 360 - 60); this.color = 'red'; this.limits = null; this.angleTR = this.g2r(360); this.angleBR = this.g2r(90); this.angleBL = this.g2r(180); this.angleTL = this.g2r(270); } start() { this.moving = true; } update(ctx, x, y) { this.limits ??= { l: this.size, t: this.size, r: ctx.canvas.width - this.size, b: ctx.canvas.height }; if (this.move(x, y)) { this.draw(ctx); return true; } return false; } draw(ctx) { ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, 2 * Math.PI, false); ctx.fillStyle = this.color; ctx.fill(); ctx.lineWidth = 1; ctx.strokeStyle = '#003300'; ctx.stroke(); } move(x, y) { if (this.moving) { this.x += this.speed * Math.cos(this.angle); this.y += this.speed * Math.sin(this.angle); // Escaped from the pad if (this.y > this.limits.b) { this.moving = false; return false; } this.collideWalls(this.limits.l, this.limits.t, this.limits.r, this.limits.b); } else { this.x = x; this.y = y - this.size - 1; } return true; } bounceL(r) { if (this.angle <= this.angleBL) this.setAngle(0 + r, 90 - r); else this.setAngle(270 + r, 360 - r); } bounceR(r) { if (this.angle <= this.angleBR) this.setAngle(90 + r, 180 - r); else this.setAngle(180 + r, 270 - r); } bounceT(r) { if (this.angle <= this.angleTL) this.setAngle(90 + r, 180 - r); else this.setAngle(0 + r, 90 - r); } bounceB(r) { if (this.angle <= this.angleBR) this.setAngle(270 + r, 360 - r); else this.setAngle(180 + r, 270 - r); } collideWalls(x0, y0, x1, y1) { let r = 20; if (this.x <= x0) { this.bounceL(r); return true; } if (this.x >= x1) { this.bounceR(r); return true; } if (this.y <= y0) { this.bounceT(r); return true; } if (this.y >= y1) { this.bounceB(r); return true; } return false; } /* TL 270 TR 180 0 BL 90 BR B --------- R | | L --------- T */ collide(x0, y0, x1, y1) { // 0 = hit Left/Right, 1 = hit Up/Down let r = 20; if (this.x >= x0 && this.x <= x1) { if ((this.y + this.size) >= y0 && (this.y + this.size) < y1) { this.bounceB(r); return true; } if ((this.y - this.size) <= y1 && (this.y - this.size) > y0) { this.bounceT(r); return true; } } if (this.y >= y0 && this.y <= y1) { if ((this.x + this.size) >= x0 && (this.x + this.size) < x1) { this.bounceR(r); return true; } if ((this.x - this.size) <= x1 && (this.x - this.size) > x0) { this.bounceL(r); return true; } } return false; } setAngle(min, max) { this.angle = this.g2r(Math.floor(Math.random() * (max - min)) + min); } g2r(deg) { return (((360 + deg) % 360) * Math.PI) / 180.0; } r2g(rad) { return rad * 180 / Math.PI; } }