85 lines
3.0 KiB
JavaScript
85 lines
3.0 KiB
JavaScript
class IncomingAtom {
|
|
constructor(anchorIndex) {
|
|
this.anchorIndex = anchorIndex;
|
|
const ap = anchorPoints[anchorIndex];
|
|
const far = Math.max(canvas.width, canvas.height) * 0.9;
|
|
this.x = CX + Math.cos(ap.angle) * far;
|
|
this.y = CY + Math.sin(ap.angle) * far;
|
|
this.tx = ap.x;
|
|
this.ty = ap.y;
|
|
this.speed = ATOM_SPEED_MIN + Math.random() * (ATOM_SPEED_MAX - ATOM_SPEED_MIN);
|
|
this.radius = ATOM_RADIUS_MIN + Math.random() * (ATOM_RADIUS_MAX - ATOM_RADIUS_MIN);
|
|
this.hue = ATOM_HUE_MIN + Math.random() * ATOM_HUE_RANGE;
|
|
this.dead = false;
|
|
this.eAngle = Math.random() * Math.PI * 2;
|
|
this.eSpeed = ATOM_ELECTRON_SPEED_MIN + Math.random() * (ATOM_ELECTRON_SPEED_MAX - ATOM_ELECTRON_SPEED_MIN);
|
|
// ap.active is set once the atom enters the visible screen (see update)
|
|
}
|
|
|
|
update() {
|
|
if (this.dead || gameOver) return;
|
|
|
|
// Activate the anchor the moment the atom becomes visible
|
|
const ap = anchorPoints[this.anchorIndex];
|
|
if (!ap.active &&
|
|
this.x >= 0 && this.x <= canvas.width &&
|
|
this.y >= 0 && this.y <= canvas.height) {
|
|
ap.active = true;
|
|
}
|
|
|
|
const dx = this.tx - this.x;
|
|
const dy = this.ty - this.y;
|
|
const dist = Math.hypot(dx, dy);
|
|
|
|
if (dist < this.speed) {
|
|
this.dead = true;
|
|
anchorPoints[this.anchorIndex].active = false;
|
|
docks++;
|
|
document.getElementById('docks-count').textContent = `${docks} / ${MAX_DOCKS} docks`;
|
|
updateCystinstein();
|
|
burst(this.tx, this.ty, '#ff4444');
|
|
if (docks >= MAX_DOCKS) triggerGameOver();
|
|
} else {
|
|
this.x += (dx / dist) * this.speed;
|
|
this.y += (dy / dist) * this.speed;
|
|
this.eAngle += this.eSpeed;
|
|
}
|
|
}
|
|
|
|
draw() {
|
|
if (this.dead) return;
|
|
const c = `hsl(${this.hue}, 80%, 60%)`;
|
|
|
|
const g = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.radius * 2.5);
|
|
g.addColorStop(0, `hsla(${this.hue}, 80%, 60%, 0.4)`);
|
|
g.addColorStop(1, 'transparent');
|
|
ctx.fillStyle = g;
|
|
ctx.beginPath();
|
|
ctx.arc(this.x, this.y, this.radius * 2.5, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
|
|
ctx.fillStyle = c;
|
|
ctx.beginPath();
|
|
ctx.arc(this.x, this.y, this.radius * 0.55, 0, Math.PI * 2);
|
|
ctx.fill();
|
|
|
|
ctx.save();
|
|
ctx.translate(this.x, this.y);
|
|
ctx.strokeStyle = `hsla(${this.hue}, 80%, 70%, 0.35)`;
|
|
ctx.lineWidth = 1;
|
|
ctx.beginPath();
|
|
ctx.ellipse(0, 0, this.radius, this.radius * 0.4, this.eAngle * 0.25, 0, Math.PI * 2);
|
|
ctx.stroke();
|
|
|
|
ctx.fillStyle = '#fff';
|
|
ctx.beginPath();
|
|
ctx.arc(
|
|
Math.cos(this.eAngle) * this.radius,
|
|
Math.sin(this.eAngle) * (this.radius * 0.4),
|
|
3, 0, Math.PI * 2
|
|
);
|
|
ctx.fill();
|
|
ctx.restore();
|
|
}
|
|
}
|