almost working for new version

This commit is contained in:
Jonas Weinz 2019-03-21 12:13:46 +01:00
parent acb1781a9f
commit 0040d7df1e
12 changed files with 970 additions and 471 deletions

View File

@ -1,199 +0,0 @@
class GameServerConnection
{
constructor(ip, port)
{
this.ip = ip;
this.port = port;
this.player = null;
this.socket = null;
this.registered = false;
this.game_manager = null;
this.connected = false;
}
set_player(p)
{
this.player = p;
}
set_game_manager(gm)
{
this.game_manager = gm;
}
is_registered()
{
return this.registered;
}
is_connected()
{
return this.connected;
}
on_open(callback_func)
{
// TODO
console.log("connected to " + this.ip + ":" + this.port);
this.connected = true;
callback_func();
}
on_close()
{
this.game_manager.end_game_listener()
}
on_error()
{
console.log("error in websocket connection");
this.game_manager.connection_error_listener();
}
on_message(event)
{
var json_msg = event.data;
var msg = JSON.parse(json_msg);
if (!msg.hasOwnProperty("type") || !msg.hasOwnProperty("data"))
{
console.log("received wrong formatted message");
return;
}
switch(msg.type)
{
case "register_response":
this.on_register_response(msg.data);
break;
case "game_starts":
this.on_game_starts(msg.data);
break;
case "move":
this.on_move(msg.data);
break;
case "move_response":
this.on_move_response(msg.data);
break;
case "end_game":
this.on_end_game(msg.data);
break;
}
}
on_register_response(data)
{
var success = data.success;
this.game_manager.register_response_listener(success);
if (!success)
{
this.socket.close();
}
}
on_game_starts(data)
{
var op_name = data.opponent_name;
var is_first_move = data.is_first_move;
this.game_manager.start_game_listener(op_name, is_first_move);
}
on_move(data)
{
var sub_x = data.sub_x;
var sub_y = data.sub_y;
var x = data.x;
var y = data.y;
this.game_manager.move_listener(sub_x, sub_y, x, y);
}
on_move_response(data)
{
if (data.success)
{
console.log("move accepted");
}
else
{
console.error("move not accepted");
}
}
on_end_game(data)
{
this.game_manager.end_game_listener();
this.close();
}
connect(callback_func)
{
this.socket = new WebSocket("wss://" + this.ip + ":" + this.port);
this.socket.onmessage = (e => this.on_message(e));
this.socket.onopen = (() => this.on_open(callback_func));
this.socket.onerror = (() => this.on_error());
this.socket.onclose = (() => this.on_close());
}
send_move(sub_x, sub_y, x, y)
{
var msg_object = {
type: "move",
data: {
sub_x: "" + sub_x,
sub_y: "" + sub_y,
x: "" + x,
y: "" + y
}
};
this.socket.send(JSON.stringify(msg_object));
}
register()
{
// register for game queue
var msg_object = {
type: "register",
data: {
id: this.player.get_id(),
name: this.player.get_name()
}
};
this.socket.send(JSON.stringify(msg_object));
}
send_disconnect()
{
if (!this.is_connected)
{
return;
}
var msg_object = {
type: "end_game",
data: {
msg: ""
}
};
this.socket.send(JSON.stringify(msg_object));
}
close()
{
if (this.is_connected)
{
this.is_connected = false;
this.socket.close();
}
}
}

31
grid.js
View File

