Bestenliste und Scores gespeichert und beim Ende eines Spiel Rang anzeige

This commit is contained in:
2025-04-28 20:56:06 +02:00
parent 76392172b5
commit 80ae256638
12 changed files with 155 additions and 32 deletions

View File

@@ -1,5 +1,6 @@
const mySql = require("mysql2");
const UserManager = require("./UserManager/UserManager");
const ScoreManager = require("./ScoreManager/ScoreManager");
require("dotenv").config();
class DataBaseManager {
@@ -20,6 +21,7 @@ class DataBaseManager {
});
this.usermanager = new UserManager(this.connection);
this.scoremanager = new ScoreManager(this.connection);
}
}

View File

@@ -0,0 +1,12 @@
class Score{
/** @param {UserManager} usermanager */
constructor(scoreJson){
this.id = scoreJson.id;
this.user1ID = scoreJson.user1;
this.user2ID = scoreJson.user2;
this.score = scoreJson.score;
this.time = new Date(scoreJson.time);
}
}
module.exports = Score;

View File

@@ -0,0 +1,44 @@
const mySql = require("mysql2");
const Score = require("./Score");
class ScoreManager{
/**@param {mySql.Connection} connection*/
constructor(connection) {
this.connection = connection;
}
async getAllScores(){
const response = await this.connection.promise().query("SELECT * FROM scores ORDER BY score DESC");
const sortedScores = response[0].map(scoreData => new Score(scoreData));
return sortedScores;
}
async createScore(newScoreJson){
const sql = `INSERT INTO scores (user1, user2, score) VALUES (
${newScoreJson.user1}, ${newScoreJson.user2}, ${newScoreJson.score})`;
const insertResult = await this.connection.promise().query(sql);
const insertId = insertResult[0].insertId;
const selectSql = `SELECT * FROM scores WHERE id = ${insertId}`;
const selectResult = await this.connection.promise().query(selectSql);
return new Score(selectResult[0][0]);
}
async getScoreById(id){
const response = await this.connection.promise().query(`SELECT * FROM scores WHERE id = ${id}`);
return new Score(response.rows[0][0]);
}
async getScoreRang(id){
const allSortetScores = await this.getAllScores();
const score = allSortetScores.find(score => score.id === id);
return allSortetScores.indexOf(score) + 1;
}
}
module.exports = ScoreManager;

View File

@@ -17,7 +17,7 @@ class ClientHandler {
this.socket
);
this.socket.on("disconnect", () => { this.defaultDisconnect() });
this.socket.on("disconnect", async () => { await this.defaultDisconnect() });
this.joinGame();
}
@@ -31,8 +31,8 @@ class ClientHandler {
this.socket.join(`game-${this.currentGameCode}`);
}
defaultDisconnect(){
this.gameManager.leaveGame(this.user, this.currentGameCode);
async defaultDisconnect(){
await this.gameManager.leaveGame(this.user, this.currentGameCode);
}
}

View File

