diff --git a/Webservice/Game.js b/Webservice/Game.js index 2cb500d..ccef9d2 100644 --- a/Webservice/Game.js +++ b/Webservice/Game.js @@ -1,26 +1,35 @@ +const Player = require('./Player'); const Hunter = require("./Hunter"); class Game { constructor() { this.players = []; - this.whosNext = 0; + this.currentPlayerIndex = 0; this.started = false; this.round = 0; this.hunter = new Hunter(); } finish_turn() { + let move_to_next_round = false; // move on to next player; skip dead players do { - this.whosNext++; - if (this.whosNext === this.players.length) { - this.whosNext = 0; - this.round++; + if (this.players.length === 0) break; + + this.currentPlayerIndex++; + if (this.currentPlayerIndex >= this.players.length) { + this.currentPlayerIndex = 0; + move_to_next_round = true; } - } while (!this.players[this.whosNext].isAlive); + } while (!this.players[this.currentPlayerIndex].isAlive); // skip dead players + this.finish_round(); + } + + finish_round() { + this.round++; // kill players with hunter if (this.round >= 5) { - this.hunter.move(1); + this.hunter.move_by(1); this.hunter.hunt(this.players); } // check if all players are dead @@ -28,6 +37,32 @@ class Game { // todo: end game (all players are dead) } } + + add_player(name) { + this.players.push(new Player(name)); + } + + remove_player(name) { + let index = this.get_player_index(name); + if (index !== -1) { + this.players.splice(index, 1); + if (this.currentPlayerIndex >= index) this.currentPlayerIndex--; + } + if (this.currentPlayerIndex === index) this.finish_turn(); // if current player leaves: move on to next + } + + current_player_is(name) { + return this.players[this.currentPlayerIndex].name === name; + } + + get_player_index(name) { + return this.players.findIndex(player => player.name === name); + } + + move_player(name, amount) { + let index = this.get_player_index(name); + this.players[index].move_by(amount); + } } module.exports = Game; \ No newline at end of file diff --git a/Webservice/Hunter.js b/Webservice/Hunter.js index 19a59ee..3538041 100644 --- a/Webservice/Hunter.js +++ b/Webservice/Hunter.js @@ -3,7 +3,7 @@ class Hunter { this.position = 0; } - move(amount) { + move_by(amount) { this.position += amount; } diff --git a/Webservice/Player.js b/Webservice/Player.js index 1de9a1b..7e80fca 100644 --- a/Webservice/Player.js +++ b/Webservice/Player.js @@ -1,13 +1,14 @@ class Player { - constructor(socketUsername) { - this.socketUsername = socketUsername; + constructor(name) { + this.name = name; this.position = 0; this.isAlive = true; } - move(amount) { + move_by(amount) { this.position += amount; - if (this.position === 15) { + //todo: move by 1 only on the last 3 fields + if (this.position >= 16) { // todo: win } } diff --git a/Webservice/mobileHandler.js b/Webservice/mobileHandler.js deleted file mode 100644 index 79a9890..0000000 --- a/Webservice/mobileHandler.js +++ /dev/null @@ -1,11 +0,0 @@ -function isMobile() { - let mobileDeviceIndicator = 0; - if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) { - mobileDeviceIndicator = 1; - } - /* - let hasTouchscreen = 'ontouchstart' in window; - alert(hasTouchscreen ? 'has touchscreen' : 'doesn\'t have touchscreen'); - */ -} - diff --git a/Webservice/server.js b/Webservice/server.js index aa1be80..12e3159 100644 --- a/Webservice/server.js +++ b/Webservice/server.js @@ -1,4 +1,3 @@ -const Player = require('./Player'); const Game = require('./Game'); const express = require('express'); @@ -50,7 +49,7 @@ io.on('connection', socket => { } if (gameState[socket.room].players.length < 4 && !gameState[socket.room].started) { - gameState[socket.room].players.push(new Player(socket.username)); + gameState[socket.room].add_player(socket.username); addedUser = true; socket.emit('login'); @@ -60,7 +59,7 @@ io.on('connection', socket => { generate_log_message(socket.room, socket.username, "JOINED", ""); } else { - // TODO + io.to(socket.id).emit('error', 'Game started already or room has two many members'); } }); @@ -78,23 +77,13 @@ io.on('connection', socket => { socket.on('disconnect', function () { if (gameState[socket.room] !== undefined && addedUser) { socket.broadcast.to(socket.room).emit('user left', socket.username); - let index = -1; - for (let i = 0; i < gameState[socket.room].players.length; i++) { - if (gameState[socket.room].players[i].socketUsername === socket.username) { - index = i; - break; - } - } + gameState[socket.room].remove_player(socket.username); - if (index > -1) { - gameState[socket.room].players.splice(index, 1); - } + // TODO Close card if card is opened and active player left socket.leave(socket.room); - if (gameState[socket.room].players.length === 0) { - delete gameState[socket.room]; - } + if (gameState[socket.room].players.length === 0) delete gameState[socket.room]; } generate_log_message(socket.room, socket.username, "LEFT", ""); @@ -103,12 +92,7 @@ io.on('connection', socket => { // Game socket.on('roll dice', function () { if (gameState[socket.room] !== undefined && addedUser) { - if(gameState[socket.room].players[gameState[socket.room].whosNext] === undefined) { - console.log(gameState[socket.room].players) - console.log(gameState[socket.room].whosNext) - } - - if (gameState[socket.room].players[gameState[socket.room].whosNext].socketUsername === socket.username) { + if (gameState[socket.room].current_player_is(socket.username)) { gameState[socket.room].started = true; let sides = 3; let randomNumber = Math.floor(Math.random() * sides) + 1; @@ -117,28 +101,40 @@ io.on('connection', socket => { generate_log_message(socket.room, socket.username, "DICE", randomNumber); } else { - // TODO + io.to(socket.id).emit('error', 'It\'s not your turn'); } } }); socket.on('get card', function (difficulty) { if (gameState[socket.room] !== undefined && addedUser) { - if (gameState[socket.room].players[gameState[socket.room].whosNext].socketUsername === socket.username) { + if (gameState[socket.room].current_player_is(socket.username)) { io.in(socket.room).emit('card', {'username': socket.username, 'card': getRandomCard(difficulty)}); generate_log_message(socket.room, socket.username, "CARD", difficulty); } else { - // TODO + io.to(socket.id).emit('error', 'It\'s not your turn'); } } }); socket.on('card finished', function (difficulty, answerIsCorrect) { if (gameState[socket.room] !== undefined && addedUser) { - if (answerIsCorrect) gameState[socket.room].players[gameState[socket.room].whosNext].move(difficulty); + if (answerIsCorrect) { + gameState[socket.room].move_player(socket.username, difficulty); + generate_log_message(socket.room, socket.username, "MOVE", difficulty); + } io.in(socket.room).emit('card destroyed'); gameState[socket.room].finish_turn(); + + let index = gameState[socket.room].get_player_index(socket.username); + let next_player = gameState[socket.room].players[gameState[socket.room].currentPlayerIndex].name; + + io.in(socket.room).emit('player moved', { + "next_player": next_player, + "player": index, + "position": gameState[socket.room].players[index].position + }); } }); }); @@ -161,6 +157,9 @@ function generate_log_message(room, user, type, message) { case 'DICE': color = '\x1b[34m'; break; + case 'MOVE': + color = '\x1b[30m'; + break; default: color = '\x1b[0m'; } @@ -191,4 +190,4 @@ function shuffleAnswers(card) { function pad(width, string, padding) { if (string === undefined || string === null) return pad(width, " ", " "); return (width <= string.length) ? string : pad(width, string + padding, padding); -} \ No newline at end of file +} diff --git a/public/css/index.css b/public/css/index.css index bc85301..2a6dae7 100644 --- a/public/css/index.css +++ b/public/css/index.css @@ -1,3 +1,7 @@ +#error { + color: red; +} + #login { background: #212121; height: 100%; diff --git a/public/css/mobile.css b/public/css/mobile.css deleted file mode 100644 index cdd1849..0000000 --- a/public/css/mobile.css +++ /dev/null @@ -1,35 +0,0 @@ -html { - width: 100%; - height: 100%; - font-family: Arial, sans-serif -} - -body { - width: 100%; - height: 100%; - padding: 0; - margin: 0; - overflow: hidden; -} - -main { - display: grid; - grid-template-rows: 80% 20%; - height: calc(100% - 3em - 10px); -} - -.material-icon { - font-family: Material Icons, sans-serif !important; - font-weight: 400; - font-style: normal; - font-size: 24px; - line-height: 1; - letter-spacing: normal; - text-transform: none; - display: inline-block; - white-space: nowrap; - word-wrap: normal; - direction: ltr; - -webkit-font-feature-settings: "liga"; - -webkit-font-smoothing: antialiased; -} \ No newline at end of file diff --git a/public/index.html b/public/index.html index 75d4ffa..1c9a073 100644 --- a/public/index.html +++ b/public/index.html @@ -24,6 +24,7 @@
+

diff --git a/public/js/chat.js b/public/js/chat.js index 724ccf4..e758a5a 100644 --- a/public/js/chat.js +++ b/public/js/chat.js @@ -2,15 +2,29 @@ let socket; let connected = false; function start_chat() { - socket = io("/", { - closeOnBeforeunload: false - }); - socket.on('login', function () { connected = true; + + document.getElementById('login').style.display = 'none'; + document.getElementById('game').style.display = 'flex'; + document.getElementById('chat').style.display = 'flex'; + start_chat(); + start_game(); + resize(); + addLogMessage("Welcome " + username + "!"); }); + socket.on('error', function (data) { + if (data === 'Game started already or room has two many members') { + document.getElementById('login').style.display = 'flex'; + document.getElementById('game').style.display = 'none'; + document.getElementById('chat').style.display = 'none'; + document.getElementById('error').innerText = data; + } + console.log(data); + }); + socket.on('new message', function (data) { addChatMessage(data); }); @@ -22,9 +36,6 @@ function start_chat() { socket.on('user left', function (data) { addLogMessage(data + ' left'); }); - - // Login - socket.emit('add user', {'username': username, 'room_name': room_name}); } function sendMessage() { diff --git a/public/js/game.js b/public/js/game.js index 73d025f..f594b5f 100644 --- a/public/js/game.js +++ b/public/js/game.js @@ -14,38 +14,30 @@ let rolled_number = null; let game = document.getElementById('game'); let app; let border_card_stack = new PIXI.Graphics(); +let my_turn; let game_board_size = 2000; let max_size = calculate_size(); let sprite_size = Math.floor(game_board_size / 11); -const rolled_number_style = new PIXI.TextStyle({ - fontFamily: 'Arial', - fontSize: 140, - fontWeight: 'bold', - wordWrap: true, - wordWrapWidth: game_board_size * 0.5 - 20, -}); -let rolled_number_text = new PIXI.Text("", rolled_number_style); - // fields let sprites = [ - new Sprite(9, 9), - new Sprite(9, 7), - new Sprite(9, 5), - new Sprite(9, 3), - new Sprite(9, 1), - new Sprite(7, 1), - new Sprite(5, 1), - new Sprite(3, 1), - new Sprite(1, 1), - new Sprite(1, 3), - new Sprite(1, 5), - new Sprite(1, 7), - new Sprite(1, 9), - new Sprite(3, 9), + new Sprite(9, 9), // lower right + new Sprite(7, 9), new Sprite(5, 9), - new Sprite(7, 9) + new Sprite(3, 9), + new Sprite(1, 9), // upper right + new Sprite(1, 7), + new Sprite(1, 5), + new Sprite(1, 3), + new Sprite(1, 1), // upper left + new Sprite(3, 1), + new Sprite(5, 1), + new Sprite(7, 1), + new Sprite(9, 1), // lower left + new Sprite(9, 3), + new Sprite(9, 5), + new Sprite(9, 7) ]; function start_game() { @@ -66,19 +58,22 @@ function start_game() { // White circles - let first_circle = generate_circle(new PIXI.Graphics(), 3, 9); - app.stage.addChild(first_circle); + let player_a = generate_circle(new PIXI.Graphics(), 9, 9, 'yellow', 1); + app.stage.addChild(player_a); - let second_circle = generate_circle(new PIXI.Graphics(), 5, 9); - app.stage.addChild(second_circle); + let player_b = generate_circle(new PIXI.Graphics(), 9, 9, 'blue', 2); + app.stage.addChild(player_b); - let third_circle = generate_circle(new PIXI.Graphics(), 7, 9); - app.stage.addChild(third_circle); + let player_c = generate_circle(new PIXI.Graphics(), 9, 9, 'green', 3); + app.stage.addChild(player_c); + + let player_d = generate_circle(new PIXI.Graphics(), 9, 9, 'red', 4); + app.stage.addChild(player_d); // Card stacks let cards_1 = generate_card_stack(PIXI.Sprite.from('/img/card_stack.png'), 3, 3, function () { - if (!show_card && rolled_number === 1) { + if (diced && !show_card && rolled_number === 1) { console.log("1"); socket.emit('get card', 1); } @@ -86,7 +81,7 @@ function start_game() { app.stage.addChild(cards_1); let cards_2 = generate_card_stack(PIXI.Sprite.from('/img/card_stack.png'), 5, 3, function () { - if (!show_card && rolled_number === 2) { + if (diced && !show_card && rolled_number === 2) { console.log("2"); socket.emit('get card', 2); } @@ -94,7 +89,7 @@ function start_game() { app.stage.addChild(cards_2); let cards_3 = generate_card_stack(PIXI.Sprite.from('/img/card_stack.png'), 7, 3, function () { - if (!show_card && rolled_number === 3) { + if (diced && !show_card && rolled_number === 3) { console.log("3"); socket.emit('get card', 3); } @@ -131,6 +126,29 @@ function start_game() { // logo.rotation -= Math.PI / 8; app.stage.addChild(logo); + + my_turn = new PIXI.Text("", new PIXI.TextStyle({ + fontFamily: 'Arial', + fontSize: 70, + fontWeight: 'bold', + })); + my_turn.x = sprite_size * 3; + my_turn.y = sprite_size * 8; + app.stage.addChild(my_turn); + + + let rolled_number_text = new PIXI.Text("", new PIXI.TextStyle({ + fontFamily: 'Arial', + fontSize: 140, + fontWeight: 'bold', + wordWrap: true, + wordWrapWidth: game_board_size * 0.5 - 20, + })); + rolled_number_text.x = sprite_size * 7 - sprite_size * 0.2 + dice.width / 2 - rolled_number_text.width / 2; + rolled_number_text.y = sprite_size * 6 - sprite_size * 0.2; + app.stage.addChild(rolled_number_text); + + socket.on('dice', function (randomInt) { rolled_number = randomInt; diced = true; @@ -138,10 +156,7 @@ function start_game() { border_card_stack.lineStyle(15, 0x862323, 1); border_card_stack.drawRoundedRect(sprite_size * (1 + 2 * rolled_number) - sprite_size * 0.2, sprite_size * 3 - sprite_size * 0.2, sprite_size * 1.5, sprite_size * 3 * 0.72, 10); - rolled_number_text = new PIXI.Text(rolled_number, rolled_number_style); - rolled_number_text.x = sprite_size * 7 - sprite_size * 0.2 + dice.width / 2 - rolled_number_text.width / 2; - rolled_number_text.y = sprite_size * 6 - sprite_size * 0.2; - app.stage.addChild(rolled_number_text); + rolled_number_text.text = rolled_number; }); socket.on('card', function (data) { @@ -158,10 +173,46 @@ function start_game() { diced = false; show_card = false; card.destroyCard(); - rolled_number_text.destroy(); + rolled_number_text.text = ""; border_card_stack.clear(); }); + socket.on('player moved', function (data) { + my_turn.text = ""; + + let player = data.player; + let position = data.position; + let next_player = data.next_player; + + let x = sprites[position].coord_x; + let y = sprites[position].coord_y; + + switch (player) { + case 0: + player_a.clear(); + player_a = generate_circle(new PIXI.Graphics(), y, x, 'yellow', 1); + app.stage.addChild(player_a); + break; + case 1: + player_b.clear(); + player_b = generate_circle(new PIXI.Graphics(), y, x, 'blue', 2); + app.stage.addChild(player_b); + break; + case 2: + player_c.clear(); + player_c = generate_circle(new PIXI.Graphics(), y, x, 'green', 3); + app.stage.addChild(player_c); + break; + case 3: + player_d.clear(); + player_d = generate_circle(new PIXI.Graphics(), y, x, 'red', 4); + app.stage.addChild(player_d); + break; + } + + if (next_player === username) my_turn.text = "Your Turn"; + }); + resize(); } @@ -183,10 +234,36 @@ function generate_red_border(graphics) { return graphics; } -function generate_circle(graphics, x, y) { +function generate_circle(graphics, x, y, color, offset) { graphics.lineStyle(0); - graphics.beginFill(0xffffff, 1); - graphics.drawCircle(sprite_size * x - sprite_size * 0.2 + sprite_size * 0.75, sprite_size * y - sprite_size * 0.2 + sprite_size * 0.75, sprite_size / 4); + switch (color) { + case 'yellow': + graphics.beginFill(0xFFDDA1, 1); + break; + case 'red': + graphics.beginFill(0xF47A93, 1); + break; + case 'green': + graphics.beginFill(0x6C9A8B, 1); + break; + case 'blue': + graphics.beginFill(0x4169E1, 1); + break; + } + switch (offset) { + case 1: + graphics.drawCircle(sprite_size * x - 65 - sprite_size * 0.2 + sprite_size * 0.75, sprite_size * y + 65 - sprite_size * 0.2 + sprite_size * 0.75, sprite_size / 4); + break; // upper left + case 2: + graphics.drawCircle(sprite_size * x + 65 - sprite_size * 0.2 + sprite_size * 0.75, sprite_size * y + 65 - sprite_size * 0.2 + sprite_size * 0.75, sprite_size / 4); + break; // upper right + case 3: + graphics.drawCircle(sprite_size * x - 65 - sprite_size * 0.2 + sprite_size * 0.75, sprite_size * y - 65 - sprite_size * 0.2 + sprite_size * 0.75, sprite_size / 4); + break; // lower left + case 4: + graphics.drawCircle(sprite_size * x + 65 - sprite_size * 0.2 + sprite_size * 0.75, sprite_size * y - 65 - sprite_size * 0.2 + sprite_size * 0.75, sprite_size / 4); + break; // lower right + } graphics.endFill(); return graphics; } @@ -221,4 +298,4 @@ function resize() { app.stage.scale.set(size / game_board_size, size / game_board_size); app.renderer.resize(size, size); -} \ No newline at end of file +} diff --git a/public/js/index.js b/public/js/index.js index 2a25b46..93968bd 100644 --- a/public/js/index.js +++ b/public/js/index.js @@ -10,10 +10,12 @@ document.getElementById('ok').addEventListener('click', function () { username = document.getElementById('username').value; room_name = document.getElementById('room').value; - document.getElementById('login').style.display = 'none'; - document.getElementById('game').style.display = 'flex'; - document.getElementById('chat').style.display = 'flex'; + socket = io("/", { + closeOnBeforeunload: false + }); + start_chat(); - start_game(); - resize(); + + // Login + socket.emit('add user', {'username': username, 'room_name': room_name}); }); \ No newline at end of file