From 58c0df447ca70e71b9f07189799ee07faa06a1bb Mon Sep 17 00:00:00 2001 From: starnakin Date: Tue, 16 Jan 2024 17:47:31 +0100 Subject: [PATCH] player pos is checked --- frontend/static/js/api/game/Game.js | 28 ++++--- frontend/static/js/api/game/MyPlayer.js | 27 ++++++- frontend/static/js/api/game/Player.js | 5 ++ frontend/static/js/views/GameView.js | 3 +- games/config.py | 1 + games/consumers.py | 54 +++++++------ games/models.py | 2 +- games/objects/Ball.py | 1 + games/objects/GameMember.py | 101 +++++++++++++++++++++--- games/objects/Position.py | 10 +++ 10 files changed, 180 insertions(+), 52 deletions(-) create mode 100644 games/objects/Position.py diff --git a/frontend/static/js/api/game/Game.js b/frontend/static/js/api/game/Game.js index d55b390..4d2cce3 100644 --- a/frontend/static/js/api/game/Game.js +++ b/frontend/static/js/api/game/Game.js @@ -16,6 +16,7 @@ class Game this.client = client; this.id = id; this.keys_pressed = []; + this.last_pos = null } async init() @@ -57,6 +58,7 @@ class Game { if (this._socket === undefined) return; + const loop_id = setInterval(() => { if (this._socket.readyState === WebSocket.OPEN) { @@ -66,24 +68,25 @@ class Game }, 500); } - _send_paddle(my_player) + _send_paddle(position, time) { - this._send({"detail": "update_my_paddle_pos", "position": my_player.pos}); + if (this.last_pos !== null && this.last_pos.time >= time) + return; + + this.last_pos = {"time": time, "position": position}; + + this._send({"detail": "update_my_paddle_pos", ...this.last_pos}); } _update_paddles(data) { - data.forEach(player_data => { - let player = this.players.find(player_data2 => player_data2.id === player_data) - + console.log(data) + data.players.forEach((player_data) => { + let player = this.players.find((player) => player.id === player_data.id); if (player === null) - { - console.error("error 1000: je ne comprends pas"); - return; - } - - player.pos = player_data.pos; - }); + return + player.update_pos(player_data.position, player_data.time); + }) } _update_ball(data) @@ -96,6 +99,7 @@ class Game _update(data) { + console.log("bozo2", data) if (data.detail === "update_paddles") this._update_paddles(data); else if (data.detail === "update_ball") diff --git a/frontend/static/js/api/game/MyPlayer.js b/frontend/static/js/api/game/MyPlayer.js index 715fe82..f33d03d 100644 --- a/frontend/static/js/api/game/MyPlayer.js +++ b/frontend/static/js/api/game/MyPlayer.js @@ -15,15 +15,36 @@ class MyPlayer extends Player let new_pos = this.pos; if (keys_pressed.includes("s")) - new_pos -= this.game.config.paddle_speed_per_second_max * this.time.deltaTimeSecond(); + new_pos -= this.game.config.paddle_speed_per_second_max * this.time.deltaTimeSecond() * 1; if (keys_pressed.includes("w")) - new_pos += this.game.config.paddle_speed_per_second_max * this.time.deltaTimeSecond(); + new_pos += this.game.config.paddle_speed_per_second_max * this.time.deltaTimeSecond() * 1; 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) + return; + console.log(this.client.me.id) this.pos = new_pos; - this.game._send_paddle(this); + this.game._send_paddle(this.pos, this.time._current_frame); + } + + update_pos(new_position, time) + { + let position_verified = new_position; + + let time_diff = (Date.now() - time) / 1000; + + let sign = this - new_position >= 0 ? 1 : -1; + + let distance = Math.abs(this.pos - 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; } } diff --git a/frontend/static/js/api/game/Player.js b/frontend/static/js/api/game/Player.js index adc2fc9..bc555c9 100644 --- a/frontend/static/js/api/game/Player.js +++ b/frontend/static/js/api/game/Player.js @@ -8,6 +8,11 @@ class Player this.nb_goal = nb_goal; this.game = game; } + + update_pos(new_position, time) + { + this.pos = new_position; + } } export { Player } \ No newline at end of file diff --git a/frontend/static/js/views/GameView.js b/frontend/static/js/views/GameView.js index 249fbc7..e6efb07 100644 --- a/frontend/static/js/views/GameView.js +++ b/frontend/static/js/views/GameView.js @@ -109,8 +109,9 @@ export default class extends AbstractView if (this.my_player) this.my_player.update_paddle(this.keys_pressed); this.draw_game(); - this.time.new_frame() + this.time.new_frame(); //clearInterval(loop_id); + // 1 sec fps }, 1000 / 60); } diff --git a/games/config.py b/games/config.py index 2f3511f..3b9599c 100644 --- a/games/config.py +++ b/games/config.py @@ -1,4 +1,5 @@ PADDLE_SPEED_PER_SECOND_MAX = 0.6 +PADDLE_SPEED_PER_SECOND_TOLERANCE = 1.01 PADDLE_RATIO = 0.3 MAP_SIZE_X = 700 diff --git a/games/consumers.py b/games/consumers.py index 4969e6f..6129256 100644 --- a/games/consumers.py +++ b/games/consumers.py @@ -11,35 +11,41 @@ game_room_manager: GameRoomManager = GameRoomManager() class GameWebSocket(WebsocketConsumer): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.channel_name = "games" - self.group_name = "games" + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.channel_name = "games" + self.group_name = "games" - def connect(self): + def connect(self): - self.user: User = self.scope["user"] - if (self.user.is_anonymous or not self.user.is_authenticated): - return + self.user: User = self.scope["user"] + if (self.user.is_anonymous or not self.user.is_authenticated): + return - self.channel_layer.group_add(self.group_name, self.channel_name) + self.channel_layer.group_add(self.group_name, self.channel_name) - self.game_id = int(self.scope['url_route']['kwargs']['game_id']) + self.game_id = int(self.scope['url_route']['kwargs']['game_id']) - self.room = game_room_manager.get(self.game_id) + self.room = game_room_manager.get(self.game_id) - if (self.room is None): - self.send("Game not found.") - self.disconnect(1017) - - self.member = GameMember(self.user.pk, self) - - self.room.append(self.member) + if (self.room is None): + self.send("Game not found.") + self.disconnect(1017) - def receive(self, text_data: str = None, bytes_data: bytes = None): - self.member.receive(text_data) + self.member = GameMember(self.user.pk, self, self.room) - def disconnect(self, close_code): - member = self.room.get_member_by_socket(self) - if (member is not None): - self.room.remove(self.member, close_code) \ No newline at end of file + self.room.append(self.member) + + def receive(self, text_data: str = None, bytes_data: bytes = None): + + if (text_data is None): + return + + data: dict = json.loads(text_data) + + self.member.receive(data) + + def disconnect(self, close_code): + member = self.room.get_member_by_socket(self) + if (member is not None): + self.room.remove(self.member, close_code) \ No newline at end of file diff --git a/games/models.py b/games/models.py index 3113eaf..c08f6ea 100644 --- a/games/models.py +++ b/games/models.py @@ -16,7 +16,7 @@ class GameModel(models.Model): return self.pk def get_players_id(self): - return [game_member.member_id for game_member in GameMembersModel.objects.filter(game_id = self.pk)] + return [game_player.player_id for game_player in GameMembersModel.objects.filter(game_id = self.pk)] class GameMembersModel(models.Model): game_id = models.IntegerField() diff --git a/games/objects/Ball.py b/games/objects/Ball.py index d8ea218..73b9505 100644 --- a/games/objects/Ball.py +++ b/games/objects/Ball.py @@ -5,4 +5,5 @@ 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 \ No newline at end of file diff --git a/games/objects/GameMember.py b/games/objects/GameMember.py index 50cda59..aa5cbfd 100644 --- a/games/objects/GameMember.py +++ b/games/objects/GameMember.py @@ -2,17 +2,96 @@ from channels.generic.websocket import AsyncWebsocketConsumer from transcendence.abstract.AbstractRoomMember import AbstractRoomMember +from .Position import Position + +import time + +from .. import config + +from ..models import GameModel + +MIN_POSITION: float = config.PADDLE_RATIO / 2 +MAX_POSITION: float = 1 - MIN_POSITION + class GameMember(AbstractRoomMember): - def __init__(self, user_id: int, socket: AsyncWebsocketConsumer): - super().__init__(user_id, socket) - self.is_a_player = False - - def receive(self, data: dict): - if (not self.is_a_player): - self.send("You are not a player.") - return + def __init__(self, user_id: int, socket: AsyncWebsocketConsumer, room): + super().__init__(user_id, socket) + self.position: Position = Position(0.5, int(time.time() * 1000.0)) + self.room = room + self.is_a_player = user_id in GameModel.objects.get(pk = self.room.game_id).get_players_id() + + def receive(self, data: dict): + + detail: str = data.get("detail") + + if (detail is None): + return + + if (detail == "update_my_paddle_pos"): + self.update_position(data) + + def send_error(self, error_message: str): + + self.send("error", {"error_message": error_message}) + + def update_position(self, data: dict): + + if (not self.is_a_player): + return + + new_position: Position = Position() + + new_position.position = data.get("position") + + if (new_position is None): + self.send_error("missing new_position") + return + + new_position.time = data.get("time") + + if (new_position.time is None): + self.send_error("missing time") + return + + if (self.position.time > new_position.time): + self.send_error("time error") + return + + distance: float = abs(self.position.position - new_position.position) + + sign = 1 if self.position.position >= new_position.position else -1 + + time_difference = (new_position.time - self.position.time) / 1000 + + max_distance = config.PADDLE_SPEED_PER_SECOND_MAX * (time_difference) * config.PADDLE_SPEED_PER_SECOND_TOLERANCE + + new_position_verified: Position = new_position.copy() - def send_ball(self, ball): - self.send("update_ball_pos", {"x": ball.x, - "y": ball.y}) \ No newline at end of file + if (distance > max_distance): + print(max_distance, distance, time_difference, self.position.position, new_position.position) + new_position_verified.position = self.position.position + max_distance * sign + + if (not MIN_POSITION <= new_position_verified.position <= MAX_POSITION): + + new_position_verified.position = max(new_position_verified.position, MIN_POSITION) + new_position_verified.position = min(new_position_verified.position, MAX_POSITION) + + if (new_position.position != new_position_verified.position): + self.send("update_paddles", { + "players": [ + { + "position": new_position_verified.position, + "time": new_position_verified.time, + "id": self.user_id, + }, + ], + }) + print("trop vite") + + self.position = new_position + + + def send_ball(self, ball): + self.send("update_ball_pos", {"x": ball.x, + "y": ball.y}) \ No newline at end of file diff --git a/games/objects/Position.py b/games/objects/Position.py new file mode 100644 index 0000000..7c119d1 --- /dev/null +++ b/games/objects/Position.py @@ -0,0 +1,10 @@ +from typing import Union + +class Position: + + def __init__(self, position = 0, time: int = 0) -> None: + self.time = time + self.position = position + + def copy(self): + return Position(self.position, self.time) \ No newline at end of file