diff --git a/frontend/static/js/api/game/Ball.js b/frontend/static/js/api/game/Ball.js index 31c734a..bcd0ca1 100644 --- a/frontend/static/js/api/game/Ball.js +++ b/frontend/static/js/api/game/Ball.js @@ -1,22 +1,45 @@ +import { Game } from "./Game.js"; +import { Point } from "./Point.js"; class Ball { + /** + * + * @param {Game} game + * @param {Number} position_x + * @param {Number} position_y + * @param {Number} velocity_x + * @param {Number} velocity_y + */ constructor(game, position_x, position_y, velocity_x, velocity_y) { + /** + * @type {Game} + */ this.game = game; + /** + * @type {Number} + */ this.position_x = position_x; + /** + * @type {Number} + */ this.position_y = position_y; + /** + * @type {Number} + */ this.velocity_x = velocity_x; + /** + * @type {Number} + */ this.velocity_y = velocity_y; } - _collision(old_pos_x, old_pos_y, new_pos_x, new_pos_y) - { - - return 0; - } - + /** + * + * @param {CanvasRenderingContext2D} ctx + */ draw(ctx) { ctx.rect(this.position_x, this.position_y, this.game.config.ball_size, this.game.config.ball_size); @@ -24,8 +47,14 @@ class Ball render() { - new_pos_x = this.position_x + this.velocity_x * this.game.time.deltaTime(); - new_pos_y = this.position_y + this.velocity_y * this.game.time.deltaTime(); + /** + * @type {Number} + */ + let new_pos_x = this.position_x + this.velocity_x * this.game.time.deltaTime(); + /** + * @type {Number} + */ + let new_pos_y = position_y + this.velocity_y * this.game.time.deltaTime(); if (this._collision(this.position_x, this.position_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 f5e708d..08253b0 100644 --- a/frontend/static/js/api/game/Game.js +++ b/frontend/static/js/api/game/Game.js @@ -1,7 +1,6 @@ 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"; @@ -20,6 +19,10 @@ class Game this.id = id; } + /** + * + * @returns {Number} + */ async init() { let response = await this.client._get(`/api/games/${this.id}`); @@ -35,7 +38,7 @@ class Game this.finished = response_data.finished; this.winner_id = this.finished ? response_data.winner_id : undefined; - if (this.finished === true || this.started === false) + if (this.finished === true) return 0; this.config = new GameConfig(this.client); @@ -51,6 +54,10 @@ class Game return 0; } + /** + * + * @param {CanvasRenderingContext2D} ctx + */ draw_sides(ctx) { this.walls.forEach(wall => { @@ -61,6 +68,10 @@ class Game }); } + /** + * + * @param {CanvasRenderingContext2D} ctx + */ draw(ctx) { ctx.clearRect(0, 0, this.config.size_x, this.config.size_y); @@ -91,6 +102,7 @@ class Game _receive_player_join(player_data) { + console.log(player_data) let index = this.players.indexOf((player) => player.id === player_data.user_id); this.players[index].is_connected = true; @@ -126,7 +138,6 @@ class Game _receive(data) { - console.log(data) if (data.detail === "update_paddle") this._receive_update_paddle(data); else if (data.detail === "update_ball") @@ -147,26 +158,13 @@ class Game 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.walls.push(new Wall().from_json(wall_data)); }); 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.position, - player_data.is_connected, - )); - + this.players.push(new Player(this).from_json(player_data)); }); this._inited = true; @@ -180,7 +178,7 @@ class Game async join() { - if (this.started !== true || this.finished === true) + if (this.finished === true) { console.error("The Game is not currently ongoing."); return; diff --git a/frontend/static/js/api/game/GameConfig.js b/frontend/static/js/api/game/GameConfig.js index ebf8116..dab00ad 100644 --- a/frontend/static/js/api/game/GameConfig.js +++ b/frontend/static/js/api/game/GameConfig.js @@ -20,21 +20,56 @@ class GameConfig let response_data = await response.json(); - + /** + * @type {Number} + */ this.size_x = response_data.MAP_SIZE_X; + /** + * @type {Number} + */ this.size_y = response_data.MAP_SIZE_Y; + /** + * @type {Number} + */ this.center_x = this.size_x / 2; + /** + * @type {Number} + */ this.center_y = this.size_y / 2; + /** + * @type {Number} + */ this.paddle_ratio = response_data.PADDLE_RATIO; + /** + * @type {Number} + */ this.paddle_speed_per_second_max = response_data.PADDLE_SPEED_PER_SECOND_MAX; + /** + * @type {Number} + */ this.wall_ratio = response_data.WALL_RATIO; + /** + * @type {Number} + */ this.ball_speed_inc = response_data.BALL_SPEED_INC; + /** + * @type {Number} + */ this.ball_speed_start = response_data.BALL_SPEED_START; + /** + * @type {Number} + */ this.ball_size = response_data.BALL_SIZE; + /** + * @type {Number} + */ this.ball_spawn_x = this.center_x; + /** + * @type {Number} + */ this.ball_spawn_y = this.center_y; return 0; diff --git a/frontend/static/js/api/game/MyPlayer.js b/frontend/static/js/api/game/MyPlayer.js index a75c19b..552d9f2 100644 --- a/frontend/static/js/api/game/MyPlayer.js +++ b/frontend/static/js/api/game/MyPlayer.js @@ -1,17 +1,35 @@ import { Player } from "./Player.js"; - +import { Client } from "../client.js" +import { Game } from "./Game.js"; +import { Segment } from "./Segment.js"; class MyPlayer extends Player { - constructor(client, game, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y, nb_goal, positon) + /** + * + * @param {Client} client + * @param {Game} game + * @param {Segment} rail + * @param {Number} nb_goal + * @param {Number} position + */ + constructor(client, game, rail, nb_goal, position) { - super(client.me.id, game, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y, nb_goal, positon, true); + super(game, client.me.id, rail, nb_goal, position, true); + /** + * @type {Client} + */ this.client = client; } + /** + * + * @param {[string]} keys_pressed + * @returns + */ update_paddle(keys_pressed) { - let new_pos = this.positon; + let new_pos = this.position; if (keys_pressed.includes("s")) new_pos -= this.game.config.paddle_speed_per_second_max * this.game.time.deltaTimeSecond() * 1.0; @@ -20,14 +38,19 @@ class MyPlayer extends Player 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.positon === new_pos) + if (this.position === new_pos) return; - this.positon = new_pos; + this.position = new_pos; - this.game._send_paddle_position(this.positon, this.game.time._current_frame); + this.game._send_paddle_position(this.position, this.game.time._current_frame); } + /** + * + * @param {Number} new_position + * @param {Number} time + */ update_pos(new_position, time) { let position_verified = new_position; @@ -36,14 +59,14 @@ class MyPlayer extends Player let sign = this - new_position >= 0 ? 1 : -1; - let distance = Math.abs(this.positon - new_position); + let distance = Math.abs(this.position - 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.positon = position_verified; + this.position = position_verified; } } diff --git a/frontend/static/js/api/game/Player.js b/frontend/static/js/api/game/Player.js index cc838ea..44ee621 100644 --- a/frontend/static/js/api/game/Player.js +++ b/frontend/static/js/api/game/Player.js @@ -1,52 +1,153 @@ +import { Game } from "./Game.js"; +import { Point } from "./Point.js"; +import { Segment } from "./Segment.js"; class Player { - constructor(id, game, rail_start_x, rail_start_y, rail_stop_x, rail_stop_y, nb_goal, positon, is_connected) + /** + * + * @param {Number} id + * @param {Game} game + * @param {Segment} rail + * @param {Number} nb_goal + * @param {Number} position + * @param {Boolean} is_connected + */ + constructor(game, id, rail, nb_goal, position, is_connected) { - this.is_connected = is_connected; - this.id = id; - this.positon = positon; - this.nb_goal = nb_goal; + /** + * @type {Game} + */ this.game = game; - 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; + /** + * @type {Boolean} + */ + this.is_connected = is_connected; - this.rail_size = Math.abs(this.rail_stop_x - this.rail_start_x) + Math.abs(this.rail_stop_y - this.rail_start_y) - + /** + * @type {Number} + */ + this.id = id; + + /** + * @type {Number} + */ + this.position = position; + + /** + * @type {Number} + */ + this.nb_goal = nb_goal; + + /** + * @type {Segment} + */ + this.rail = rail === undefined ? new Segment() : rail; + + /** + * @type {Number} + */ + this.rail_size = Math.abs(this.rail.stop.x - this.rail.start.x) + Math.abs(this.rail.stop.y - this.rail.start.y); + + /** + * @type {Number} + */ this.paddle_size = this.rail_size * this.game.config.paddle_ratio; + + /** + * @type {Number} + */ + this.diff_x = this.rail.stop.x - this.rail.start.x; - this.diff_x = this.rail_stop_x - this.rail_start_x, - this.diff_y = this.rail_stop_y - this.rail_start_y; + /** + * @type {Number} + */ + this.diff_y = this.rail.stop.y - this.rail.start.y; } + /** + * + * @param {Number} new_position + */ update_pos(new_position, time) { - this.positon = new_position; + this.position = new_position; } + /** + * @param {CanvasRenderingContext2D} ctx + */ draw(ctx) { if (this.is_connected === false) { - ctx.moveTo(this.rail_start_x, this.rail_start_y); - ctx.lineTo(this.rail_stop_x, this.rail_stop_y); + ctx.moveTo(this.rail.start.x, this.rail.start.y); + ctx.lineTo(this.rail.stop.x, this.rail.stop.y); return; } - 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 paddle_pos = new Point(this.rail.start.x + this.diff_x * this.position, + this.rail.start.y + this.diff_y * this.position); - 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)); + 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)); ctx.moveTo(start_x, start_y); ctx.lineTo(stop_x, stop_y); } + + from_json(data) + { + /** + * @type {Boolean} + */ + + this.is_connected = data.is_connected; + /** + * @type {Number} + */ + this.id = data.user_id; + + /** + * @type {Number} + */ + this.position = data.position.position ; + + /** + * @type {Number} + */ + this.nb_goal = data.nb_goal; + + /** + * @type {Segment} + */ + this.rail = this.rail.from_json(data.rail); + + /** + * @type {Number} + */ + this.rail_size = Math.abs(this.rail.stop.x - this.rail.start.x) + Math.abs(this.rail.stop.y - this.rail.start.y); + + /** + * @type {Number} + */ + this.paddle_size = this.rail_size * this.game.config.paddle_ratio; + + /** + * @type {Number} + */ + this.diff_x = this.rail.stop.x - this.rail.start.x; + + /** + * @type {Number} + */ + this.diff_y = this.rail.stop.y - this.rail.start.y; + + return this + } } export { Player } \ No newline at end of file diff --git a/frontend/static/js/api/game/Point.js b/frontend/static/js/api/game/Point.js new file mode 100644 index 0000000..3280668 --- /dev/null +++ b/frontend/static/js/api/game/Point.js @@ -0,0 +1,30 @@ + + +class Point +{ + /** + * @param {Number} x + * @param {Number} y + */ + constructor(x, y) + { + /** + * @type {Number} + */ + this.x = x; + /** + * @type {Number} + */ + this.y = y; + } + + from_json(data) + { + this.x = data.x + this.y = data.y + + return this + } +} + +export { Point } \ No newline at end of file diff --git a/frontend/static/js/api/game/Segment.js b/frontend/static/js/api/game/Segment.js new file mode 100644 index 0000000..7d6fedc --- /dev/null +++ b/frontend/static/js/api/game/Segment.js @@ -0,0 +1,33 @@ +import { Point } from "./Point.js" + +class Segment +{ + /** + * @param {Point} start + * @param {Point} stop + */ + constructor(start, stop) + { + this.start = start === undefined ? new Point() : start; + this.stop = stop === undefined ? new Point() : stop; + } + + /** + * @param {CanvasRenderingContext2D} ctx + */ + draw(ctx) + { + ctx.moveTo(this.start.x, this.start.y); + ctx.lineTo(this.stop.x, this.stop.y); + } + + from_json(data) + { + this.start = this.start.from_json(data.start); + this.stop = this.stop.from_json(data.stop); + + return this; + } +} + +export { Segment } \ No newline at end of file diff --git a/frontend/static/js/api/game/Time.js b/frontend/static/js/api/game/Time.js index da180f8..e8885b9 100644 --- a/frontend/static/js/api/game/Time.js +++ b/frontend/static/js/api/game/Time.js @@ -4,7 +4,14 @@ class Time { constructor() { + /** + * @type {Number} + */ this._last_frame = undefined; + + /** + * @type {Number} + */ this._current_frame = undefined; } diff --git a/frontend/static/js/api/game/Wall.js b/frontend/static/js/api/game/Wall.js index 8d027c6..be69f42 100644 --- a/frontend/static/js/api/game/Wall.js +++ b/frontend/static/js/api/game/Wall.js @@ -1,19 +1,28 @@ - +import { Segment } from "./Segment.js"; class Wall { - constructor (rail_start_x, rail_start_y, rail_stop_x, rail_stop_y) + /** + * @param {Segment} start + */ + constructor (rail) { - 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; + /** + * @type {Segment} + */ + this.rail = rail === undefined ? new Segment() : rail; } draw(ctx) { - ctx.moveTo(this.rail_start_x, this.rail_start_y); - ctx.lineTo(this.rail_stop_x, this.rail_stop_y); + this.rail.draw(ctx); + } + + from_json(data) + { + this.rail = this.rail.from_json(data.rail) + + return this } } diff --git a/frontend/static/js/views/GameView.js b/frontend/static/js/views/GameView.js index e0fdc4f..2b8e3c7 100644 --- a/frontend/static/js/views/GameView.js +++ b/frontend/static/js/views/GameView.js @@ -1,9 +1,7 @@ import { client } from "../index.js"; import { Game } from "../api/game/Game.js"; import AbstractView from "./abstracts/AbstractView.js"; -import { Time } from "../api/game/Time.js"; import { MyPlayer } from "../api/game/MyPlayer.js"; -import { Ball } from "../api/game/Ball.js"; export default class extends AbstractView { @@ -35,6 +33,9 @@ export default class extends AbstractView if (canva === null) return 1; + /** + * @type {CanvasRenderingContext2D} + */ let ctx = canva.getContext('2d'); ctx.beginPath(); @@ -71,7 +72,7 @@ export default class extends AbstractView document.removeEventListener('keyup', this.keyStretchHandler); } - async start_game() + async join_game() { await this.game.join() @@ -89,16 +90,13 @@ export default class extends AbstractView 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_x, - my_player.rail_stop_y, - my_player.nb_goal, - my_player.positon, + my_player.rail, + my_player.nb_gool, + my_player.position, ); this.game.players[index] = this.my_player; } - + this.register_key() this.render_game(); @@ -108,8 +106,8 @@ export default class extends AbstractView { document.getElementById("game-state").innerText = this.game.state; - if (this.game.started === true && this.game.finished === false) - await this.start_game(); + if (this.game.finished === false) + await this.join_game(); } async postInit() @@ -124,7 +122,7 @@ export default class extends AbstractView async leavePage() { - if (this.game.started === true && this.game.finished === false) + if (this.game.finished === false) { this.game.leave(); this.game = undefined; diff --git a/games/consumers.py b/games/consumers.py index 837e02c..3b457c8 100644 --- a/games/consumers.py +++ b/games/consumers.py @@ -23,6 +23,7 @@ class GameWebSocket(WebsocketConsumer): super().__init__(*args, **kwargs) self.channel_name = "games" self.group_name = "games" + self.member = None def connect(self): @@ -30,20 +31,23 @@ class GameWebSocket(WebsocketConsumer): if (self.user.pk is None): self.user.pk = 0 - self.channel_layer.group_add(self.group_name, self.channel_name) + self.accept() self.game_id = int(self.scope['url_route']['kwargs']['game_id']) self.game: Game = game_manager.get(self.game_id) - + if (self.game is None): - self.send("Game not found.") - self.disconnect(1017) - + self.send(text_data=json.dumps({"detail": "Game not found"})) + self.disconnect(1404) + return + self.member: Player | Spectator = self.game.join(self.user.pk, self) def disconnect(self, code): - self.member.disconnect() + if (self.member is not None): + self.member.disconnect() + super().disconnect(code) def receive(self, text_data: str = None, bytes_data: bytes = None): diff --git a/games/objects/Ball.py b/games/objects/Ball.py index 5fa8725..4d2dbcb 100644 --- a/games/objects/Ball.py +++ b/games/objects/Ball.py @@ -7,10 +7,12 @@ class Ball: 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 + self.size: float = config.BALL_SIZE def to_dict(self): data: dict = { + "size": self.size, "position_x": self.postion_x, "position_y": self.postion_y, "velocity_x": self.velocity_x, diff --git a/games/objects/Game.py b/games/objects/Game.py index 7db38c7..72b6fa8 100644 --- a/games/objects/Game.py +++ b/games/objects/Game.py @@ -9,6 +9,8 @@ from .Ball import Ball from .Player import Player from .Spectator import Spectator from .Wall import Wall +from .Point import Point +from .Segment import Segment import math @@ -34,30 +36,34 @@ class Game(AbstractRoom): players_id: list[int] = self.model.get_players_id() - self.nb_sides = len(players_id) * 2 + nb_sides = len(players_id) * 2 - self.polygon: list[tuple[float, float]] = [] + polygon: list[Point] = [] - for i in range(self.nb_sides): + for i in range(nb_sides): - angle: float = (i * 2 * math.pi / self.nb_sides) + (math.pi * 3 / 4) + 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)) + polygon.append(Point(x, y)) + + segments: list[Point] = [] + for i in range(nb_sides): + segments.append(Segment(polygon[i], polygon[(i + 1) % nb_sides])) self.players: list[Player] = [] for i, player_id in enumerate(players_id): - player = Player(self, player_id, None, *self.polygon[i * 2], *self.polygon[(i * 2 + 1) % self.nb_sides]) + player = Player(self, player_id, None, segments[i * 2]) self.players.append(player) self.spectators: list[Spectator] = [] self.walls: list[Wall] = [] - for i in range(1, self.nb_sides, 2): - self.walls.append(Wall(*self.polygon[i], *self.polygon[(i + 1) % self.nb_sides])) + for i in range(1, nb_sides, 2): + self.walls.append(Wall(segments[i])) self._updated_players: list[Player] = [] @@ -86,12 +92,11 @@ class Game(AbstractRoom): def get_player_by_user_id(self, user_id: int) -> Player: for player in self.players: - player: Player if (player.user_id == user_id): return player return None - def _send_game_data(self, member: AbstractRoomMember): + def _send_game_data(self, member: Spectator | Player): member.send("init_game", self.to_dict()) def everbody_is_here(self): @@ -109,20 +114,24 @@ class Game(AbstractRoom): if (player.is_connected()): player.disconnect(1001) - - player.connect(socket) + player.socket = socket + if (self.everbody_is_here()): + print("chie moi dessu") print("start") self.start() - + + self._update_player(player) + return player def _update_player(self, player: Player): self._updated_players.append(player) def _player_leave(self, player: Player): - self._updated_players.append(player) + print(player.socket) + self._update_player(player) def _spectator_join(self, user_id: int, socket: WebsocketConsumer): @@ -130,8 +139,6 @@ class Game(AbstractRoom): self.spectators.append(spectator) - spectator.accept() - return spectator def _spectator_leave(self, spectator: Spectator): diff --git a/games/objects/GameManager.py b/games/objects/GameManager.py index d953690..1f5eba5 100644 --- a/games/objects/GameManager.py +++ b/games/objects/GameManager.py @@ -9,7 +9,7 @@ class GameManager(): def get(self, game_id: int) -> Game: - if (not GameModel.objects.filter(pk = game_id, started = True, finished = False).exists()): + if (not GameModel.objects.filter(pk = game_id, finished = False).exists()): return None for game in self._game_list: diff --git a/games/objects/Player.py b/games/objects/Player.py index f9a10ea..9d6ca6d 100644 --- a/games/objects/Player.py +++ b/games/objects/Player.py @@ -6,6 +6,8 @@ from channels.generic.websocket import WebsocketConsumer from .Position import Position from .Spectator import Spectator +from .Point import Point +from .Segment import Segment from typing import TYPE_CHECKING @@ -15,7 +17,7 @@ if TYPE_CHECKING: class Player(Spectator): - def __init__(self, game: Game, user_id: int, socket: WebsocketConsumer, rail_start_x: float, rail_start_y: float, rail_stop_x: float, rail_stop_y: float) -> None: + def __init__(self, game: Game, user_id: int, socket: WebsocketConsumer, rail: Segment) -> None: super().__init__(user_id, socket, game) @@ -23,10 +25,7 @@ class Player(Spectator): self.nb_goal: int = 0 - self.rail_start_x: float = rail_start_x - self.rail_start_y: float = rail_start_y - self.rail_stop_x: float = rail_stop_x - self.rail_stop_y: float = rail_stop_y + self.rail: Segment = rail def receive(self, data: dict): @@ -106,19 +105,17 @@ class Player(Spectator): def disconnect(self, code: int = 1000): self.socket = None + print("bozoman") self.game.leave(self) - def to_dict(self): + def to_dict(self) -> dict: data = { "user_id": self.user_id, "position": self.position.to_dict(), "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, + "rail": self.rail.to_dict(), "is_connected": self.is_connected(), } diff --git a/games/objects/Point.py b/games/objects/Point.py new file mode 100644 index 0000000..3d01a04 --- /dev/null +++ b/games/objects/Point.py @@ -0,0 +1,16 @@ + + +class Point: + + def __init__(self, x: float, y: float) -> None: + self.x = x + self.y = y + + def to_dict(self): + + data: dict[str: float] = { + "x": self.x, + "y": self.y, + } + + return data \ No newline at end of file diff --git a/games/objects/Segment.py b/games/objects/Segment.py new file mode 100644 index 0000000..8de44c5 --- /dev/null +++ b/games/objects/Segment.py @@ -0,0 +1,17 @@ + +from .Point import Point + +class Segment: + + def __init__(self, start: Point, stop: Point) -> None: + self.start: Point = start + self.stop: Point = stop + + def to_dict(self): + + data: dict[str: dict] = { + "start": self.start.to_dict(), + "stop": self.stop.to_dict(), + } + + return data \ No newline at end of file diff --git a/games/objects/Wall.py b/games/objects/Wall.py index 4a96907..c18e13f 100644 --- a/games/objects/Wall.py +++ b/games/objects/Wall.py @@ -1,20 +1,15 @@ +from .Segment import Segment 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 __init__(self, rail: Segment) -> None: + self.rail: Segment = rail - def to_dict(self): + def to_dict(self) -> dict[str: dict]: 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, + "rail": self.rail.to_dict(), } return data \ No newline at end of file diff --git a/games/routine.py b/games/routine.py index c77e707..6d52fe0 100644 --- a/games/routine.py +++ b/games/routine.py @@ -5,16 +5,68 @@ from typing import TYPE_CHECKING if TYPE_CHECKING: from .objects.Spectator import Spectator from .objects.Player import Player - from .objects.Game import Game + from .objects.Game import Game + from .objects.Ball import Ball + +from .objects.Point import Point +from .objects.Segment import Segment from . import config +import math from time import sleep +#see the video to understand the algorithme +#https://www.youtube.com/watch?v=KOYoMYWUTEo +def determine_director_coefficient(segment: Segment): + return ((segment.start.y - segment.stop.y) / (segment.start.x - segment.stop.x)) + +def determine_ordinate_at_origin(point: Point, director_cofficient: float): + return point.y - point.x * director_cofficient + +def determine_intersection(director_coefficient1: float, ordinate_at_origin1: float, director_coefficient2: float, ordinate_at_origin2: float): + if (director_coefficient1 == director_coefficient2): + return None + return (ordinate_at_origin1 + ordinate_at_origin2) / (director_coefficient1 + director_coefficient2) + +def determine_intersections(ball: Ball, segments: list[Segment]): + + intersections: list[Point] = [] + + for segment in segments: + + # form m * x + p + m: float = determine_director_coefficient(segment) + p: float = determine_ordinate_at_origin(segment.start, m) + + x: float = determine_intersection(m, p, ball.velocity_y, 0) + + if (x is None): + continue + + y: float = m * x + p + + intersections.append(Point(x, y)) + + return intersections + +def determine_distance_between_ball_and_wall(ball: Ball, segments: list[Segment]): + + intersections: list[Point] = determine_intersections(ball, segments) + + distances = list(map(math.dist, intersections)) + + return min(distances) + +def render(ball: Ball, game: Game): + + segments: list[Segment] = [player.rail for player in game.players] + + print(determine_distance_between_ball_and_wall(ball)) + def routine(game: Game): while True: - for player in game._updated_players: game.broadcast("update_paddle", player.to_dict(), [player])