Bestenliste und Scores gespeichert und beim Ende eines Spiel Rang anzeige
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
12
backend/src/Database/ScoreManager/Score.js
Normal file
12
backend/src/Database/ScoreManager/Score.js
Normal 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;
|
||||
44
backend/src/Database/ScoreManager/ScoreManager.js
Normal file
44
backend/src/Database/ScoreManager/ScoreManager.js
Normal 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;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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){
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,17 +18,19 @@ 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();
|
||||
|
||||
setTimeout(() => {
|
||||
this.loop();
|
||||
}, 125);
|
||||
if(this.game.gameStarted){
|
||||
setTimeout(() => {
|
||||
this.loop();
|
||||
}, 125);
|
||||
}
|
||||
}
|
||||
|
||||
sendUpdate(){
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) });
|
||||
|
||||
|
||||
@@ -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 */;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -86,7 +86,7 @@ img{
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
height: 150px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
#scoreEndDiv h3{
|
||||
|
||||
Reference in New Issue
Block a user