game: add: PADDLE CAN MOVE

This commit is contained in:
starnakin 2024-01-15 17:54:58 +01:00
parent a2fbfa1937
commit a30ec46685
8 changed files with 154 additions and 49 deletions

View File

@ -1,5 +1,6 @@
import { Ball } from "./Ball.js"; import { Ball } from "./Ball.js";
import { GameConfig } from "./GameConfig.js" import { GameConfig } from "./GameConfig.js"
import { MyPlayer } from "./MyPlayer.js";
import { Player } from "./Player.js"; import { Player } from "./Player.js";
class Game class Game
@ -14,6 +15,7 @@ class Game
*/ */
this.client = client; this.client = client;
this.id = id; this.id = id;
this.keys_pressed = [];
} }
async init() async init()
@ -31,9 +33,7 @@ class Game
this.finished = response_data.finished; this.finished = response_data.finished;
this.winner_id = this.finished ? response_data.winner_id : undefined; this.winner_id = this.finished ? response_data.winner_id : undefined;
//TODO invert line if (this.finished === true || this.started === false)
if (false)
//if (this.finished === true || this.started === false)
return 0; return 0;
this.config = new GameConfig(this.client); this.config = new GameConfig(this.client);
@ -43,8 +43,8 @@ class Game
return ret; return ret;
this.players = []; this.players = [];
response_data.players.forEach(player_data => { response_data.players_id.forEach(player_id => {
let player = new Player(player_data.id, player_data.pos, player_data.nb_goal); let player = new Player(player_id, 0.5, 0, this);
this.players.push(player); this.players.push(player);
}); });
@ -55,12 +55,20 @@ class Game
_send(data) _send(data)
{ {
this._socket.send(JSON.stringify(data)); if (this._socket === undefined)
return;
const loop_id = setInterval(() => {
if (this._socket.readyState === WebSocket.OPEN)
{
this._socket.send(JSON.stringify(data));
clearInterval(loop_id);
}
}, 500);
} }
_send_paddle() _send_paddle(my_player)
{ {
this._send({"detail": "update_my_paddle_pos", "pos": this.players.find(player => player.id === this.client.me.id).pos}); this._send({"detail": "update_my_paddle_pos", "position": my_player.pos});
} }
_update_paddles(data) _update_paddles(data)
@ -91,7 +99,7 @@ class Game
if (data.detail === "update_paddles") if (data.detail === "update_paddles")
this._update_paddles(data); this._update_paddles(data);
else if (data.detail === "update_ball") else if (data.detail === "update_ball")
this._ this._update_ball(data);
} }
join() join()
@ -104,7 +112,7 @@ class Game
let url = `${window.location.protocol[4] === 's' ? 'wss' : 'ws'}://${window.location.host}/ws/games/${this.id}`; let url = `${window.location.protocol[4] === 's' ? 'wss' : 'ws'}://${window.location.host}/ws/games/${this.id}`;
this._socket = WebSocket(url); this._socket = new WebSocket(url);
this._socket.onmessage = (event) => { this._socket.onmessage = (event) => {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);

View File

@ -27,6 +27,7 @@ class GameConfig
this.center_y = this.size_y / 2; this.center_y = this.size_y / 2;
this.paddle_ratio = response_data.PADDLE_RATIO; this.paddle_ratio = response_data.PADDLE_RATIO;
this.paddle_speed_per_second_max = response_data.PADDLE_SPEED_PER_SECOND_MAX;
this.wall_ratio = response_data.WALL_RATIO; this.wall_ratio = response_data.WALL_RATIO;
this.ball_speed_inc = response_data.BALL_SPEED_INC; this.ball_speed_inc = response_data.BALL_SPEED_INC;

View File

@ -1,9 +1,30 @@
import { Player } from "./Player"; import { Player } from "./Player.js";
class MyPlayer extends Player class MyPlayer extends Player
{ {
constructor(client, pos, nb_goal, game, time)
{
super(client.me.id, pos, nb_goal, game);
this.time = time;
this.client = client;
}
update_paddle(keys_pressed)
{
let new_pos = this.pos;
if (keys_pressed.includes("s"))
new_pos -= this.game.config.paddle_speed_per_second_max * this.time.deltaTimeSecond();
if (keys_pressed.includes("w"))
new_pos += this.game.config.paddle_speed_per_second_max * this.time.deltaTimeSecond();
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);
this.pos = new_pos;
this.game._send_paddle(this);
}
} }
export {MyPlayer } export { MyPlayer }

View File

