From ca658c579210b99d175a540f2d6412a7643c208f Mon Sep 17 00:00:00 2001 From: Daniel Emig Date: Fri, 27 Sep 2024 13:26:44 +0200 Subject: [PATCH 1/4] basegame (but not rendering) --- index.html | 2 ++ js/game.js | 85 +++++++++++++++++++++++++++++++++++++++++++++++++- js/obstacle.js | 28 +++++++++++++++++ js/player.js | 47 ++++++++++++++++++++++++++++ js/script.js | 36 +++++++++++++++++++++ 5 files changed, 197 insertions(+), 1 deletion(-) create mode 100644 js/obstacle.js create mode 100644 js/player.js diff --git a/index.html b/index.html index d80d77c..3caabc1 100644 --- a/index.html +++ b/index.html @@ -39,5 +39,7 @@

Game Over

+ + diff --git a/js/game.js b/js/game.js index af4789c..811ef01 100644 --- a/js/game.js +++ b/js/game.js @@ -1,3 +1,86 @@ class Game { - // code to be added + constructor() { + this.startScreen = document.getElementById("game-intro"); + this.gameScreen = document.getElementById("game-screen"); + this.endScreen = document.getElementById("game-end"); + this.player = new Player(this.gameScreen, 200, 500, 100, 150, "./images/car.png", 1); + this.height = 600; + this.width = 500; + this.obstacles = []; + this.score = 0; + this.lives = 3; + this.gameIsOver = false; + this.gameIntervalId; + this.gameLoopFrecuency = 1000 / 60; + } + + start() { + this.gameScreen.width = this.width; + this.gameScreen.height = this.height; + this.startScreen.style.display = "none"; + this.gameScreen.style.display = "block"; + this.gameIntervalId = setInterval(this.gameLoop.bind(this), this.gameLoopFrecuency); + } + + endGame() { + this.player.element.remove(); + this.obstacles.forEach((obstacle) => obstacle.element.remove()); + + this.gameIsOver = true; + + this.gameScreen.style.display = "none"; + this.gameEndScreen.style.display = "block"; + } + + update() { + this.player.move(); + + if (this.spawnObstacleCheck()) { + let speed = 3; + this.generateObstacle(speed); + } + + for (let i = this.obstacles.length - 1; i >= 0; i--) { + const obstacle = this.obstacles[i]; + + obstacle.move() + let deleteObstacle = false; + if (this.player.didCollide(obstacle)) { + this.lives--; + deleteObstacle = true; + } + else if (obstacle.x > this.height) { + this.score++; + deleteObstacle = true; + } + if (deleteObstacle) { + obstacle.element.remove(); + this.obstacles.splice(i, 1); + } + } + + if (this.lives == 0) { + this.endGame(); + } + } + + gameLoop() { + this.update(); + if (this.gameIsOver) { + clearInterval(this.gameIntervalId); + } + } + + spawnObstacleCheck() { + return Math.random() < 0.02; + } + + generateObstacle(speed) { + const obstacle = new Obstacle(this.gameScreen, 200, 500, 100, 150, "./images/redCar.png", speed); + this.obstacles.push(obstacle); + } + + collissionCheck(a, b) { + + } } \ No newline at end of file diff --git a/js/obstacle.js b/js/obstacle.js new file mode 100644 index 0000000..1098938 --- /dev/null +++ b/js/obstacle.js @@ -0,0 +1,28 @@ +class Obstacle { + constructor(gameScreen, x, y, width, height, imgSrc, speed) { + this.gameScreen = gameScreen; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.element = document.createElement("img"); + this.gameScreen.appendChild(this.element); + this.element.src = imgSrc; + this.element.style.position = "absolute"; + this.element.style.width = this.width + "px"; + this.element.style.height = this.height + "px"; + this.element.style.left = this.x + "px"; + this.element.style.top = this.y + "px"; + this.speed = speed; + } + + move() { + this.y += this.speed; + this.updatePosition(); + } + + updatePosition() { + this.element.style.left = this.x + "px"; + this.element.style.top = this.y + "px"; + } +} \ No newline at end of file diff --git a/js/player.js b/js/player.js new file mode 100644 index 0000000..45e69f0 --- /dev/null +++ b/js/player.js @@ -0,0 +1,47 @@ +class Player { + constructor(gameScreen, x, y, width, height, imgSrc, speed) { + this.gameScreen = gameScreen; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.directionX = 0; + this.directionY = 0; + this.element = document.createElement("img"); + this.gameScreen.appendChild(this.element); + this.element.src = imgSrc; + this.element.style.position = "absolute"; + this.element.style.width = this.width + "px"; + this.element.style.height = this.height + "px"; + this.element.style.left = this.x + "px"; + this.element.style.top = this.y + "px"; + this.speed = speed; + } + + move() { + this.x += this.directionX * this.speed; + this.y += this.directionY * this.speed; + this.x = clamp(this.x, 10, this.gameScreen.offsetWidth - this.width - 10); + this.y = clamp(this.y, 10, this.gameScreen.offsetHeight - this.height - 10); + this.updatePosition(); + } + + updatePosition() { + this.element.style.left = this.x + "px"; + this.element.style.top = this.y + "px"; + } + + didCollide(obstacle) { + const playerRect = this.element.getBoundingClientRect(); + const obstacleRect = obstacle.element.getBoundingClientRect(); + + if (playerRect.left < obstacleRect.right && + playerRect.right > obstacleRect.left && + playerRect.top < obstacleRect.bottom && + playerRect.bottom > obstacleRect.top + ) { + return true; + } + return false; + } +} \ No newline at end of file diff --git a/js/script.js b/js/script.js index 95e544f..9429afe 100644 --- a/js/script.js +++ b/js/script.js @@ -8,5 +8,41 @@ window.onload = function () { function startGame() { console.log("start game"); + const game = new Game(); + game.start(); + } + + window.addEventListener("keydown", handleKeydown); + function handleKeydown(e) { + const key = e.key; + const possibleKeys = [ + "ArrowLeft", + "ArrowUp", + "ArrowRight", + "ArrowDown", + ]; + + if (possibleKeys.includes(key)) { + e.preventDefault(); + + switch (key) { + case "ArrowLeft": + game.player.directionX = -1; + break; + case "ArrowRight": + game.player.directionX = 1; + break; + case "ArrowUp": + game.player.directionY = -1; + break; + case "ArrowDown": + game.player.directionY = 1; + break; + } + } } }; + +function clamp(number, min, max) { + return Math.max(min, Math.min(number, max)); +} From 7ab559c00deb9d09a9d4bd06bb7eabe98a98ef5f Mon Sep 17 00:00:00 2001 From: Daniel Emig Date: Fri, 27 Sep 2024 14:34:22 +0200 Subject: [PATCH 2/4] Add component.js --- index.html | 9 ++++++--- js/component.js | 25 +++++++++++++++++++++++++ js/game.js | 4 ++-- js/obstacle.js | 23 +++-------------------- js/player.js | 24 ++---------------------- js/script.js | 1 + 6 files changed, 39 insertions(+), 47 deletions(-) create mode 100644 js/component.js diff --git a/index.html b/index.html index 3caabc1..afe4393 100644 --- a/index.html +++ b/index.html @@ -25,7 +25,9 @@

Stats

Lives: 3

-
+
+

TEST

+
@@ -37,9 +39,10 @@

Game Over

+ + + - - diff --git a/js/component.js b/js/component.js new file mode 100644 index 0000000..9753e9c --- /dev/null +++ b/js/component.js @@ -0,0 +1,25 @@ +class Component { + constructor(gameScreen, x, y, width, height, imgSrc, speed) { + this.gameScreen = gameScreen; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.directionX = 0; + this.directionY = 0; + this.element = document.createElement("img"); + this.gameScreen.appendChild(this.element); + this.element.src = imgSrc; + this.element.style.position = "absolute"; + this.element.style.width = this.width + "px"; + this.element.style.height = this.height + "px"; + this.element.style.left = this.x + "px"; + this.element.style.top = this.y + "px"; + this.speed = speed; + } + + updatePosition() { + this.element.style.left = this.x + "px"; + this.element.style.top = this.y + "px"; + } +} \ No newline at end of file diff --git a/js/game.js b/js/game.js index 811ef01..c1fdf91 100644 --- a/js/game.js +++ b/js/game.js @@ -15,8 +15,8 @@ class Game { } start() { - this.gameScreen.width = this.width; - this.gameScreen.height = this.height; + this.gameScreen.width = this.width + "px"; + this.gameScreen.height = this.height + "px"; this.startScreen.style.display = "none"; this.gameScreen.style.display = "block"; this.gameIntervalId = setInterval(this.gameLoop.bind(this), this.gameLoopFrecuency); diff --git a/js/obstacle.js b/js/obstacle.js index 1098938..2552fc1 100644 --- a/js/obstacle.js +++ b/js/obstacle.js @@ -1,28 +1,11 @@ -class Obstacle { +class Obstacle extends Component { constructor(gameScreen, x, y, width, height, imgSrc, speed) { - this.gameScreen = gameScreen; - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.element = document.createElement("img"); - this.gameScreen.appendChild(this.element); - this.element.src = imgSrc; - this.element.style.position = "absolute"; - this.element.style.width = this.width + "px"; - this.element.style.height = this.height + "px"; - this.element.style.left = this.x + "px"; - this.element.style.top = this.y + "px"; - this.speed = speed; + super(gameScreen, x, y, width, height, imgSrc, speed); + } move() { this.y += this.speed; this.updatePosition(); } - - updatePosition() { - this.element.style.left = this.x + "px"; - this.element.style.top = this.y + "px"; - } } \ No newline at end of file diff --git a/js/player.js b/js/player.js index 45e69f0..5a611d5 100644 --- a/js/player.js +++ b/js/player.js @@ -1,21 +1,6 @@ -class Player { +class Player extends Component { constructor(gameScreen, x, y, width, height, imgSrc, speed) { - this.gameScreen = gameScreen; - this.x = x; - this.y = y; - this.width = width; - this.height = height; - this.directionX = 0; - this.directionY = 0; - this.element = document.createElement("img"); - this.gameScreen.appendChild(this.element); - this.element.src = imgSrc; - this.element.style.position = "absolute"; - this.element.style.width = this.width + "px"; - this.element.style.height = this.height + "px"; - this.element.style.left = this.x + "px"; - this.element.style.top = this.y + "px"; - this.speed = speed; + super(gameScreen, x, y, width, height, imgSrc, speed); } move() { @@ -26,11 +11,6 @@ class Player { this.updatePosition(); } - updatePosition() { - this.element.style.left = this.x + "px"; - this.element.style.top = this.y + "px"; - } - didCollide(obstacle) { const playerRect = this.element.getBoundingClientRect(); const obstacleRect = obstacle.element.getBoundingClientRect(); diff --git a/js/script.js b/js/script.js index 9429afe..9a7a485 100644 --- a/js/script.js +++ b/js/script.js @@ -5,6 +5,7 @@ window.onload = function () { startButton.addEventListener("click", function () { startGame(); }); + restartButton.addEventListener("click", () => location.reload()); function startGame() { console.log("start game"); From 28757a844280de88cd8e07889abb07df3465c0e3 Mon Sep 17 00:00:00 2001 From: Daniel Emig Date: Fri, 27 Sep 2024 14:43:46 +0200 Subject: [PATCH 3/4] small changes --- js/component.js | 2 +- js/game.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/component.js b/js/component.js index 9753e9c..bff0f4b 100644 --- a/js/component.js +++ b/js/component.js @@ -8,13 +8,13 @@ class Component { this.directionX = 0; this.directionY = 0; this.element = document.createElement("img"); - this.gameScreen.appendChild(this.element); this.element.src = imgSrc; this.element.style.position = "absolute"; this.element.style.width = this.width + "px"; this.element.style.height = this.height + "px"; this.element.style.left = this.x + "px"; this.element.style.top = this.y + "px"; + this.gameScreen.appendChild(this.element); this.speed = speed; } diff --git a/js/game.js b/js/game.js index c1fdf91..5b5c6a7 100644 --- a/js/game.js +++ b/js/game.js @@ -29,7 +29,7 @@ class Game { this.gameIsOver = true; this.gameScreen.style.display = "none"; - this.gameEndScreen.style.display = "block"; + this.endScreen.style.display = "block"; } update() { From 9d7d40e02b966a51fef26783f8a28a6a9fa62a5b Mon Sep 17 00:00:00 2001 From: Daniel Emig Date: Fri, 27 Sep 2024 16:38:46 +0200 Subject: [PATCH 4/4] polish --- index.html | 24 ++++++++--- js/game.js | 103 ++++++++++++++++++++++++++++++++++++++--------- js/script.js | 53 ++++++------------------ styles/style.css | 16 ++++++++ 4 files changed, 129 insertions(+), 67 deletions(-) diff --git a/index.html b/index.html index afe4393..13a29c3 100644 --- a/index.html +++ b/index.html @@ -19,15 +19,27 @@
-
+

Stats

-

Score: 0

-

Lives: 3

+
+
Score:
+ 0 +
+
+
Lives:
+ 0 +
+
+
speed X:
+ 0 +
+
+
Speed Y:
+ 0 +
-
-

TEST

-
+
diff --git a/js/game.js b/js/game.js index 5b5c6a7..5e28a88 100644 --- a/js/game.js +++ b/js/game.js @@ -3,7 +3,11 @@ class Game { this.startScreen = document.getElementById("game-intro"); this.gameScreen = document.getElementById("game-screen"); this.endScreen = document.getElementById("game-end"); - this.player = new Player(this.gameScreen, 200, 500, 100, 150, "./images/car.png", 1); + this.livesLabel = document.getElementById("lives"); + this.scoreLabel = document.getElementById("score"); + this.speedXLabel = document.getElementById("speed-x"); + this.speedYLabel = document.getElementById("speed-y"); + this.player = null; this.height = 600; this.width = 500; this.obstacles = []; @@ -15,8 +19,9 @@ class Game { } start() { - this.gameScreen.width = this.width + "px"; - this.gameScreen.height = this.height + "px"; + this.player = new Player(this.gameScreen, 200, 500, 100, 150, "./images/car.png", 2); + this.gameScreen.style.width = this.width + "px"; + this.gameScreen.style.height = this.height + "px"; this.startScreen.style.display = "none"; this.gameScreen.style.display = "block"; this.gameIntervalId = setInterval(this.gameLoop.bind(this), this.gameLoopFrecuency); @@ -40,6 +45,43 @@ class Game { this.generateObstacle(speed); } + this.collissionCheck(); + + this.setLabels(); + + const drag = 0.01; + this.player.directionX -= drag * Math.sign(this.player.directionX); + this.player.directionY -= drag * Math.sign(this.player.directionY); + + if (this.lives == 0) { + this.endGame(); + } + } + + gameLoop() { + this.update(); + if (this.gameIsOver) { + clearInterval(this.gameIntervalId); + } + } + + spawnObstacleCheck() { + if (this.obstacles.length > 1) { + return false; + } + return Math.random() < 0.05; + } + + generateObstacle(speed) { + const width = 100; + const height = 150; + const x = Math.random() * this.width - width * 0.5; + const y = -height; + const obstacle = new Obstacle(this.gameScreen, x, y, width, height, "./images/redCar.png", speed); + this.obstacles.push(obstacle); + } + + collissionCheck() { for (let i = this.obstacles.length - 1; i >= 0; i--) { const obstacle = this.obstacles[i]; @@ -49,7 +91,7 @@ class Game { this.lives--; deleteObstacle = true; } - else if (obstacle.x > this.height) { + else if (obstacle.y > this.height + obstacle.height) { this.score++; deleteObstacle = true; } @@ -58,29 +100,50 @@ class Game { this.obstacles.splice(i, 1); } } + } - if (this.lives == 0) { - this.endGame(); - } + setLabels() { + this.livesLabel.innerText = this.lives; + this.scoreLabel.innerText = this.score; + this.speedXLabel.innerText = this.player.directionX.toFixed(2); + this.speedYLabel.innerText = this.player.directionY.toFixed(2); } - gameLoop() { - this.update(); + handleKeydown(e) { if (this.gameIsOver) { - clearInterval(this.gameIntervalId); + return; } - } - spawnObstacleCheck() { - return Math.random() < 0.02; - } + const key = e.key; + const possibleKeys = [ + "ArrowLeft", + "ArrowUp", + "ArrowRight", + "ArrowDown", + "w", "a", "s", "d", + ]; - generateObstacle(speed) { - const obstacle = new Obstacle(this.gameScreen, 200, 500, 100, 150, "./images/redCar.png", speed); - this.obstacles.push(obstacle); - } - - collissionCheck(a, b) { + if (possibleKeys.includes(key)) { + e.preventDefault(); + switch (key) { + case "ArrowLeft": + case "a": + this.player.directionX = -1; + break; + case "ArrowRight": + case "d": + this.player.directionX = 1; + break; + case "ArrowUp": + case "w": + this.player.directionY = -1; + break; + case "ArrowDown": + case "s": + this.player.directionY = 1; + break; + } + } } } \ No newline at end of file diff --git a/js/script.js b/js/script.js index 9a7a485..815baf5 100644 --- a/js/script.js +++ b/js/script.js @@ -1,49 +1,20 @@ window.onload = function () { - const startButton = document.getElementById("start-button"); - const restartButton = document.getElementById("restart-button"); + const startButton = document.getElementById("start-button"); + const restartButton = document.getElementById("restart-button"); - startButton.addEventListener("click", function () { - startGame(); - }); - restartButton.addEventListener("click", () => location.reload()); + startButton.addEventListener("click", function () { + startGame(); + }); + restartButton.addEventListener("click", () => location.reload()); - function startGame() { - console.log("start game"); - const game = new Game(); - game.start(); - } - - window.addEventListener("keydown", handleKeydown); - function handleKeydown(e) { - const key = e.key; - const possibleKeys = [ - "ArrowLeft", - "ArrowUp", - "ArrowRight", - "ArrowDown", - ]; - - if (possibleKeys.includes(key)) { - e.preventDefault(); - - switch (key) { - case "ArrowLeft": - game.player.directionX = -1; - break; - case "ArrowRight": - game.player.directionX = 1; - break; - case "ArrowUp": - game.player.directionY = -1; - break; - case "ArrowDown": - game.player.directionY = 1; - break; - } + function startGame() { + console.log("start game"); + const game = new Game(); + window.addEventListener("keydown", (e) => game.handleKeydown(e)); + game.start(); } - } }; function clamp(number, min, max) { - return Math.max(min, Math.min(number, max)); + return Math.max(min, Math.min(number, max)); } diff --git a/styles/style.css b/styles/style.css index cf0cff3..1318582 100644 --- a/styles/style.css +++ b/styles/style.css @@ -14,6 +14,22 @@ body { justify-content: center; } +#game-stats +{ + font-family: Consolas, monaco, monospace; + padding-right: 50px; + width: 200px; + text-align: left; +} + +.speed +{ + display: flex; + flex-direction: row; + justify-content: space-between; + width: 150px; +} + #game-screen { display: none; align-content: center;