All checks were successful
Check & deploy / deploy (push) Successful in 7s
135 lines
3.6 KiB
JavaScript
135 lines
3.6 KiB
JavaScript
const enemySpawnFrequencyPerSecond = 4.5;
|
|
const maxDeltaTimeInMs = 50;
|
|
|
|
const canvasHandler = new CanvasHandler("canvas");
|
|
const inputHandler = new InputHandler(canvasHandler);
|
|
|
|
let game;
|
|
function newGame() {
|
|
canvasHandler.fillCanvas("black");
|
|
game = new Game();
|
|
}
|
|
|
|
document.getElementById("startButton").addEventListener("click", newGame);
|
|
|
|
class Circle {
|
|
constructor(position, color, velocity, target, size) {
|
|
this.position = position;
|
|
this.color = color;
|
|
this.velocity = velocity;
|
|
this.target = target;
|
|
this.size = size;
|
|
}
|
|
move(deltaTime) {
|
|
if (deltaTime > 0) {
|
|
const maxDistance = this.velocity * deltaTime;
|
|
const deltaPosition = subtract(this.target.position, this.position);
|
|
|
|
this.position = add(this.position, limit(deltaPosition, maxDistance));
|
|
}
|
|
}
|
|
|
|
draw(canvasHandler) {
|
|
canvasHandler.drawCircle(this.position, this.size, this.color);
|
|
}
|
|
|
|
isTouching(other) {
|
|
return (
|
|
magnitude(subtract(this.position, other.position)) <
|
|
this.size + other.size
|
|
);
|
|
}
|
|
}
|
|
|
|
class Game {
|
|
constructor() {
|
|
this.player = new Circle(
|
|
[0.5 * canvasHandler.width, 0.5 * canvasHandler.height],
|
|
"#FFC07F",
|
|
canvasHandler.unitToPx(0.0002),
|
|
inputHandler,
|
|
canvasHandler.unitToPx(0.01)
|
|
);
|
|
|
|
this.circleHolder = [this.player];
|
|
this.spawnInterval = 1000 / enemySpawnFrequencyPerSecond;
|
|
this.previousSpawn = this.previousTime = 0;
|
|
this.score = 0;
|
|
|
|
this.menuBox = document.getElementById("menuBox").style;
|
|
document.getElementById("startText").style.display = this.menuBox.display =
|
|
"none";
|
|
|
|
this.isActive = true;
|
|
this.boundNextFrame = this.nextFrame.bind(this);
|
|
window.requestAnimationFrame(this.boundNextFrame);
|
|
}
|
|
|
|
nextFrame(timestamp) {
|
|
if (this.isActive) {
|
|
canvasHandler.fillCanvas("rgba(165, 64, 45, 0.1)");
|
|
this.spawnEnemyIfNeeded(timestamp);
|
|
this.moveCircles(timestamp);
|
|
window.requestAnimationFrame(this.boundNextFrame);
|
|
}
|
|
}
|
|
|
|
spawnEnemyIfNeeded(timestamp) {
|
|
if (timestamp - this.previousSpawn > this.spawnInterval) {
|
|
this.circleHolder.push(
|
|
new Circle(
|
|
[
|
|
Math.random() > 0.5 ? -10 : 1.05 * canvasHandler.width,
|
|
Math.random() * canvasHandler.height,
|
|
],
|
|
"#F15156",
|
|
canvasHandler.unitToPx(0.0001),
|
|
this.player,
|
|
canvasHandler.unitToPx(0.01)
|
|
)
|
|
);
|
|
|
|
this.previousSpawn = timestamp;
|
|
this.score++;
|
|
}
|
|
}
|
|
|
|
moveCircles(timestamp) {
|
|
const deltaTime = this.getDeltaTime(timestamp);
|
|
const collided = new Set();
|
|
for (let i = 0; i < this.circleHolder.length; i++) {
|
|
this.circleHolder[i].move(deltaTime);
|
|
this.circleHolder[i].draw(canvasHandler);
|
|
|
|
for (let j = i + 1; j < this.circleHolder.length; j++) {
|
|
if (this.circleHolder[i].isTouching(this.circleHolder[j])) {
|
|
if (this.circleHolder[i] === this.player) {
|
|
this.showEndScreen();
|
|
return;
|
|
}
|
|
collided.add(i).add(j);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (collided.size > 0) {
|
|
this.circleHolder = this.circleHolder.filter(
|
|
(_, index) => !collided.has(index)
|
|
);
|
|
}
|
|
}
|
|
|
|
getDeltaTime(timestamp) {
|
|
const tempPreviousTime = this.previousTime;
|
|
this.previousTime = timestamp;
|
|
return Math.min(timestamp - tempPreviousTime, maxDeltaTimeInMs);
|
|
}
|
|
|
|
showEndScreen() {
|
|
document.getElementById("endText").style.display = "block";
|
|
document.getElementById("endScore").innerHTML = `Your score: ${this.score}`;
|
|
document.getElementById("startButton").textContent = "Play again";
|
|
this.menuBox.display = "flex";
|
|
this.isActive = false;
|
|
}
|
|
}
|