From 7cafc07bf1613d9c80e1b9a3e3f9222146a860bf Mon Sep 17 00:00:00 2001 From: Jonas Date: Thu, 24 Apr 2025 18:20:30 +0200 Subject: [PATCH] =?UTF-8?q?Funktionierender=20Punktestand=20durch=20=C3=84?= =?UTF-8?q?pfel=20und=20Blaubeeren?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Game/Classes/Fruits/Classes/Fruit.js | 37 ++++++++++ .../Game/Classes/Fruits/FruitManager.js | 72 +++++++++++++++++++ .../Game/Classes/Playground/Playground.js | 2 +- .../GameManager/Game/Classes/Snake/Snake.js | 24 +++++-- backend/src/SocketIO/GameManager/Game/Game.js | 16 +++-- .../src/SocketIO/GameManager/Game/GameLoop.js | 7 +- frontend/game/scripts/Game/Loop.js | 11 +++ frontend/game/scripts/Game/UI/UIManager.js | 25 ++++++- frontend/game/style/mainStyle.css | 18 ++++- 9 files changed, 193 insertions(+), 19 deletions(-) create mode 100644 backend/src/SocketIO/GameManager/Game/Classes/Fruits/Classes/Fruit.js create mode 100644 backend/src/SocketIO/GameManager/Game/Classes/Fruits/FruitManager.js diff --git a/backend/src/SocketIO/GameManager/Game/Classes/Fruits/Classes/Fruit.js b/backend/src/SocketIO/GameManager/Game/Classes/Fruits/Classes/Fruit.js new file mode 100644 index 0000000..19c476d --- /dev/null +++ b/backend/src/SocketIO/GameManager/Game/Classes/Fruits/Classes/Fruit.js @@ -0,0 +1,37 @@ +const Playground = require("../../Playground/Playground"); +const FruitManager = require("../FruitManager"); + +class Fruit{ + /** @param {FruitManager} fruitManager @param {Playground} playground */ + constructor(fruitManager, playground, startX, startY, type, index = 0) { + this.fruitManager = fruitManager; + this.playground = playground; + this.index = index; + + this.x = startX; + this.y = startY; + + this.type = type; + } + + update(){ + const tile = this.playground.getTile(this.x, this.y); + + if(tile === undefined) return; + + if(tile?.class === "Snake"){ + this.fruitManager.scored(this.index); + + return; + } + + this.playground.setTile(this.x, this.y, { + class: "Fruit", + type: this.type, + x: this.x, + y: this.y + }); + } +} + +module.exports = Fruit; \ No newline at end of file diff --git a/backend/src/SocketIO/GameManager/Game/Classes/Fruits/FruitManager.js b/backend/src/SocketIO/GameManager/Game/Classes/Fruits/FruitManager.js new file mode 100644 index 0000000..7da5ada --- /dev/null +++ b/backend/src/SocketIO/GameManager/Game/Classes/Fruits/FruitManager.js @@ -0,0 +1,72 @@ +const Fruit = require("./Classes/Fruit"); +const socketIO = require("socket.io"); +const Game = require("../../Game"); +const Playground = require("../Playground/Playground"); + +class FruitManager{ + /** @param {socketIO.Server} io @param {Game} game @param {Playground} playground */ + constructor(io, game, playground){ + this.io = io; + this.game = game; + this.playground = playground; + + this.fruitAmount = 5; + + /** @type {Array} */ + this.fruits = []; + + this.setupFruits(); + } + + setupFruits(){ + for(let i = 0; i < this.fruitAmount; i++){ + this.createFruit(); + } + } + + createFruit(){ + const pos = this.randomUnusedTile(); + const type = Math.random() < 0.5 ? "Apfel" : "Blaubeere"; + const newFruit = new Fruit( + this, + this.playground, + pos.x, + pos.y, + type + ); + this.fruits.push(newFruit); + + this.fruits.forEach((fruit, i) => { fruit.index = i }); + } + + + randomUnusedTile(){ + let isUnused = false; + let x = 0; + let y = 0; + + do{ + x = Math.floor(Math.random() * this.playground.height); + y = Math.floor(Math.random() * this.playground.width); + + const tile = this.playground.getTile(x, y); + + if(tile === null) isUnused = true; + } while(!isUnused); + + return {x, y}; + } + updateFruits(){ + this.fruits.forEach(fruit => fruit.update()); + } + + scored(fruitIndex){ + this.game.score += 1; + + this.fruits.splice(fruitIndex, 1); + + this.createFruit(); + } +} + +module.exports = FruitManager; \ No newline at end of file diff --git a/backend/src/SocketIO/GameManager/Game/Classes/Playground/Playground.js b/backend/src/SocketIO/GameManager/Game/Classes/Playground/Playground.js index aeb8c3b..c51857b 100644 --- a/backend/src/SocketIO/GameManager/Game/Classes/Playground/Playground.js +++ b/backend/src/SocketIO/GameManager/Game/Classes/Playground/Playground.js @@ -23,7 +23,7 @@ class Playground { getTile(x, y){ if (x < 0 || x >= this.width || y < 0 || y >= this.height) { - return null; // Ungültiges feld + return undefined; // Ungültiges feld } return this.tiles[x][y]; } diff --git a/backend/src/SocketIO/GameManager/Game/Classes/Snake/Snake.js b/backend/src/SocketIO/GameManager/Game/Classes/Snake/Snake.js index c21946b..efb6a1d 100644 --- a/backend/src/SocketIO/GameManager/Game/Classes/Snake/Snake.js +++ b/backend/src/SocketIO/GameManager/Game/Classes/Snake/Snake.js @@ -1,11 +1,13 @@ const SocketUser = require("../../../../Classes/SocketUser"); +const Game = require("../../Game"); const Playground = require("../Playground/Playground"); class Snake{ - /** @param {SocketUser} player @param {Playground} playground */ - constructor(player, playground, color, startTiles, startMovement) { + /** @param {SocketUser} player @param {Playground} playground @param {Game} game */ + constructor(player, playground, game, color, startTiles, startMovement) { this.player = player; this.playground = playground; + this.game = game; this.color = color; this.startLength = 5; @@ -64,7 +66,7 @@ class Snake{ }); } - this.drawTiles(); + this.checkAndDrawTiles(); } movementToAxes(movement){ @@ -154,11 +156,23 @@ class Snake{ else if (dy === 1) end.deg = 270; else if (dy === -1) end.deg = 90; - this.drawTiles(); + this.checkAndDrawTiles(); } - drawTiles(){ + checkAndDrawTiles(){ this.tiles.forEach(tile => { + const exsitingtile = this.playground.getTile(tile.x, tile.y); + + // TODO: Solang Entfernt kann man alleine Testen + // if(exsitingtile === undefined){ + // // End Game weil außerhalb des Spielfeldes + // this.game.endGame(`${this.player.username} hat die Wand berührt!`) + // } + // if(exsitingtile?.class === "Snake"){ + // // Eng Game weil schon belegt mit anderer oder eigender Schlange + // this.game.endGame(`Ihr seit koolidiert!`) + // } + this.playground.setTile(tile.x, tile.y, tile); }) } diff --git a/backend/src/SocketIO/GameManager/Game/Game.js b/backend/src/SocketIO/GameManager/Game/Game.js index f71a622..c965f38 100644 --- a/backend/src/SocketIO/GameManager/Game/Game.js +++ b/backend/src/SocketIO/GameManager/Game/Game.js @@ -11,6 +11,8 @@ class Game{ this.gameManager = gameManager; this.code = code; + this.score = 0; + this.waitingSeconds = 5; this.gameStarted = false; @@ -37,6 +39,7 @@ class Game{ const snake = new Snake( player, this.gameLoop.playground, + this, this.snakeColors[i], { x: start, @@ -51,13 +54,14 @@ class Game{ this.gameLoop.loop(); } + endGame(msg){ + this.io.to(`game-${this.code}`).emit("gameEnd", msg); + } + waitingForPlayers(changeTime = false){ if(this.waitingSeconds <= 0){ if(this.players.length < 2) { - this.io.to(`game-${this.code}`).emit( - "gameEnd", - "Das Spiel ist zu Ende, da nicht genug Spieler beigetreten sind!" - ); + this.endGame("Das Spiel ist zu Ende, da nicht genug Spieler beigetreten sind!"); this.gameManager.games.delete(this.code); return; } @@ -68,7 +72,7 @@ class Game{ let msg = ""; this.players.forEach(player => { if(msg === ""){ - msg = `Schon beigetreten sind: ${player.username}`; + msg = `Schon beigetreten: ${player.username}`; } else{ msg += ` und ${player.username}, es geht Sofort los!`; @@ -107,7 +111,7 @@ class Game{ }); if(this.players.length != 2){ - this.io.to(`game-${this.code}`).emit("gameEnd", "Das Spiel ist zu Ende, da ein Spieler verlassen hat!"); + this.endGame("gameEnd", "Das Spiel ist zu Ende, da ein Spieler verlassen hat!"); return 1; } } diff --git a/backend/src/SocketIO/GameManager/Game/GameLoop.js b/backend/src/SocketIO/GameManager/Game/GameLoop.js index b57d521..774fa37 100644 --- a/backend/src/SocketIO/GameManager/Game/GameLoop.js +++ b/backend/src/SocketIO/GameManager/Game/GameLoop.js @@ -2,6 +2,7 @@ const socketIO = require("socket.io"); const Playground = require("./Classes/Playground/Playground"); const Game = require("./Game"); const Snake = require("./Classes/Snake/Snake"); +const FruitManager = require("./Classes/Fruits/FruitManager"); class GameLoop{ /** @param {socketIO.Server} io @param {Game} game */ @@ -13,12 +14,15 @@ class GameLoop{ /** @type {Array} */ this.snakes = []; + + this.fruitManager = new FruitManager(this.io, this.game, this.playground); } loop(){ this.playground.resetPlayground(); - this.snakes.forEach(snake => { snake.move() }); + this.snakes.forEach(snake => { snake.move()}); + this.fruitManager.updateFruits(); this.sendUpdate(); @@ -30,6 +34,7 @@ class GameLoop{ sendUpdate(){ this.io.to(`game-${this.game.code}`).emit("loop", { code: this.game.code, + score: this.game.score, playground: { tiles: this.playground.tiles, } diff --git a/frontend/game/scripts/Game/Loop.js b/frontend/game/scripts/Game/Loop.js index dedc492..75d091f 100644 --- a/frontend/game/scripts/Game/Loop.js +++ b/frontend/game/scripts/Game/Loop.js @@ -14,6 +14,7 @@ class Loop{ this.game.playGround.resetOverlay(); const tiles = data.playground.tiles; + // Spielfeld Zeichenen tiles.forEach((row, x) => { row.forEach((tile, y) => { if(!tile) return; @@ -23,11 +24,21 @@ class Loop{ tile.deg ) + this.game.playGround.setOverlay(x, y, overlay); + } + else if(tile.class === "Fruit"){ + const overlay = new Overlay( + `./assets/Früchte/${tile.type}.png` + ) + this.game.playGround.setOverlay(x, y, overlay); } }) }); + // Score Anzeigen + this.game.uiManager.score.innerText = `${data.score}`; + this.game.playGround.draw(); } } diff --git a/frontend/game/scripts/Game/UI/UIManager.js b/frontend/game/scripts/Game/UI/UIManager.js index 93d2af9..83ace4e 100644 --- a/frontend/game/scripts/Game/UI/UIManager.js +++ b/frontend/game/scripts/Game/UI/UIManager.js @@ -1,12 +1,14 @@ class UIManager{ constructor(){ this.mainDiv = document.getElementById("mainMenu"); + this.score = undefined; this.gameCanvasDiv = undefined; } // Erstellen des Grundgerüstes der UI loadGameContent(){ + // Spielfeld erstellen this.mainDiv.innerHTML = ""; const body = document.body; @@ -18,15 +20,32 @@ class UIManager{ this.gameCanvasDiv.id = "gameCanvasDiv" this.mainDiv.appendChild(this.gameCanvasDiv); + + // Punktestand erstellen + const scoreDiv = document.createElement("div"); + scoreDiv.id = "scoreDiv"; + scoreDiv.classList.add("gameShow"); + + const title = document.createElement("h2"); + title.innerText = "Punktestand:"; + scoreDiv.appendChild(title); + + this.score = document.createElement("h1"); + this.score.id = "scoreText" + this.score.innerText = "0"; + scoreDiv.appendChild(this.score); + + this.mainDiv.appendChild(scoreDiv); } // Erstellen der Info für welche Schlange man ist addSnakeColorInfo(color){ const infoDiv = document.createElement("div"); - infoDiv.id = "infoDiv" + infoDiv.id = "infoDiv"; + infoDiv.classList.add("gameShow"); - const header = document.createElement("h1") - header.innerText = "Deine Schlange:" + const header = document.createElement("h1"); + header.innerText = "Deine Schlange:"; infoDiv.appendChild(header); const snakeTable = document.createElement("table"); diff --git a/frontend/game/style/mainStyle.css b/frontend/game/style/mainStyle.css index f3794ca..f332f68 100644 --- a/frontend/game/style/mainStyle.css +++ b/frontend/game/style/mainStyle.css @@ -19,15 +19,27 @@ img{ } #infoDiv{ + height: 75vh; + width: 15vw; + right: 2.5vw; +} + +#scoreDiv{ + left: 2.5vw; + height: 60px; + min-width: 230px; + + justify-content: space-around; + flex-direction: row; +} + +.gameShow{ background-color: rgba(0, 0, 0, 0.3); position: absolute; - height: 75vh; - width: 15vw; border: 5px solid rgba(255, 255, 255, 0.678); border-radius: 25px; - right: 2.5vw; text-align: center;