diff --git a/frontend/static/js/api/game/Ball.js b/frontend/static/js/api/game/Ball.js index b29165b..31c734a 100644 --- a/frontend/static/js/api/game/Ball.js +++ b/frontend/static/js/api/game/Ball.js @@ -2,13 +2,13 @@ class Ball { - constructor(game) + constructor(game, position_x, position_y, velocity_x, velocity_y) { this.game = game; - this.position_x = game.config.size_x / 2; - this.position_y = game.config.size_y / 2; - this.velocity_x = game.config.ball_speed_start; - this.velocity_y = game.config.ball_speed_start; + this.position_x = position_x; + this.position_y = position_y; + this.velocity_x = velocity_x; + this.velocity_y = velocity_y; } _collision(old_pos_x, old_pos_y, new_pos_x, new_pos_y) diff --git a/frontend/static/js/api/game/Game.js b/frontend/static/js/api/game/Game.js index 071fc16..b236c4b 100644 --- a/frontend/static/js/api/game/Game.js +++ b/frontend/static/js/api/game/Game.js @@ -1,7 +1,10 @@ +import { sleep } from "../../utils/sleep.js"; import { Ball } from "./Ball.js"; import { GameConfig } from "./GameConfig.js" import { MyPlayer } from "./MyPlayer.js"; import { Player } from "./Player.js"; +import { Time } from "./Time.js"; +import { Wall } from "./Wall.js"; class Game { @@ -15,8 +18,6 @@ class Game */ this.client = client; this.id = id; - this.keys_pressed = []; - this.last_pos = null } async init() @@ -43,60 +44,33 @@ class Game if (ret !== 0) return ret; - this.players = []; - response_data.players_id.forEach(player_id => { - let player = new Player(player_id, 0.5, 0, this, 0, 0, 0, 0); - this.players.push(player); - }); - - this.ball = new Ball(this); + this.time = new Time(); + this.last_pos = null + this._inited = false; + this._wall_drew = false; return 0; } - draw_wall(ctx, stop_x, stop_y) + draw_sides(ctx) { - ctx.lineTo(stop_x, stop_y); - } - - draw_sides(ctx, nb_sides) - { - let start_x, - start_y, - stop_x, - stop_y; - - let radius = Math.min(this.config.size_x, this.config.size_y) / 2 - 10; - - for (let i = 0; i <= nb_sides; i++) + if (this._wall_drew !== true) { - let angle = (i * 2 * Math.PI / nb_sides) + (Math.PI * 3 / 4); - - stop_x = this.config.center_x + radius * Math.cos(angle); - stop_y = this.config.center_y + radius * Math.sin(angle); - - if (i == 0) - ctx.moveTo(stop_x, start_y); - if (i % 2 == 0) - this.draw_wall(ctx, stop_x, stop_y); - else - this.players[(i - 1) / 2].draw(ctx); - start_x = stop_x; - start_y = stop_y; + this.walls.forEach(wall => { + wall.draw(ctx); + }); } + this.players.forEach(player => { + player.draw(ctx); + }); + this._wall_drew = true; } draw(ctx) { - ctx.beginPath() - ctx.clearRect(0, 0, this.config.size_x, this.config.size_y); - this.draw_sides(ctx, (this.players_id.length) * 2); + this.draw_sides(ctx); this.ball.draw(ctx); - - ctx.strokeStyle = "#000000"; - ctx.lineWidth = 10; - ctx.stroke(); } _send(data) @@ -134,24 +108,54 @@ class Game }) } - _update_ball(data) - { - this.ball.position_x = data.position_x; - this.ball.position_y = data.position_y; - this.ball.velocity_x = data.velocity_x; - this.ball.velocity_y = data.velocity_y; - } - _update(data) { - console.log("bozo2", data) if (data.detail === "update_paddles") this._update_paddles(data); else if (data.detail === "update_ball") this._update_ball(data); + else if (data.detail === "init_game") + this._init_game(data) } - join() + _init_game(data) + { + const ball_data = data.ball; + this.ball = new Ball(this, ball_data.position_x, ball_data.position_y, ball_data.velocity_x, ball_data.velocity_y); + + this.walls = []; + const walls_data = data.walls; + walls_data.forEach((wall_data) => { + this.walls.push(new Wall(wall_data.rail_start_x, + wall_data.rail_start_y, + wall_data.rail_stop_x, + wall_data.rail_stop_y)); + }); + + this.players = [] + const players_data = data.players; + players_data.forEach((player_data) => { + this.players.push(new Player(player_data.user_id, + this, + player_data.rail_start_x, + player_data.rail_start_y, + player_data.rail_stop_x, + player_data.rail_stop_y, + player_data.nb_goal, + player_data.position + )); + }); + + this._inited = true; + } + + async wait_init() + { + while (this._inited !== true) + await sleep(100); + } + + async join() { if (this.started !== true || this.finished === true) { @@ -167,6 +171,8 @@ class Game const data = JSON.parse(event.data); this._update(data); }; + + return this.wait_init(); } leave() diff --git a/frontend/static/js/api/game/MyPlayer.js b/frontend/static/js/api/game/MyPlayer.js index 64e3d98..0dbffe2 100644 --- a/frontend/static/js/api/game/MyPlayer.js +++ b/frontend/static/js/api/game/MyPlayer.js @@ -3,30 +3,29 @@ import { Player } from "./Player.js"; class MyPlayer extends Player { - constructor(client, pos, nb_goal, game, time, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y) + constructor(client, game, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y, nb_goal, positon) { - super(client.me.id, pos, nb_goal, game, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y); - this.time = time; + super(client.me.id, game, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y, nb_goal, positon); this.client = client; } update_paddle(keys_pressed) { - let new_pos = this.pos; + let new_pos = this.positon; if (keys_pressed.includes("s")) - new_pos -= this.game.config.paddle_speed_per_second_max * this.time.deltaTimeSecond() * 1.0; + new_pos -= this.game.config.paddle_speed_per_second_max * this.game.time.deltaTimeSecond() * 1.0; if (keys_pressed.includes("w")) - new_pos += this.game.config.paddle_speed_per_second_max * this.time.deltaTimeSecond() * 1.0; + new_pos += this.game.config.paddle_speed_per_second_max * this.game.time.deltaTimeSecond() * 1.0; new_pos = Math.max(0 + this.game.config.paddle_ratio / 2, new_pos); new_pos = Math.min(1 - this.game.config.paddle_ratio / 2, new_pos); - if (this.pos === new_pos) + if (this.positon === new_pos) return; - console.log(this.client.me.id) - this.pos = new_pos; - this.game._send_paddle(this.pos, this.time._current_frame); + this.positon = new_pos; + + this.game._send_paddle(this.positon, this.game.time._current_frame); } update_pos(new_position, time) @@ -37,14 +36,14 @@ class MyPlayer extends Player let sign = this - new_position >= 0 ? 1 : -1; - let distance = Math.abs(this.pos - new_position); + let distance = Math.abs(this.positon - new_position); let distance_max = time_diff * this.game.config.paddle_speed_per_second_max; if (distance > distance_max) position_verified = distance_max * sign; - this.pos = position_verified; + this.positon = position_verified; } } diff --git a/frontend/static/js/api/game/Player.js b/frontend/static/js/api/game/Player.js index e8f75ff..4d4dc0d 100644 --- a/frontend/static/js/api/game/Player.js +++ b/frontend/static/js/api/game/Player.js @@ -1,10 +1,10 @@ class Player { - constructor(id, pos, nb_goal, game, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y) + constructor(id, game, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y, nb_goal, positon) { this.id = id; - this.pos = pos; + this.positon = positon; this.nb_goal = nb_goal; this.game = game; @@ -23,28 +23,22 @@ class Player update_pos(new_position, time) { - this.pos = new_position; + this.positon = new_position; } draw(ctx) { - let paddle_pos_x = this.rail_start_x + this.diff_x * this.pos, - paddle_pos_y = this.rail_start_y + this.diff_y * this.pos; - - console.log(this) + let paddle_pos_x = this.rail_start_x + this.diff_x * this.positon, + paddle_pos_y = this.rail_start_y + this.diff_y * this.positon; + let start_x = paddle_pos_x - (this.diff_x * (this.paddle_size / 2 / this.rail_size)), start_y = paddle_pos_y - (this.diff_y * (this.paddle_size / 2 / this.rail_size)), stop_x = paddle_pos_x + (this.diff_x * (this.paddle_size / 2 / this.rail_size)), stop_y = paddle_pos_y + (this.diff_y * (this.paddle_size / 2 / this.rail_size)); - console.log(start_x, stop_x); - console.log(start_y, stop_y) - ctx.moveTo(start_x, start_y); ctx.lineTo(stop_x, stop_y); - - ctx.moveTo(this.rail_stop_x, this.rail_stop_y); } } diff --git a/frontend/static/js/api/game/Wall.js b/frontend/static/js/api/game/Wall.js new file mode 100644 index 0000000..8d027c6 --- /dev/null +++ b/frontend/static/js/api/game/Wall.js @@ -0,0 +1,20 @@ + + +class Wall +{ + constructor (rail_start_x, rail_start_y, rail_stop_x, rail_stop_y) + { + this.rail_start_x = rail_start_x; + this.rail_start_y = rail_start_y; + this.rail_stop_x = rail_stop_x; + this.rail_stop_y = rail_stop_y; + } + + draw(ctx) + { + ctx.moveTo(this.rail_start_x, this.rail_start_y); + ctx.lineTo(this.rail_stop_x, this.rail_stop_y); + } +} + +export { Wall } \ No newline at end of file diff --git a/frontend/static/js/utils/sleep.js b/frontend/static/js/utils/sleep.js new file mode 100644 index 0000000..72867ad --- /dev/null +++ b/frontend/static/js/utils/sleep.js @@ -0,0 +1,6 @@ +function sleep(ms) +{ + return new Promise(resolve => setTimeout(resolve, ms)); +} + +export {sleep} \ No newline at end of file diff --git a/frontend/static/js/views/GameView.js b/frontend/static/js/views/GameView.js index 8bfcddd..4e56c1c 100644 --- a/frontend/static/js/views/GameView.js +++ b/frontend/static/js/views/GameView.js @@ -12,7 +12,6 @@ export default class extends AbstractView super(params, "Game"); this.game = new Game(client, params.id); this.keys_pressed = []; - this.time = new Time(); this.my_player = undefined; } @@ -33,7 +32,13 @@ export default class extends AbstractView { let ctx = document.getElementById('canva').getContext('2d'); + ctx.beginPath(); + this.game.draw(ctx); + + ctx.strokeStyle = "#000000"; + ctx.lineWidth = 10; + ctx.stroke(); } render_game() @@ -42,8 +47,8 @@ export default class extends AbstractView if (this.my_player) this.my_player.update_paddle(this.keys_pressed); this.draw(); - this.time.new_frame(); - //clearInterval(loop_id); + this.game.time.new_frame(); + clearInterval(loop_id); // 1 sec fps }, 1000 / 60); } @@ -60,15 +65,9 @@ export default class extends AbstractView document.removeEventListener('keyup', this.keyStretchHandler); } - start_game() + async start_game() { - let index = this.game.players.findIndex((player) => player.id); - if (index !== -1) - { - let my_player = this.game.players[index]; - this.my_player = new MyPlayer(client, my_player.pos, my_player.nb_goal, my_player.game, this.time); - this.game.players[index] = this.my_player; - } + await this.game.join() let canva = document.createElement("canvas"); @@ -78,19 +77,33 @@ export default class extends AbstractView document.getElementById("app").appendChild(canva); - this.game.join() - this.register_key() this.render_game(); + + let index = this.game.players.findIndex((player) => player.id); + if (index !== -1) + { + let my_player = this.game.players[index]; + this.my_player = new MyPlayer(client, + this.game, + my_player.rail_start_x, + my_player.rail_start_y, + my_player.rail_stop_y, + my_player.rail_stop_y, + my_player.nb_goal, + my_player.positon, + ); + this.game.players[index] = this.my_player; + } } - update_game_state() + async update_game_state() { document.getElementById("game-state").innerText = this.game.state; if (this.game.started === true && this.game.finished === false) - this.start_game(); + await this.start_game(); } async postInit() @@ -100,7 +113,7 @@ export default class extends AbstractView if (error_code) return error_code; - this.update_game_state(); + await this.update_game_state(); } async leavePage() diff --git a/games/config.py b/games/config.py index 3b9599c..88e90bd 100644 --- a/games/config.py +++ b/games/config.py @@ -4,6 +4,8 @@ PADDLE_RATIO = 0.3 MAP_SIZE_X = 700 MAP_SIZE_Y = 700 +MAP_CENTER_X = MAP_SIZE_X / 2 +MAP_CENTER_Y = MAP_SIZE_Y / 2 WALL_RATIO = 1 diff --git a/games/consumers.py b/games/consumers.py index 6129256..a2c6524 100644 --- a/games/consumers.py +++ b/games/consumers.py @@ -6,8 +6,11 @@ import json from .objects.GameRoomManager import GameRoomManager from .objects.GameMember import GameMember +from .objects.Game import Game +from .objects.GameManager import GameManager game_room_manager: GameRoomManager = GameRoomManager() +game_manager: GameManager = GameManager() class GameWebSocket(WebsocketConsumer): @@ -16,6 +19,9 @@ class GameWebSocket(WebsocketConsumer): self.channel_name = "games" self.group_name = "games" + def send_game_data(self): + self.member.send("init_game", self.game.to_dict()) + def connect(self): self.user: User = self.scope["user"] @@ -25,6 +31,8 @@ class GameWebSocket(WebsocketConsumer): self.channel_layer.group_add(self.group_name, self.channel_name) self.game_id = int(self.scope['url_route']['kwargs']['game_id']) + + self.game = game_manager.get(self.game_id) self.room = game_room_manager.get(self.game_id) @@ -36,6 +44,8 @@ class GameWebSocket(WebsocketConsumer): self.room.append(self.member) + self.send_game_data() + def receive(self, text_data: str = None, bytes_data: bytes = None): if (text_data is None): diff --git a/games/objects/Ball.py b/games/objects/Ball.py index 73b9505..5fa8725 100644 --- a/games/objects/Ball.py +++ b/games/objects/Ball.py @@ -3,7 +3,19 @@ from .. import config class Ball: def __init__(self) -> None: - self.x: float = config.BALL_SPAWN_POS_X - self.y: float = config.BALL_SPAWN_POS_Y - self.speed: float = config.BALL_SPEED_START + self.postion_x: float = config.BALL_SPAWN_POS_X + self.postion_y: float = config.BALL_SPAWN_POS_Y + self.velocity_x: float = config.BALL_SPEED_START + self.velocity_y: float = config.BALL_SPEED_START + + def to_dict(self): + + data: dict = { + "position_x": self.postion_x, + "position_y": self.postion_y, + "velocity_x": self.velocity_x, + "velocity_y": self.velocity_y, + } + + return data \ No newline at end of file diff --git a/games/objects/Game.py b/games/objects/Game.py index 42b7a9b..ff03683 100644 --- a/games/objects/Game.py +++ b/games/objects/Game.py @@ -1,8 +1,53 @@ from .Ball import Ball -from .Paddle import Paddle +from .Player import Player +from .Wall import Wall + +import math + +from .. import config + +from ..models import GameModel class Game: - def __init__(self, paddles: [Paddle], ball: Ball) -> None: - self.ball: Ball = ball - self.paddles: [paddles] = paddles \ No newline at end of file + def __init__(self, game_id: int) -> None: + self.ball: Ball = Ball() + game: GameModel = GameModel.objects.get(pk = game_id) + players_id: [int] = game.get_players_id() + + radius: float = min(config.MAP_SIZE_X, config.MAP_SIZE_Y) / 2 - 10 + + nb_sides = len(players_id) * 2 + + self.polygon = [] + + for i in range(nb_sides): + + angle: float = (i * 2 * math.pi / nb_sides) + (math.pi * 3 / 4) + + x: float = config.MAP_CENTER_X + radius * math.cos(angle) + y: float = config.MAP_CENTER_Y + radius * math.sin(angle) + + self.polygon.append((x, y)) + + self.players: list(Player) = [] + self.walls: list(Wall) = [] + + for i in range(nb_sides): + if (i % 2 == 0): + self.players.append(Player(players_id[ i // 2], *self.polygon[i], *self.polygon[(i + 1) % nb_sides])) + else: + self.walls.append(Wall(*self.polygon[i], *self.polygon[(i + 1) % nb_sides])) + + self.game_id: int = game_id + + def to_dict(self): + + data: dict = {"ball": self.ball.to_dict(), + "players": [player.to_dict() for player in self.players], + "walls": [wall.to_dict() for wall in self.walls], + } + + print(data) + + return data \ No newline at end of file diff --git a/games/objects/GameManager.py b/games/objects/GameManager.py new file mode 100644 index 0000000..81c18b8 --- /dev/null +++ b/games/objects/GameManager.py @@ -0,0 +1,22 @@ + +from .Game import Game +from ..models import GameModel + +class GameManager(): + + def __init__(self) -> None: + self._game_list: [Game] = [] + + def get(self, game_id: int): + + if (not GameModel.objects.filter(pk = game_id, started = True, finished = False).exists()): + return None + + for game in self._game_list: + game: Game + if (game.game_id == game_id): + return game + + return Game(game_id) + + \ No newline at end of file diff --git a/games/objects/GameMember.py b/games/objects/GameMember.py index aa5cbfd..c2187c6 100644 --- a/games/objects/GameMember.py +++ b/games/objects/GameMember.py @@ -44,7 +44,7 @@ class GameMember(AbstractRoomMember): new_position.position = data.get("position") - if (new_position is None): + if (new_position.position is None): self.send_error("missing new_position") return diff --git a/games/objects/Player.py b/games/objects/Player.py index 7efd400..7f4f148 100644 --- a/games/objects/Player.py +++ b/games/objects/Player.py @@ -2,12 +2,27 @@ class Player: - def __init__(self, user_id, pos, nb_goal, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y) -> None: + def __init__(self, user_id, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y) -> None: self.user_id = user_id - self.pos = pos - self.nb_goal = nb_goal + self.position = 0.5 + self.nb_goal = 0 self.rail_start_x = rail_start_x self.rail_start_y = rail_start_y self.rail_stop_x = rail_stop_x - self.rail_stop_y = rail_stop_y \ No newline at end of file + self.rail_stop_y = rail_stop_y + + def to_dict(self): + + data = { + "user_id": self.user_id, + "position": self.position, + "nb_goal": self.nb_goal, + + "rail_start_x": self.rail_start_x, + "rail_start_y": self.rail_start_y, + "rail_stop_x": self.rail_stop_x, + "rail_stop_y": self.rail_stop_y, + } + + return data \ No newline at end of file diff --git a/games/objects/Wall.py b/games/objects/Wall.py new file mode 100644 index 0000000..4a96907 --- /dev/null +++ b/games/objects/Wall.py @@ -0,0 +1,20 @@ + + +class Wall: + + def __init__(self, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y) -> None: + self.rail_start_x = rail_start_x + self.rail_start_y = rail_start_y + self.rail_stop_x = rail_stop_x + self.rail_stop_y = rail_stop_y + + def to_dict(self): + + data = { + "rail_start_x": self.rail_start_x, + "rail_start_y": self.rail_start_y, + "rail_stop_x": self.rail_stop_x, + "rail_stop_y": self.rail_stop_y, + } + + return data \ No newline at end of file