@ -0,0 +1,33 @@
class Time
{
constructor()
{
this._last_frame = undefined;
this._current_frame = undefined;
}
deltaTime()
{
return (this._current_frame - this._last_frame) !== NaN ? this._current_frame - this._last_frame : 0;
}
deltaTimeSecond()
{
return this.deltaTime() / 1000;
}
get_fps()
{
return 1 / this.deltaTimeSecond();
}
new_frame()
{
this._last_frame = this._current_frame;
this._current_frame = Date.now();
}
}
export { Time }

View File

@ -1,13 +1,18 @@
import { client } from "../index.js"; import { client } from "../index.js";
import { Game } from "../api/game/Game.js"; import { Game } from "../api/game/Game.js";
import AbstractView from "./abstracts/AbstractView.js"; import AbstractView from "./abstracts/AbstractView.js";
import { Time } from "../api/game/Time.js";
import { MyPlayer } from "../api/game/MyPlayer.js";
export default class extends AbstractView export default class extends AbstractView
{ {
constructor(params) constructor(params)
{ {
super(params, "Game"); super(params, "Game");
this.game = new Game(client, params.id); this.game = new Game(client, params.id);
this.keys_pressed = [];
this.time = new Time()
this.my_player = undefined;
} }
draw_wall(ctx, stop_x, stop_y) draw_wall(ctx, stop_x, stop_y)
@ -24,25 +29,32 @@ export default class extends AbstractView
let diff_x = rail_stop_x - rail_start_x, let diff_x = rail_stop_x - rail_start_x,
diff_y = rail_stop_y - rail_start_y; diff_y = rail_stop_y - rail_start_y;
let pos_x = rail_start_x + diff_x * pos, let paddle_pos_x = rail_start_x + diff_x * pos,
pos_y = rail_start_y + diff_y * pos; paddle_pos_y = rail_start_y + diff_y * pos;
let start_x = pos_x - (diff_x * (paddle_size / rail_size)), let start_x = paddle_pos_x - (diff_x * (paddle_size / 2 / rail_size)),
start_y = pos_y - (diff_y * (paddle_size / rail_size)), start_y = paddle_pos_y - (diff_y * (paddle_size / 2 / rail_size)),
stop_x = pos_x + (diff_x * (paddle_size / rail_size)), stop_x = paddle_pos_x + (diff_x * (paddle_size / 2 / rail_size)),
stop_y = pos_y + (diff_y * (paddle_size / rail_size)); stop_y = paddle_pos_y + (diff_y * (paddle_size / 2 / rail_size));
console.log(start_x, start_y, stop_x, stop_y);
ctx.moveTo(start_x, start_y); ctx.moveTo(start_x, start_y);
ctx.lineTo(stop_x, stop_y); ctx.lineTo(stop_x, stop_y);
ctx.moveTo(rail_stop_x, rail_stop_y); ctx.moveTo(rail_stop_x, rail_stop_y);
} }
_down() keyStretchHandler(event)
{ {
pl const idx = this.keys_pressed.indexOf(event.key);
} if (idx != -1)
this.keys_pressed.splice(idx, 1);
}
keyPressHandler(event)
{
if (!this.keys_pressed.includes(event.key))
this.keys_pressed.push(event.key);
}
draw_ball(ctx, x, y) draw_ball(ctx, x, y)
{ {
@ -56,20 +68,21 @@ export default class extends AbstractView
stop_x, stop_x,
stop_y; stop_y;
let radius = Math.min(this.game.config.size_x, this.game.config.size_y) / 2 - 10;
for (let i = 0; i <= nb_sides; i++) for (let i = 0; i <= nb_sides; i++)
{ {
let angle = (i * 2 * Math.PI / nb_sides) + (Math.PI * 3 / 4); let angle = (i * 2 * Math.PI / nb_sides) + (Math.PI * 3 / 4);
stop_x = this.game.config.center_x + 400 * Math.cos(angle); stop_x = this.game.config.center_x + radius * Math.cos(angle);
stop_y = this.game.config.center_y + 400 * Math.sin(angle); stop_y = this.game.config.center_y + radius * Math.sin(angle);
if (i == 0) if (i == 0)
ctx.moveTo(stop_x, start_y); ctx.moveTo(stop_x, start_y);
if (i % 2 == 0) if (i % 2 == 0)
this.draw_wall(ctx, stop_x, stop_y); this.draw_wall(ctx, stop_x, stop_y);
else else
this.draw_paddle(ctx, start_x, start_y, stop_x, stop_y, 0.5); this.draw_paddle(ctx, start_x, start_y, stop_x, stop_y, this.game.players[(i - 1) / 2].pos);
start_x = stop_x; start_x = stop_x;
start_y = stop_y; start_y = stop_y;
} }
@ -81,6 +94,7 @@ export default class extends AbstractView
ctx.beginPath() ctx.beginPath()
ctx.clearRect(0, 0, this.game.config.size_x, this.game.config.size_y);
this.draw_sides(ctx, (this.game.players_id.length +0) * 2); this.draw_sides(ctx, (this.game.players_id.length +0) * 2);
this.draw_ball(ctx, this.game.ball_pos_x, this.game.ball_pos_y); this.draw_ball(ctx, this.game.ball_pos_x, this.game.ball_pos_y);
@ -91,12 +105,25 @@ export default class extends AbstractView
render_game() render_game()
{ {
while (true) let loop_id = setInterval(() => {
{ if (this.my_player)
this.my_player.update_paddle(this.keys_pressed);
this.draw_game(); this.draw_game();
// TODO remove the line below this.time.new_frame()
break; //clearInterval(loop_id);
} }, 1000 / 50);
}
register_key()
{
document.addEventListener('keydown', this.keyPressHandler.bind(this));
document.addEventListener('keyup', this.keyStretchHandler.bind(this));
}
unregister_key()
{
document.removeEventListener('keydown', this.keyPressHandler);
document.removeEventListener('keyup', this.keyStretchHandler);
} }
start_game() start_game()
@ -110,18 +137,17 @@ export default class extends AbstractView
document.getElementById("app").appendChild(canva); document.getElementById("app").appendChild(canva);
this.game.join() this.game.join()
this.register_key()
this.render_game(); this.render_game();
} }
async update_game_state() update_game_state()
{ {
await this.game.init();
document.getElementById("game-state").innerText = this.game.state; document.getElementById("game-state").innerText = this.game.state;
//TODO invert line if (this.game.started === true && this.game.finished === false)
//if (this.game.started === true && this.game.finished === false)
if (true)
this.start_game(); this.start_game();
} }
@ -132,9 +158,22 @@ export default class extends AbstractView
if (error_code) if (error_code)
return error_code; return error_code;
await this.update_game_state(); 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;
}
this.update_game_state();
} }
async leavePage()
{
this.unregister_key();
}
async getHtml() async getHtml()
{ {
return /* HTML */ ` return /* HTML */ `

View File

@ -1,8 +1,8 @@
PADDLE_SPEED_PER_SECOND_MAX = 0.5 PADDLE_SPEED_PER_SECOND_MAX = 0.2
PADDLE_RATIO = 0.1 PADDLE_RATIO = 0.3
MAP_SIZE_X = 900 MAP_SIZE_X = 700
MAP_SIZE_Y = 900 MAP_SIZE_Y = 700
WALL_RATIO = 1 WALL_RATIO = 1

View File

@ -1,14 +1,15 @@
from channels.generic.websocket import AsyncWebsocketConsumer from channels.generic.websocket import WebsocketConsumer
from django.contrib.auth.models import User from django.contrib.auth.models import User
import json import json
from .objects.GameRoomManager import GameRoomManager from .objects.GameRoomManager import GameRoomManager
from .objects.GameMember import GameMember
game_room_manager: GameRoomManager = GameRoomManager() game_room_manager: GameRoomManager = GameRoomManager()
class GameWebSocket(AsyncWebsocketConsumer): class GameWebSocket(WebsocketConsumer):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -31,10 +32,12 @@ class GameWebSocket(AsyncWebsocketConsumer):
self.send("Game not found.") self.send("Game not found.")
self.disconnect(1017) self.disconnect(1017)
self.member = GameMember(self.user.pk, self)
self.room.append(self.member) self.room.append(self.member)
def receive(self, text_data: str = None, bytes_data: bytes = None): def receive(self, text_data: str = None, bytes_data: bytes = None):
self.member.receive(text_data, bytes_data) self.member.receive(text_data)
def disconnect(self, close_code): def disconnect(self, close_code):
member = self.room.get_member_by_socket(self) member = self.room.get_member_by_socket(self)

View File

@ -1,7 +1,7 @@
from transcendence.abstract.AbstractRoomManager import AbstractRoomManager from transcendence.abstract.AbstractRoomManager import AbstractRoomManager
from ..models import GameModel from ..models import GameModel
from . import GameRoom from .GameRoom import GameRoom
class GameRoomManager(AbstractRoomManager): class GameRoomManager(AbstractRoomManager):