@ -1,9 +1,9 @@
class Grid class Grid
{ {
constructor(n, grid_container_div, tile_width, tile_height, ground_color) constructor(n, parent, tile_width, tile_height, ground_color)
{ {
this.n = n; this.n = n;
this.grid_container_div = grid_container_div; this.grid_container_div = null;
this.tile_width = tile_width; this.tile_width = tile_width;
this.tile_height = tile_height; this.tile_height = tile_height;
this.ground_color = ground_color; this.ground_color = ground_color;
@ -11,6 +11,8 @@ class Grid
this.won_player = null; this.won_player = null;
this.n_complete_subgrids = 0; this.n_complete_subgrids = 0;
this.parent = parent;
this.subgrids = [] this.subgrids = []
console.log("create grid of size " + this.n); console.log("create grid of size " + this.n);
@ -20,6 +22,10 @@ class Grid
create() create()
{ {
this.grid_container_div = document.createElement("div");
this.grid_container_div.className = "grid-container";
this.parent.appendChild(this.grid_container_div);
var x,y; var x,y;
for (y = 0; y < this.n; y++) for (y = 0; y < this.n; y++)
{ {
@ -49,7 +55,10 @@ class Grid
{ {
this.check_win(sub_x, sub_y, x, y); this.check_win(sub_x, sub_y, x, y);
this.check_complete(sub_x, sub_y, x, y); this.check_complete(sub_x, sub_y, x, y);
this.click_callback(sub_x, sub_y, x, y); if (this.click_callback != null)
{
this.click_callback(sub_x, sub_y, x, y);
}
} }
player_change_listener(player) player_change_listener(player)
@ -211,6 +220,22 @@ class Grid
} }
} }
unblock_all_non_completed()
{
var x,y;
for (y = 0; y < this.n; y++)
{
for (x = 0; x < this.n; x++)
{
if (this.subgrids[y][x].is_won() || this.subgrids[y][x].is_draw())
{
continue;
}
this.subgrids[y][x].unblock();
}
}
}
block(x,y) block(x,y)
{ {
this.subgrids[y][x].block(); this.subgrids[y][x].block();

View File

@ -8,23 +8,17 @@
<title>ultimate tictactoe</title> <title>ultimate tictactoe</title>
</head> </head>
<body> <body>
<div id="main-container" class="main-container"> <div id="main-container" class="main-container"></div>
<div id="grid-container" class="grid-container"></div>
<div id="sidebar-container" class="sidebar-container">
<div id="create-game-container" class="create-game-container"></div>
<div id="setting-container" class="setting-container"></div>
<div id="control-container" class="control-container"></div>
<div id="info-container" class="info-container"></div>
</div>
</div>
<script src="settings.js"></script> <script src="settings.js"></script>
<script src="player.js"></script> <script src="player.js"></script>
<script src="tile.js"></script> <script src="tile.js"></script>
<script src="grid.js"></script> <script src="grid.js"></script>
<script src="subgrid.js"></script> <script src="subgrid.js"></script>
<script src="game_manager.js"></script> <script src="local_match_manager.js"></script>
<script src="game_server_connection.js"></script> <script src="online_match_manager.js"></script>
<script src="sidebar.js"></script> <script src="websocket_connection.js"></script>
<script src="infobar.js"></script>
<script src="infocontainer.js"></script>
<script src="main.js"></script> <script src="main.js"></script>
</body> </body>

15
infobar.js Normal file
View File

@ -0,0 +1,15 @@
class Infobar
{
constructor(parent)
{
this.parent = parent;
this.container = document.createElement("div");
this.container.className = "infobar-container";
this.parent.appendChild(this.container);
}
create_infocontainer()
{
return new Infocontainer(this.container);
}
}

49
infocontainer.js Normal file
View File

@ -0,0 +1,49 @@
class Infocontainer
{
constructor(parent)
{
this.parent = parent;
this.container = document.createElement("div");
this.container.className = "info-container";
this.parent.appendChild(this.container);
}
create_button(text)
{
var b = document.createElement("button");
b.className = "infobar-button";
b.appendChild(document.createTextNode(text));
this.container.appendChild(b)
return b;
}
create_input(placeholder, pw=false)
{
var i = document.createElement("input");
i.className = "infobar-input";
i.placeholder = placeholder;
i.type = pw ? "password" : "text";
this.container.appendChild(i);
return i;
}
create_label(text)
{
var l = document.createElement("label");
l.className = "infobar-label";
l.innerHTML = text;
this.container.appendChild(l);
return l;
}
hide()
{
this.container.style.display = "none";
}
show()
{
this.container.style.display = "inline-block";
}
}

69
local_match_manager.js Normal file
View File

@ -0,0 +1,69 @@
class LocalMatchManager
{
constructor(grid, status_label, control_container)
{
this.grid = grid;
this.status_label = status_label;
this.control_container = control_container;
this.control_container.show();
this.local_player_a = new Player("red player", 255,0,0);
this.local_player_b = new Player("green player", 0,255,0);
this.is_local_player_a = false;
this.grid.register_click_callback((i,j,k,l) => this.click_listener(i,j,k,l));
this.grid.deactivate_all();
this.grid.unblock_all();
this.toggle_local_player();
}
click_listener(sub_x, sub_y, x,y)
{
// check whether the game is over:
if (grid.is_won())
{
this.status_change_listener("" + grid.get_won_player().get_name() + " has won.", "Game Over")
this.end_game();
}
else if (grid.is_complete())
{
this.status_change_listener("Draw. Everybody looses!", "Game Over");
this.end_game();
}
else
{
this.toggle_local_player();
this.grid.block_all()
if (this.grid.subgrids[y][x].is_draw() || this.grid.subgrids[y][x].is_won())
{
this.grid.unblock_all_non_completed();
}
else
{
this.grid.subgrids[y][x].unblock();
}
}
}
toggle_local_player()
{
this.is_local_player_a = !this.is_local_player_a;
var next_player = this.is_local_player_a ? this.local_player_a : this.local_player_b;
this.status_label.innerHTML = "" + "it's " + next_player.get_name() + "'s turn...";
this.grid.player_change_listener(next_player);
}
end_game()
{
this.status_label.innerHTML = "Game Over. Game Closed";
this.grid.block_all();
}
}

225
main.js
View File

@ -3,16 +3,225 @@ var n = style.getPropertyValue("--tictactoe_n");
var tilesize = style.getPropertyValue("--tile-size"); var tilesize = style.getPropertyValue("--tile-size");
var default_opacity = style.getPropertyValue("--opacity"); var default_opacity = style.getPropertyValue("--opacity");
var ground_color = style.getPropertyValue("--ground-color"); var ground_color = style.getPropertyValue("--ground-color");
var main_container = document.getElementById("main-container");
var create_game_container = document.getElementById("create-game-container");
var setting_container = document.getElementById("setting-container");
var control_container = document.getElementById("control-container");
var info_container = document.getElementById("info-container");
var grid = new Grid(n, document.getElementById("grid-container"), tilesize, tilesize, ground_color); var main_menu = new Infobar(main_container);
var server_connection = new GameServerConnection(server_url, server_port); var grid = new Grid(n, main_container, tilesize, tilesize, ground_color);
var game_manager = new GameManager(grid, server_connection); var sub_menu = new Infobar(main_container);
var sidebar = new Sidebar(create_game_container, setting_container, control_container, info_container, game_manager);
// fill containers with buttons and containers:
// empty dummy container on top (to force other containers to be at the bottom)
dummy_main = main_menu.create_infocontainer();
dummy_sub = sub_menu.create_infocontainer();
// start container:
create_game_container = main_menu.create_infocontainer();
create_game_container.create_label("Start Local Game");
b_local_game = create_game_container.create_button("Local Game");
// register container:
register_container = main_menu.create_infocontainer();
register_container.create_label("Register or login to play online");
i_register_username = register_container.create_input("username");
i_register_pw = register_container.create_input("password", true);
b_register = register_container.create_button("register/login");
// logout:
logout_container = sub_menu.create_infocontainer();
l_username = logout_container.create_label("logged in as: ");
b_logout = logout_container.create_button("logout");
// match control
match_control = sub_menu.create_infocontainer();
b_end_game = match_control.create_button("End Game");
// fill subcontainer:
match_slot_container = sub_menu.create_infocontainer();
match_slot_container.create_label("online matches");
// search match:
search_match_container = main_menu.create_infocontainer();
search_match_container.create_label("Create Online Match");
b_match_search = search_match_container.create_button("random match");
search_match_container.create_label("<p> </p>");
l_match_op = search_match_container.create_input("player name");
b_match_invite = search_match_container.create_button("invite player");
//status:
status_container = main_menu.create_infocontainer();
l_status_head = status_container.create_label("status:");
l_status = status_container.create_label("...");
// global vars:
game_manager = null;
logged_in = false;
// connection stuff:
var connection = null;
// global funcs:
disable_all_containers = function()
{
create_game_container.hide();
register_container.hide();
logout_container.hide();
match_slot_container.hide();
search_match_container.hide();
match_control.hide();
status_container.hide();
dummy_main.hide();
dummy_sub.hide();
}
end_local_game = function()
{
disable_all_containers();
create_game_container.show();
status_container.show();
if (logged_in)
{
logout_container.show();
search_match_container.show();
match_slot_container.show();
}
else
{
register_container.show();
}
game_manager = null;
}
on_close_click = function() {
if (game_manager != null)
{
game_manager.end_game();
end_local_game();
}
else if (connection != null)
{
connection.on_close_click();
}
}
start_local_game = function()
{
console.log("clicked");
disable_all_containers();
match_control.show();
dummy_main.show();
dummy_sub.show();
status_container.show();
game_manager = new LocalMatchManager(grid, l_status, match_control, end_local_game);
}
// connection stuff:
login_callback = function()
{
logged_in = true;
if (game_manager != null)
{
game_manager.end_game();
}
end_local_game();
l_username.innerHTML = "logged in as: " + connection.player.get_name();
}
login = function(){
if (connection != null)
{
connection.close();
}
connection = new WebsocketConnection(server_url, server_port, grid, l_status, match_slot_container, match_control, login_callback);
connection.connect(i_register_username.value, i_register_pw.value);
}
logout = function()
{
logged_in = false;
if (connection != null)
{
connection.close();
}
connection = null;
grid.unblock_all();
grid.deactivate_all();
grid.block_all();
end_local_game();
}
search_match = function()
{
if (connection != null)
{
connection.send_match_request(null);
}
}
invite_player = function()
{
if (connection != null)
{
if (l_match_op.value == "")
{
l_status.innerHTML = "choose your opponent first!";
}
else
{
connection.send_match_request(l_match_op.value);
}
}
}
// initiate stuff and connect events:
end_local_game();
b_local_game.addEventListener("click", start_local_game);
b_end_game.addEventListener("click", on_close_click);
b_register.addEventListener("click", login);
b_logout.addEventListener("click", logout);
b_match_search.addEventListener("click", search_match);
b_match_invite.addEventListener("click", invite_player);
/*
var websocket_connection = new WebsocketConnection('127.0.0.1', 5556);
websocket_connection.connect();
*/
// register resize event:
window.addEventListener("resize", function() { window.addEventListener("resize", function() {
var tilesize = getComputedStyle(document.body).getPropertyValue("--tile-size"); var tilesize = getComputedStyle(document.body).getPropertyValue("--tile-size");

199
online_match_manager.js Normal file
View File

@ -0,0 +1,199 @@
class OnlineMatchManager
{
constructor(grid, status_label, matches_container, control_container, game_server_connection, match_id, match_state, player_name)
{
this.grid = grid;
this.status_label = status_label;
this.match_id = match_id;
this.game_server_connection = game_server_connection;
this.match_state = match_state;
this.player_name = player_name
var player_a = this.match_state.player_a;
var player_b = this.match_state.player_b;
this.online_opponent = new Player(player_a == this.player_name ? player_b : player_a, 255,0,0);
this.local_player = new Player(this.player_name, 0,255,0);
// create match button in match list:
this.control_container = control_container;
this.matches_container = matches_container
this.match_button = matches_container.create_button("" + this.online_opponent.get_name());
this.match_button.addEventListener("click", () => this.open_match());
this.match_button.style.background = "rbg(0,255,0)";
this.match_button.className = "infobar-button-active";
this.is_closed = false;
}
click_listener(sub_x, sub_y, x,y)
{
this.grid.block_all();
this.game_server_connection.send_move(sub_x, sub_y, x, y, this.match_id);
this.status_label.innerHTML = "waiting for " + this.online_opponent.get_name() + "'s move";
}
on_user_close()
{
// send end match message:
if (!this.match_state.game_over)
{
this.game_server_connection.send_end_match(this.match_id);
}
this.matches_container.container.removeChild(this.match_button);
this.status_label.innerHTML = "match is closed";
this.control_container.hide();
this.is_closed = true;
}
remove_match()
{
if (!this.is_closed)
{
this.matches_container.container.removeChild(this.match_button);
}
}
update_match_state(match_state)
{
this.match_state = match_state;
this.match_button.className = "infobar-button-active";
if (this.match_state.current_player != this.current_player_name)
{
this.game_server_connection.notify("" + this.online_opponent.get_name() + " moved");
}
}
open_match()
{
this.grid.register_click_callback(null);
this.grid.deactivate_all();
this.grid.unblock_all();
this.match_button.className = "infobar-button";
this.game_server_connection.set_active_match(this.match_id);
this.control_container.show();
var complete_field = this.match_state.complete_field;
var global_field = this.match_state.global_field;
var sub_x = null;
var sub_y = null;
var x = null;
var y = null;
if (this.match_state.last_move != null)
{
sub_x = this.match_state.last_move.sub_x;
sub_y = this.match_state.last_move.sub_y;
x = this.match_state.last_move.x;
y = this.match_state.last_move.y;
}
var game_over = this.match_state.game_over;
var player_won = this.match_state.player_won;
var current_player_name = this.match_state.active_player;
var player_a = this.match_state.player_a;
var player_b = this.match_state.player_b;
console.log(game_over);
console.log(current_player);
var FIELD_EMPTY = 0
var FIELD_USER = player_a == this.player_name ? 1 : 2;
var FIELD_OPPONENT = player_a == this.player_name ? 2 : 1;
var FIELD_DRAW = 3
this.online_opponent = new Player(player_a == this.player_name ? player_b : player_a, 255,0,0);
this.local_player = new Player(this.player_name, 0,255,0);
var i,j;
for(j = 0; j < 9; j++)
{
for(i = 0; i < 9; i++)
{
var si = Math.floor(i / 3);
var sj = Math.floor(j / 3);
if (complete_field[j][i] == FIELD_USER)
{
this.grid.subgrids[sj][si].player_change_listener(this.local_player);
this.grid.subgrids[sj][si].cells[j % 3][i % 3].on_click();
}
if (complete_field[j][i] == FIELD_OPPONENT)
{
this.grid.subgrids[sj][si].player_change_listener(this.online_opponent);
this.grid.subgrids[sj][si].cells[j % 3][i % 3].on_click();
}
}
}
this.grid.block_all();
this.grid.register_click_callback((i,j,k,l) => this.click_listener(i,j,k,l));
if (game_over && player_won != null)
{
if (player_won == this.player_name)
{
this.status_label.innerHTML = "Congratulation, you won!";
}
else
{
this.status_label.innerHTML = "Game over, you lost!";
}
return;
}
else if(game_over)
{
this.status_label.innerHTML = "Game was closed by server or opponent";
return;
}
var current_player = this.player_name == current_player_name ? this.local_player : this.online_opponent;
this.grid.player_change_listener(current_player);
if (this.player_name == current_player_name)
{
if (this.match_state.last_move != null)
{
if (this.grid.subgrids[y][x].is_won() || this.grid.subgrids[y][x].is_draw())
{
this.grid.unblock_all_non_completed();
}
else
{
this.grid.unblock(x,y);
}
this.status_label.innerHTML = "It's your turn!";
}
else
{
this.grid.unblock_all();
}
}
else
{
this.status_label.innerHTML = "waiting for " + this.online_opponent.get_name() + "'s move";
}
}
}

View File

@ -1,2 +1,2 @@
var server_url = "the-cake-is-a-lie.net"; var server_url = "the-cake-is-a-lie.net";
var server_port = "5555"; var server_port = "5556";

View File

@ -1,184 +0,0 @@
class Sidebar
{
constructor(create_game_container, setting_container, control_container, info_container, game_manager)
{
this.create_game_container = create_game_container;
this.setting_container = setting_container;
this.control_container = control_container;
this.info_container = info_container;
this.game_manager = game_manager;
this.fill_containers();
this.bind_events();
this.activate_create_game();
this.activate_setting();
this.activate_info();
}
create_button(text)
{
var b = document.createElement("button");
b.className = "sidebar-button";
b.appendChild(document.createTextNode(text));
return b;
}
create_input(text)
{
var i = document.createElement("input");
i.className = "sidebar-input";
i.type = "text";
i.value = text;
return i;
}
create_label(text)
{
var l = document.createElement("label");
l.className = "sidebar-label";
l.innerHTML = text;
return l;
}
fill_containers()
{
// create new game area:
this.create_game_container.appendChild(this.create_label("Choose game type"));
this.b_local = this.create_button("local game")
this.create_game_container.appendChild(this.b_local);
this.b_remote = this.create_button("remote game");
this.create_game_container.appendChild(this.b_remote);
this.create_game_container.style.display = "none";
// settings area
this.setting_container.appendChild(this.create_label("select online name:"));
this.i_player_name = this.create_input("");
this.setting_container.appendChild(this.i_player_name);
this.setting_container.style.display = "none";
// control area:
this.b_end_game = this.create_button("end game");
this.control_container.appendChild(this.b_end_game);
this.control_container.style.display = "none";
// status area:
this.status_title = this.create_label("");
this.info_container.appendChild(this.status_title);
this.status_text = this.create_label("select gamemode. <br> <a href=https://en.wikipedia.org/wiki/Ultimate_tic-tac-toe#Rules>here are the rules </a>");
this.info_container.appendChild(this.status_text);
this.info_container.style.display = "none";
}
bind_events()
{
// TODO
this.game_manager.register_game_mode_change_listener((c) => this.game_mode_change_listener(c));
this.game_manager.register_status_change_listener((c,t=null) => this.status_change_listener(c, t));
this.b_local.addEventListener("click", () => this.game_manager.start_local_game());
this.b_end_game.addEventListener("click", () => this.game_manager.end_game(true));
this.b_remote.addEventListener("click", () => this.game_manager.register_remote_game(this.get_player_name()));
}
set_status(text)
{
this.status_text.innerHTML = text;
}
get_player_name()
{
return this.i_player_name.value;
}
activate_create_game()
{
this.create_game_container.style.display = "inline-block";
}
activate_setting()
{
this.setting_container.style.display = "inline-block";
}
activate_control()
{
this.control_container.style.display = "inline-block";
}
activate_info()
{
this.info_container.style.display = "inline-block";
}
deactivate_create_game()
{
this.create_game_container.style.display = "none";
}
deactivate_setting()
{
this.setting_container.style.display = "none";
}
deactivate_control()
{
this.control_container.style.display = "none";
}
deactivate_info()
{
this.info_container.style.display = "none";
}
game_mode_change_listener(gamemode)
{
if (gamemode == "none")
{
this.activate_create_game();
this.activate_setting();
this.deactivate_control();
this.activate_info();
return
}
if (gamemode == "local")
{
this.deactivate_create_game();
this.deactivate_setting();
this.activate_control();
this.activate_info();
}
if (gamemode == "remote")
{
this.deactivate_create_game();
this.deactivate_setting();
this.activate_control();
this.activate_info();
}
}
status_change_listener(statustext, title=null)
{
this.status_text.innerHTML = statustext;
if (title != null)
{
this.status_title.innerHTML = "<p>" + title + "</p>";
}
}
}

147
style.css
View File

@ -4,7 +4,7 @@ html, body {
body { body {
margin: 0; margin: 0;
background: rgb(30, 36, 119) ; background: rgb(49, 54, 74) ;
outline: 0; outline: 0;
position: relative; position: relative;
} }
@ -15,21 +15,36 @@ body {
--tile-size: calc((100vh / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin)); --tile-size: calc((100vh / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin));
--opacity: 1; --opacity: 1;
--border-radius: 1vh; --border-radius: 1vh;
--sidebar-width: 25vh; --sidebar-width: 26vh;
--ground-color: rgb(30, 36, 119) ; --ground-color: rgb(41, 45, 62) ;
--board-size: calc(var(--tictactoe_n) * var(--tictactoe_n) * var(--tile-size) + (var(--tictactoe_n) * var(--tictactoe_n) + var(--tictactoe_n)) * var(--button-margin) ); --board-size: calc(var(--tictactoe_n) * var(--tictactoe_n) * var(--tile-size) + (var(--tictactoe_n) * var(--tictactoe_n) + var(--tictactoe_n)) * var(--button-margin) );
--sidebar-height: calc(var(--board-size) - 2 * var(--border-radius)); --sidebar-height: calc(var(--board-size) - 2 * var(--border-radius));
} }
/* override settings on portrait mode: */ /* override settings on portrait mode: */
@media (orientation: portrait) { @media (max-aspect-ratio: 16/10) {
:root{
--button-margin: 0.35vh;
--tile-size: calc(((70vh / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin)));
--border-radius: 0.7vh;
--sidebar-width: 18.2vh;
--board-size: calc((var(--tictactoe_n) * var(--tictactoe_n) * var(--tile-size) + (var(--tictactoe_n) * var(--tictactoe_n) + var(--tictactoe_n)) * var(--button-margin)));
--sidebar-height: calc(var(--board-size) - 2 * var(--border-radius));
}
}
/* override settings on portrait mode: */
@media (max-aspect-ratio: 1/1) {
:root{ :root{
--button-margin: 0.5vw; --button-margin: 0.5vw;
--tile-size: calc((100vw / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin)); --tile-size: calc(((100vw / (var(--tictactoe_n) * var(--tictactoe_n))) - 2 * var(--button-margin)));
--border-radius: 1vw; --border-radius: 1vw;
--board-size: calc(var(--tictactoe_n) * var(--tictactoe_n) * var(--tile-size) + (var(--tictactoe_n) * var(--tictactoe_n) + var(--tictactoe_n)) * var(--button-margin) );
--sidebar-width: calc(var(--board-size) - 2 * var(--border-radius)); --sidebar-width: calc(var(--board-size) - 2 * var(--border-radius));
--sidebar-height: 15vw; --sidebar-height: 25vw;
} }
} }
@ -51,11 +66,11 @@ a:visited {
} }
/* override settings on portrait mode: */ /* override settings on portrait mode: */
@media (orientation: portrait) { @media (max-aspect-ratio: 1/1) {
.main-container { .main-container {
white-space: normal; white-space: normal;
padding-top: calc(50vh - 0.5 * var(--board-size)); padding-top: calc(50vh - 0.5 * var(--board-size) - var(--sidebar-height) - 2 * var(--button-margin));
} }
} }
@ -114,11 +129,11 @@ a:visited {
transition-duration: 0.5s; transition-duration: 0.5s;
} }
.sidebar-container { .infobar-container {
border-radius: var(--border-radius); border-radius: var(--border-radius);
padding: var(--border-radius); padding: var(--border-radius);
vertical-align: top; vertical-align: top;
background: rgba(255, 255, 255, 0.05); background: none;
display: inline-flex; display: inline-flex;
justify-content: space-between; justify-content: space-between;
flex-direction:column; flex-direction:column;
@ -129,44 +144,15 @@ a:visited {
} }
/* override settings on portrait mode: */ /* override settings on portrait mode: */
@media (orientation: portrait) { @media (max-aspect-ratio: 1/1) {
.sidebar-container { .infobar-container {
flex-direction:row; flex-direction:row;
padding: none; padding: none;
} }
} }
.create-game-container {
border-radius: var(--border-radius);
padding: var(--border-radius);
top: 0;
background: none;
display: inline-block;
vertical-align: middle;
}
.control-container {
border-radius: var(--border-radius);
padding: var(--border-radius);
top: 0;
background: none;
display: inline-block;
vertical-align: middle;
}
.setting-container {
border-radius: var(--border-radius);
padding: var(--border-radius);
top: 0;
background: none;
display: inline-block;
vertical-align: middle;
}
.info-container { .info-container {
border-radius: var(--border-radius); border-radius: var(--border-radius);
padding: var(--border-radius); padding: var(--border-radius);
@ -178,7 +164,7 @@ a:visited {
white-space: normal; white-space: normal;
} }
.sidebar-label { .infobar-label {
color: white; color: white;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -187,14 +173,14 @@ a:visited {
text-align: left; text-align: left;
} }
@media (orientation: portrait) { @media (max-aspect-ratio: 1/1) {
.sidebar-label .infobar-label
{ {
width: calc(var(--sidebar-width) * 0.3); width: calc(var(--sidebar-width) * 0.25);
} }
} }
.sidebar-button { .infobar-button {
border-radius: var(--border-radius); border-radius: var(--border-radius);
margin: var(--border-radius); margin: var(--border-radius);
border: none; border: none;
@ -202,7 +188,7 @@ a:visited {
transition-duration: 0.3s; transition-duration: 0.3s;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
color: rgb(255, 255, 255); color: rgb(255, 255, 255);
font-size: calc(3 * var(--border-radius)); font-size: calc(2.8 * var(--border-radius));
height: calc(4 * var(--border-radius)); height: calc(4 * var(--border-radius));
width: calc(var(--sidebar-width) - 4 * var(--border-radius)); width: calc(var(--sidebar-width) - 4 * var(--border-radius));
vertical-align: middle; vertical-align: middle;
@ -210,30 +196,59 @@ a:visited {
flex-direction: column; flex-direction: column;
} }
@media (orientation: portrait) { @media (max-aspect-ratio: 1/1) {
.sidebar-button{ .infobar-button{
width: calc(0.25 * var(--sidebar-width)); width: calc(0.25 * var(--sidebar-width));
height: calc(0.3 * var(--sidebar-height)); height: calc(0.18 * var(--sidebar-height));
} }
} }
.infobar-button-active {
.sidebar-button:hover {
background: rgba(255, 255, 255, 0.2);
}
.sidebar-button:active {
background: rgba(255, 255, 255, 0.4);
}
.sidebar-input {
border-radius: var(--border-radius); border-radius: var(--border-radius);
margin: var(--border-radius); margin: var(--border-radius);
border: none; border: none;
outline: 0; outline: 0;
transition-duration: 0.3s; transition-duration: 0.3s;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 255, 0, 0.5);
color: rgb(255, 255, 255);
font-size: calc(2.8 * var(--border-radius));
height: calc(4 * var(--border-radius));
width: calc(var(--sidebar-width) - 4 * var(--border-radius));
vertical-align: middle;
display: flex;
flex-direction: column;
}
@media (max-aspect-ratio: 1/1) {
.infobar-button-active{
width: calc(0.25 * var(--sidebar-width));
height: calc(0.18 * var(--sidebar-height));
}
}
.infobar-button:hover {
background: rgba(255, 255, 255, 0.2);
}
.infobar-button:active {
background: rgba(255, 255, 255, 0.4);
}
.infobar-button:disabled {
background: rgba(0, 0, 0, 0.1);
color: rgb(64,64,64);
}
.infobar-input {
border-radius: var(--border-radius);
margin: var(--border-radius);
border: none;
outline: 0;
transition-duration: 0.3s;
background: rgba(0, 0, 0, 0.2);
color: rgb(255, 255, 255); color: rgb(255, 255, 255);
font-size: calc(3 * var(--border-radius)); font-size: calc(3 * var(--border-radius));
height: calc(4 * var(--border-radius)); height: calc(4 * var(--border-radius));
@ -244,10 +259,14 @@ a:visited {
text-align: center; text-align: center;
} }
@media (orientation: portrait) { .infobar-input::placeholder {
color: rgba(255,255,255,0.3);
}
.sidebar-input{ @media (max-aspect-ratio: 1/1) {
height: calc(0.3 * var(--sidebar-height));
.infobar-input{
height: calc(0.18 * var(--sidebar-height));
width: calc(0.25 * var(--sidebar-width)); width: calc(0.25 * var(--sidebar-width));
} }
} }

303
websocket_connection.js Normal file
View File

@ -0,0 +1,303 @@
class WebsocketConnection
{
constructor(ip, port, grid, status_label, matches_container, control_container, login_callback_func)
{
this.ip = ip;
this.port = port;
this.session_id = null;
this.player = new Player("player", 128, 0,0);
this.socket = null;
this.registered = false;
this.grid = grid;
this.status_label = status_label;
this.matches_container = matches_container;
this.control_container = control_container;
this.active_match = null;
this.connected = false;
this.current_end_button = null;
this.login_callback_func = login_callback_func;
this.openmatches = {};
this.
matches_container.hide();
}
set_player(p)
{
this.player = p;
}
set_game_manager(gm)
{
this.game_manager = gm;
}
is_registered()
{
return this.registered;
}
is_connected()
{
return this.connected;
}
on_open(username, pw)
{
this.connected = true;
this.login(username, pw)
}
on_close()
{
this.registered = false;
this.connected = false;
}
on_error()
{
console.log("error in websocket connection");
this.registered = false;
this.connected = false;
}
on_message(event)
{
var json_msg = event.data;
var msg = JSON.parse(json_msg);
if (!msg.hasOwnProperty("type") || !msg.hasOwnProperty("data"))
{
console.log("received wrong formatted message");
return;
}
console.log("raw_msg: " + json_msg);
switch(msg.type)
{
case "login_response":
this.on_register_response(msg.data);
break;
case "temp_session_response":
console.log(json_msg)
this.on_temp_session_response(msg.data);
break;
case "match_update":
this.on_match_update(msg.data);
break;
case "match_request_response":
this.on_match_request_response(msg.data);
break;
}
}
set_active_match(id)
{
this.active_match = id;
}
on_close_click()
{
if (this.active_match != null && (this.active_match in this.openmatches))
{
this.openmatches[this.active_match].on_user_close();
}
}
on_match_update(data)
{
var id = data.id
var match_state = data.match_state;
if (match_state == null)
{
// checking whether we can delete our dict object
if (id in this.openmatches)
{
delete this.openmatches[id];
if (this.active_match == id)
{
if (this.current_end_button != null)
{
this.control_container.container.deleteChild(this.current_end_button);
this.current_end_button = null;
}
}
}
}
else
{
if (id in this.openmatches)
{
this.openmatches[id].update_match_state(match_state)
console.log("update!!!");
if (this.active_match == id)
{
this.openmatches[id].open_match();
}
}
else
{
if (!match_state.game_over)
{
this.openmatches[id] = new OnlineMatchManager(this.grid, this.status_label, this.matches_container, this.control_container, this, id, match_state, this.player.get_name());
}
}
}
}
on_register_response(data)
{
if (data.success)
{
this.registered = true;
this.session_id = data.id;
this.login_callback_func();
}
this.status_label.innerHTML = data.msg;
}
on_temp_session_response(data)
{
console.log("not supported yet");
}
on_match_request_response(data)
{
if (data.success)
{
this.status_label.innerHTML = "match request sent";
}
else
{
this.status_label.innerHTML = "could not send request: " + data.msg;
}
}
connect(username, pw)
{
this.socket = new WebSocket("wss://" + this.ip + ":" + this.port);
this.socket.onmessage = (e => this.on_message(e));
this.socket.onopen = (() => this.on_open(username, pw));
this.socket.onerror = (() => this.on_error());
this.socket.onclose = (() => this.on_close());
}
send_move(sub_x, sub_y, x, y, match_id)
{
var msg_object = {
type: "move",
data: {
id: match_id,
sub_x: "" + sub_x,
sub_y: "" + sub_y,
x: "" + x,
y: "" + y
}
};
this.socket.send(JSON.stringify(msg_object));
}
send_end_match(match_id)
{
var msg_object = {
type: "end_match",
data: {
id: match_id,
}
};
this.socket.send(JSON.stringify(msg_object));
}
send_match_request(player_name)
{
var msg_object = {
type: "match_request",
data: {
player: player_name
}
};
this.socket.send(JSON.stringify(msg_object));
}
login(username, pw)
{
this.player.set_name(username);
// register for game queue
var msg_object = {
type: "login",
data: {
name: this.player.get_name(),
pw: pw
}
};
this.socket.send(JSON.stringify(msg_object));
}
send_disconnect()
{
if (!this.is_connected)
{
return;
}
var msg_object = {
type: "end_game",
data: {
msg: ""
}
};
this.socket.send(JSON.stringify(msg_object));
}
close()
{
for (var key in this.openmatches)
{
this.openmatches[key].remove_match();
}
this.socket.close();
}
notify(text) {
Notification.requestPermission(function(result) {
if (result === 'granted') {
navigator.serviceWorker.ready.then(function(registration) {
registration.showNotification(text, {
icon: './icon.png',
vibrate: [200, 200],
tag: "tictactoe-notification"
});
});
}
});
}
}