@@ -28,7 +28,7 @@ class Snake{
this.setup(startTiles);
}
setup(startTiles){
async setup(startTiles){
this.player.socket.emit("color", this.color);
const headX = startTiles.x;
@@ -66,7 +66,7 @@ class Snake{
});
}
this.checkAndDrawTiles();
await this.checkAndDrawTiles();
}
movementToAxes(movement){
@@ -82,7 +82,7 @@ class Snake{
return {num, axes};
}
move(){
async move(){
// Aktuelles Movement Klonen nicht das es zwischendurch geändert wird
if(
this.movementToAxes(this.nextMovement).axes
@@ -156,7 +156,7 @@ class Snake{
else if (dy === 1) end.deg = 270;
else if (dy === -1) end.deg = 90;
this.checkAndDrawTiles();
await this.checkAndDrawTiles();
}
getBigger(){
@@ -181,22 +181,24 @@ class Snake{
this.tiles.push(newEnd);
}
checkAndDrawTiles(){
this.tiles.forEach(tile => {
async checkAndDrawTiles(){
for (const tile of this.tiles) {
const exsitingtile = this.playground.getTile(tile.x, tile.y);
// TODO: Klammert man das ein Kann man alleine Spielen, da es keine Kolisionserkennung gibt
if(exsitingtile === undefined){
// End Game weil außerhalb des Spielfeldes
this.game.endGame(`${this.player.username} hat die Wand berührt!`)
await this.game.endGame(`${this.player.username} hat die Wand berührt!`);
return;
}
if(exsitingtile?.class === "Snake"){
// Eng Game weil schon belegt mit anderer oder eigender Schlange
this.game.endGame(`Es gab eine Kollision!`)
await this.game.endGame(`Es gab eine Kollision!`);
return;
}
this.playground.setTile(tile.x, tile.y, tile);
})
}
}
updateNextMovement(data){

View File

@@ -21,6 +21,9 @@ class Game{
/**@type {Array<SocketUser>} */
this.players = [];
/**@type {Array<SocketUser>} */
this.playerIds = [];
this.gameLoop = new GameLoop(io, this);
setTimeout(() => { this.waitingForPlayers(true) }, 100);
@@ -35,6 +38,9 @@ class Game{
// 2 Schlangen für die Spieler Instazieren
this.players.forEach((player, i) => {
// id pushen um nachher das Endgame zu beenden
this.playerIds.push(player.id);
const start = (10 * i + 5) - 1;
const snake = new Snake(
player,
@@ -54,20 +60,29 @@ class Game{
this.gameLoop.loop();
}
endGame(msg){
async endGame(msg){
// TODO: Spielende in die Datenbank eintragen
this.gameStarted = false;
const scoreDb = await this.gameManager.db.scoremanager.createScore({
user1: this.playerIds[0],
user2: this.playerIds[1],
score: this.score
});
const rang = await this.gameManager.db.scoremanager.getScoreRang(scoreDb.id);
this.io.to(`game-${this.code}`).emit("gameEnd", {
msg: msg,
score: this.score,
rang: rang
});
}
waitingForPlayers(changeTime = false){
async waitingForPlayers(changeTime = false){
if(this.waitingSeconds <= 0){
if(this.players.length < 2) {
this.endGame("Das Spiel ist zu Ende, da nicht genug Spieler beigetreten sind!");
await this.endGame("Das Spiel ist zu Ende, da nicht genug Spieler beigetreten sind!");
this.gameManager.games.delete(this.code);
return;
}
@@ -108,16 +123,15 @@ class Game{
}
/** @param {SocketUser} user */
leaveUser(user){
async leaveUser(user){
this.players.forEach((player, index) => {
if(player.id === user.id){
this.players.splice(index, 1);
return;
}
});
if(this.players.length != 2){
this.endGame("Das Spiel ist zu Ende, da ein Spieler verlassen hat!");
if(this.gameStarted) await this.endGame("Das Spiel ist zu Ende, da ein Spieler verlassen hat!");
return 1;
}
}

View File

@@ -18,18 +18,20 @@ class GameLoop{
this.fruitManager = new FruitManager(this.io, this.game, this.playground);
}
loop(){
async loop(){
this.playground.resetPlayground();
this.snakes.forEach(snake => { snake.move()});
await Promise.all(this.snakes.map(snake => snake.move()));
this.fruitManager.updateFruits();
this.sendUpdate();
if(this.game.gameStarted){
setTimeout(() => {
this.loop();
}, 125);
}
}
sendUpdate(){
this.io.to(`game-${this.game.code}`).emit("loop", {

View File

@@ -2,12 +2,14 @@ const socketIO = require("socket.io");
const SocketUser = require("../Classes/SocketUser");
const TemporaryLobby = require("../LobbyManager/Classes/TemporaryLobby");
const LobbyManager = require("../LobbyManager/LobbyManager");
const DataBaseManager = require("../../Database/DataBaseManager");
const Game = require("./Game/Game");
class GameManager {
/** @param {socketIO.Server} io @param {LobbyManager} lobbyManager */
constructor(io, lobbyManager) {
/** @param {socketIO.Server} io @param {DataBaseManager} db @param {LobbyManager} lobbyManager */
constructor(io, db, lobbyManager) {
this.io = io;
this.db = db;
this.lobbyManager = lobbyManager;
/** @type {Map<string, Game>}*/
@@ -52,11 +54,11 @@ class GameManager {
return oldLobbySave.gameCode;
}
leaveGame(user, code){
async leaveGame(user, code){
const game = this.games.get(code);
if(!game) return 1;
const response = game.leaveUser(user);
const response = await game.leaveUser(user);
if(response === 1) this.games.delete(code);
}

View File

@@ -31,7 +31,7 @@ class SocketIOManager {
Der LobbyManager kümmert sich um alle Lobbys
*/
this.lobbyManager = new LobbyManager(this.io);
this.gameManager = new GameManager(this.io, this.lobbyManager);
this.gameManager = new GameManager(this.io, this.db, this.lobbyManager);
this.io.on("connection", (socket) => { this.sendToRightManager(socket) });

View File

@@ -47,6 +47,26 @@ INSERT INTO `users` (`id`, `username`, `email`, `password`, `fullName`, `created
(2, 'test2', 'test2@gmail.com', '$2b$10$fRrqNkFVA4TIyy61ovgPae83drW6oZOCND94BErwthKmt1MxzgTci', 'Test Person 2', '2025-03-22 19:48:45'),
(3, 'test3', NULL, '$2b$10$5QEkQuI/HxnaNovp8XPbnOnkuPpfSLdjwyqXMXKCB5oHZQR3ILTkq', NULL, '2025-03-22 19:48:51');
-- --------------------------------------------------------
--
-- Tabellenstruktur für Tabelle `scores`
--
CREATE TABLE `scores` (
`id` int(11) NOT NULL,
`user1` int(11) NOT NULL,
`user2` int(11) NOT NULL,
`score` int(11) NOT NULL,
`time` timestamp NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
--
-- Daten für Tabelle `scores`
--
INSERT INTO `scores` (`id`, `user1`, `user2`, `score`, `time`) VALUES
(1, 1, 2, 100, '2025-03-22 20:00:00'),
(2, 2, 3, 150, '2025-03-22 20:15:00'),
(3, 1, 3, 200, '2025-03-22 20:30:00');
--
-- Indizes der exportierten Tabellen
--
@@ -58,6 +78,14 @@ ALTER TABLE `users`
ADD PRIMARY KEY (`id`),
ADD UNIQUE KEY `username` (`username`);
--
-- Indizes für die Tabelle `scores`
--
ALTER TABLE `scores`
ADD PRIMARY KEY (`id`),
ADD KEY `user1` (`user1`),
ADD KEY `user2` (`user2`);
--
-- AUTO_INCREMENT für exportierte Tabellen
--
@@ -67,6 +95,19 @@ ALTER TABLE `users`
--
ALTER TABLE `users`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
--
-- AUTO_INCREMENT für Tabelle `scores`
--
ALTER TABLE `scores`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
--
-- Constraints der Tabelle `scores`
--
ALTER TABLE `scores`
ADD CONSTRAINT `scores_ibfk_1` FOREIGN KEY (`user1`) REFERENCES `users` (`id`),
ADD CONSTRAINT `scores_ibfk_2` FOREIGN KEY (`user2`) REFERENCES `users` (`id`);
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;

View File

@@ -107,6 +107,10 @@ class UIManager{
const score = document.createElement("h2");
score.innerText = data.score;
scoreDiv.appendChild(score);
const rang = document.createElement("h2");
rang.innerText = `Bestenliste Platz: ${data.rang}`;
rang.style.color = "rgb(255, 223, 0)";
scoreDiv.appendChild(rang);
endDiv.appendChild(scoreDiv);
const dashButton = document.createElement("button");

View File

@@ -86,7 +86,7 @@ img{
flex-direction: column;
align-items: center;
justify-content: space-evenly;
height: 150px;
height: 200px;
}
#scoreEndDiv h3{