game: core: use server game calulation form

This commit is contained in:
starnakin 2024-01-17 14:23:23 +01:00
parent b2dc43c1d8
commit 2bd0624100
15 changed files with 274 additions and 110 deletions

View File

@ -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)

View File

@ -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++)
{
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;
if (this._wall_drew !== true)
{
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()

View File

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

View File

@ -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;
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;
console.log(this)
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);
}
}

View File

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

View File

@ -0,0 +1,6 @@
function sleep(ms)
{
return new Promise(resolve => setTimeout(resolve, ms));
}
export {sleep}

View File

@ -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()

View File

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

View File

@ -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"]
@ -26,6 +32,8 @@ class GameWebSocket(WebsocketConsumer):
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)
if (self.room is None):
@ -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):

View File

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

View File

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

View File

@ -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)

View File

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

View File

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

20
games/objects/Wall.py Normal file
View File

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