Player movement #38

Merged
fabianthome merged 14 commits from player-movement into main 2021-06-18 08:20:22 +00:00
11 changed files with 223 additions and 139 deletions

View File

@ -1,26 +1,35 @@
const Player = require('./Player');
const Hunter = require("./Hunter"); const Hunter = require("./Hunter");
class Game { class Game {
constructor() { constructor() {
this.players = []; this.players = [];
this.whosNext = 0; this.currentPlayerIndex = 0;
this.started = false; this.started = false;
this.round = 0; this.round = 0;
this.hunter = new Hunter(); this.hunter = new Hunter();
} }
finish_turn() { finish_turn() {
let move_to_next_round = false;
// move on to next player; skip dead players // move on to next player; skip dead players
do { do {
this.whosNext++; if (this.players.length === 0) break;
if (this.whosNext === this.players.length) {
this.whosNext = 0; this.currentPlayerIndex++;
this.round++; 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 // kill players with hunter
if (this.round >= 5) { if (this.round >= 5) {
this.hunter.move(1); this.hunter.move_by(1);
this.hunter.hunt(this.players); this.hunter.hunt(this.players);
} }
// check if all players are dead // check if all players are dead
@ -28,6 +37,32 @@ class Game {
// todo: end game (all players are dead) // 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; module.exports = Game;

View File

@ -3,7 +3,7 @@ class Hunter {
this.position = 0; this.position = 0;
} }
move(amount) { move_by(amount) {
this.position += amount; this.position += amount;
} }

View File

@ -1,13 +1,14 @@
class Player { class Player {
constructor(socketUsername) { constructor(name) {
this.socketUsername = socketUsername; this.name = name;
this.position = 0; this.position = 0;
this.isAlive = true; this.isAlive = true;
} }
move(amount) { move_by(amount) {
this.position += amount; this.position += amount;
if (this.position === 15) { //todo: move by 1 only on the last 3 fields
if (this.position >= 16) {
// todo: win // todo: win
} }
} }

View File

@ -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');
*/
}

View File

@ -1,4 +1,3 @@
const Player = require('./Player');
const Game = require('./Game'); const Game = require('./Game');
const express = require('express'); const express = require('express');
@ -50,7 +49,7 @@ io.on('connection', socket => {
} }
if (gameState[socket.room].players.length < 4 && !gameState[socket.room].started) { 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; addedUser = true;
socket.emit('login'); socket.emit('login');
@ -60,7 +59,7 @@ io.on('connection', socket => {
generate_log_message(socket.room, socket.username, "JOINED", ""); generate_log_message(socket.room, socket.username, "JOINED", "");
} else { } 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 () { socket.on('disconnect', function () {
if (gameState[socket.room] !== undefined && addedUser) { if (gameState[socket.room] !== undefined && addedUser) {
socket.broadcast.to(socket.room).emit('user left', socket.username); socket.broadcast.to(socket.room).emit('user left', socket.username);
let index = -1; gameState[socket.room].remove_player(socket.username);
for (let i = 0; i < gameState[socket.room].players.length; i++) {
if (gameState[socket.room].players[i].socketUsername === socket.username) {
index = i;
break;
}
}
if (index > -1) { // TODO Close card if card is opened and active player left
gameState[socket.room].players.splice(index, 1);
}
socket.leave(socket.room); socket.leave(socket.room);
if (gameState[socket.room].players.length === 0) { if (gameState[socket.room].players.length === 0) delete gameState[socket.room];
delete gameState[socket.room];
}
} }
generate_log_message(socket.room, socket.username, "LEFT", ""); generate_log_message(socket.room, socket.username, "LEFT", "");
@ -103,12 +92,7 @@ io.on('connection', socket => {
// Game // Game
socket.on('roll dice', function () { socket.on('roll dice', function () {
if (gameState[socket.room] !== undefined && addedUser) { if (gameState[socket.room] !== undefined && addedUser) {
if(gameState[socket.room].players[gameState[socket.room].whosNext] === undefined) { if (gameState[socket.room].current_player_is(socket.username)) {
console.log(gameState[socket.room].players)
console.log(gameState[socket.room].whosNext)
}
if (gameState[socket.room].players[gameState[socket.room].whosNext].socketUsername === socket.username) {
gameState[socket.room].started = true; gameState[socket.room].started = true;
let sides = 3; let sides = 3;
let randomNumber = Math.floor(Math.random() * sides) + 1; 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); generate_log_message(socket.room, socket.username, "DICE", randomNumber);
} else { } else {
// TODO io.to(socket.id).emit('error', 'It\'s not your turn');
} }
} }
}); });
socket.on('get card', function (difficulty) { socket.on('get card', function (difficulty) {
if (gameState[socket.room] !== undefined && addedUser) { 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)}); io.in(socket.room).emit('card', {'username': socket.username, 'card': getRandomCard(difficulty)});
generate_log_message(socket.room, socket.username, "CARD", difficulty); generate_log_message(socket.room, socket.username, "CARD", difficulty);
} else { } else {
// TODO io.to(socket.id).emit('error', 'It\'s not your turn');
} }
} }
}); });
socket.on('card finished', function (difficulty, answerIsCorrect) { socket.on('card finished', function (difficulty, answerIsCorrect) {
if (gameState[socket.room] !== undefined && addedUser) { 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'); io.in(socket.room).emit('card destroyed');
gameState[socket.room].finish_turn(); 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': case 'DICE':
color = '\x1b[34m'; color = '\x1b[34m';
break; break;
case 'MOVE':
color = '\x1b[30m';
break;
default: default:
color = '\x1b[0m'; color = '\x1b[0m';
} }
@ -191,4 +190,4 @@ function shuffleAnswers(card) {
function pad(width, string, padding) { function pad(width, string, padding) {
if (string === undefined || string === null) return pad(width, " ", " "); if (string === undefined || string === null) return pad(width, " ", " ");
return (width <= string.length) ? string : pad(width, string + padding, padding); return (width <= string.length) ? string : pad(width, string + padding, padding);
} }

View File

@ -1,3 +1,7 @@
#error {
color: red;
}
#login { #login {
background: #212121; background: #212121;
height: 100%; height: 100%;

View File

@ -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;
}

View File

@ -24,6 +24,7 @@
<main> <main>
<div id="login"> <div id="login">
<form> <form>
<h2 id="error"></h2>
<label for="username">Benutzername: </label> <label for="username">Benutzername: </label>
<input id="username" name="username" placeholder="Benutzername" type="text"> <input id="username" name="username" placeholder="Benutzername" type="text">

View File

@ -2,15 +2,29 @@ let socket;
let connected = false; let connected = false;
function start_chat() { function start_chat() {
socket = io("/", {
closeOnBeforeunload: false
});
socket.on('login', function () { socket.on('login', function () {
connected = true; 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 + "!"); 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) { socket.on('new message', function (data) {
addChatMessage(data); addChatMessage(data);
}); });
@ -22,9 +36,6 @@ function start_chat() {
socket.on('user left', function (data) { socket.on('user left', function (data) {
addLogMessage(data + ' left'); addLogMessage(data + ' left');
}); });
// Login
socket.emit('add user', {'username': username, 'room_name': room_name});
} }
function sendMessage() { function sendMessage() {

View File

@ -14,38 +14,30 @@ let rolled_number = null;
let game = document.getElementById('game'); let game = document.getElementById('game');
let app; let app;
let border_card_stack = new PIXI.Graphics(); let border_card_stack = new PIXI.Graphics();
let my_turn;
let game_board_size = 2000; let game_board_size = 2000;
let max_size = calculate_size(); let max_size = calculate_size();
let sprite_size = Math.floor(game_board_size / 11); 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 // fields
let sprites = [ let sprites = [
new Sprite(9, 9), new Sprite(9, 9), // lower right
new Sprite(9, 7), new Sprite(7, 9),
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(5, 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() { function start_game() {
@ -66,19 +58,22 @@ function start_game() {
// White circles // White circles
let first_circle = generate_circle(new PIXI.Graphics(), 3, 9); let player_a = generate_circle(new PIXI.Graphics(), 9, 9, 'yellow', 1);
app.stage.addChild(first_circle); app.stage.addChild(player_a);
let second_circle = generate_circle(new PIXI.Graphics(), 5, 9); let player_b = generate_circle(new PIXI.Graphics(), 9, 9, 'blue', 2);
app.stage.addChild(second_circle); app.stage.addChild(player_b);
let third_circle = generate_circle(new PIXI.Graphics(), 7, 9); let player_c = generate_circle(new PIXI.Graphics(), 9, 9, 'green', 3);
app.stage.addChild(third_circle); app.stage.addChild(player_c);
let player_d = generate_circle(new PIXI.Graphics(), 9, 9, 'red', 4);
app.stage.addChild(player_d);
// Card stacks // Card stacks
let cards_1 = generate_card_stack(PIXI.Sprite.from('/img/card_stack.png'), 3, 3, function () { 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"); console.log("1");
socket.emit('get card', 1); socket.emit('get card', 1);
} }
@ -86,7 +81,7 @@ function start_game() {
app.stage.addChild(cards_1); app.stage.addChild(cards_1);
let cards_2 = generate_card_stack(PIXI.Sprite.from('/img/card_stack.png'), 5, 3, function () { 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"); console.log("2");
socket.emit('get card', 2); socket.emit('get card', 2);
} }
@ -94,7 +89,7 @@ function start_game() {
app.stage.addChild(cards_2); app.stage.addChild(cards_2);
let cards_3 = generate_card_stack(PIXI.Sprite.from('/img/card_stack.png'), 7, 3, function () { 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"); console.log("3");
socket.emit('get card', 3); socket.emit('get card', 3);
} }
@ -131,6 +126,29 @@ function start_game() {
// logo.rotation -= Math.PI / 8; // logo.rotation -= Math.PI / 8;
app.stage.addChild(logo); 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) { socket.on('dice', function (randomInt) {
rolled_number = randomInt; rolled_number = randomInt;
diced = true; diced = true;
@ -138,10 +156,7 @@ function start_game() {
border_card_stack.lineStyle(15, 0x862323, 1); 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); 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.text = rolled_number;
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('card', function (data) { socket.on('card', function (data) {
@ -158,10 +173,46 @@ function start_game() {
diced = false; diced = false;
show_card = false; show_card = false;
card.destroyCard(); card.destroyCard();
rolled_number_text.destroy(); rolled_number_text.text = "";
border_card_stack.clear(); 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(); resize();
} }
@ -183,10 +234,36 @@ function generate_red_border(graphics) {
return graphics; return graphics;
} }
function generate_circle(graphics, x, y) { function generate_circle(graphics, x, y, color, offset) {
graphics.lineStyle(0); graphics.lineStyle(0);
graphics.beginFill(0xffffff, 1); switch (color) {
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); 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(); graphics.endFill();
return graphics; return graphics;
} }
@ -221,4 +298,4 @@ function resize() {
app.stage.scale.set(size / game_board_size, size / game_board_size); app.stage.scale.set(size / game_board_size, size / game_board_size);
app.renderer.resize(size, size); app.renderer.resize(size, size);
} }

View File

@ -10,10 +10,12 @@ document.getElementById('ok').addEventListener('click', function () {
username = document.getElementById('username').value; username = document.getElementById('username').value;
room_name = document.getElementById('room').value; room_name = document.getElementById('room').value;
document.getElementById('login').style.display = 'none'; socket = io("/", {
document.getElementById('game').style.display = 'flex'; closeOnBeforeunload: false
document.getElementById('chat').style.display = 'flex'; });
start_chat(); start_chat();
start_game();
resize(); // Login
socket.emit('add user', {'username': username, 'room_name': room_name});
}); });