Browse Source

* Pong: game now responsive

* Pong: reset menus after game ended
master
vvandenb 2 years ago
parent
commit
eb55134f79
  1. 13
      front/volume/src/components/NavBar.svelte
  2. 9
      front/volume/src/components/Pong/Game.ts
  3. 31
      front/volume/src/components/Pong/GameComponent.svelte
  4. 71
      front/volume/src/components/Pong/MapCustomization.svelte
  5. 60
      front/volume/src/components/Pong/Pong.svelte

13
front/volume/src/components/NavBar.svelte

@ -27,28 +27,28 @@
{#if link.text === "Leaderboard"}
<li>
<button on:click={clickLeaderboard}>
<p>Leaderboard</p>
Leaderboard
</button>
</li>
{/if}
{#if link.text === "Spectate"}
<li>
<button on:click={clickSpectate}>
<p>Spectate</p>
Spectate
</button>
</li>
{/if}
{#if link.text === "Channels"}
<li>
<button on:click={clickChannels}>
<p>Channels</p>
Channels
</button>
</li>
{/if}
{#if link.text === "Friends"}
<li>
<button on:click={clickFriends}>
<p>Friends</p>
Friends
</button>
</li>
{/if}
@ -62,7 +62,7 @@
{#if link.text === "History"}
<li>
<button on:click={clickHistory}>
<p>History</p>
History
</button>
</li>
{/if}
@ -111,17 +111,18 @@
.navigation-bar {
flex-direction: column;
align-items: stretch;
padding: 0;
}
.navigation-bar ul {
flex-direction: column;
align-items: center;
justify-content: center;
margin: 4px;
}
.navigation-bar li {
margin: 0;
padding: 1rem;
text-align: center;
}
}

9
front/volume/src/components/Pong/Game.ts

@ -9,6 +9,7 @@ import { formatWebsocketData, Point, Rect } from "./utils";
const FPS = import.meta.env.VITE_FRONT_FPS;
export class Game {
renderCanvas: HTMLCanvasElement;
canvas: HTMLCanvasElement;
context: CanvasRenderingContext2D;
ball: Ball;
@ -21,11 +22,13 @@ export class Game {
backgroundColor: string;
constructor(
renderCanvas: HTMLCanvasElement,
canvas: HTMLCanvasElement,
context: CanvasRenderingContext2D,
elementsColor: string,
backgroundColor: string
) {
this.renderCanvas = renderCanvas;
this.canvas = canvas;
this.context = context;
this.players = [];
@ -37,6 +40,8 @@ export class Game {
}
setInfo(data: GameInfo) {
this.renderCanvas.width = data.mapSize.x;
this.renderCanvas.height = data.mapSize.y;
this.canvas.width = data.mapSize.x;
this.canvas.height = data.mapSize.y;
this.ball = new Ball(
@ -72,7 +77,7 @@ export class Game {
start(socket: WebSocket) {
if (this.my_paddle) {
this.canvas.addEventListener("mousemove", (e) => {
this.renderCanvas.addEventListener("pointermove", (e) => {
this.my_paddle.move(e);
const data: Point = this.my_paddle.rect.center;
socket.send(formatWebsocketData(GAME_EVENTS.PLAYER_MOVE, data));
@ -121,5 +126,7 @@ export class Game {
max_width,
this.context
);
this.renderCanvas.getContext("2d").drawImage(this.canvas, 0, 0);
}
}

31
front/volume/src/components/Pong/GameComponent.svelte

@ -3,30 +3,45 @@
import { GAME_EVENTS } from "./constants";
import { formatWebsocketData } from "./utils";
export let gameCanvas: HTMLCanvasElement;
export let gamePlaying: boolean;
export let setupSocket: (
renderCanvas: HTMLCanvasElement,
canvas: HTMLCanvasElement,
context: CanvasRenderingContext2D
) => void;
export let socket: WebSocket;
let gameCanvas: HTMLCanvasElement;
let renderCanvas: HTMLCanvasElement;
//Get canvas and its context
onMount(() => {
if (gameCanvas) {
const context: CanvasRenderingContext2D = gameCanvas.getContext(
"2d"
) as CanvasRenderingContext2D;
if (gameCanvas && renderCanvas) {
const context: CanvasRenderingContext2D = gameCanvas.getContext("2d");
if (context) {
setupSocket(gameCanvas, context);
setupSocket(renderCanvas, gameCanvas, context);
}
}
});
</script>
<div hidden={!gamePlaying}>
<div hidden={!gamePlaying} class="gameDiv">
<button on:click={() => socket.send(formatWebsocketData(GAME_EVENTS.READY))}
>Ready</button
>
<canvas bind:this={gameCanvas} />
<canvas hidden bind:this={gameCanvas} />
<canvas bind:this={renderCanvas} class="renderCanvas" />
</div>
<style>
.gameDiv {
width: 100%;
height: 100%;
}
.renderCanvas {
width: 100%;
height: auto;
touch-action: none;
}
</style>

71
front/volume/src/components/Pong/MapCustomization.svelte

@ -3,10 +3,11 @@
import { Point, Rect } from "./utils";
import type { Map } from "./Map";
import { DEFAULT_BALL_SIZE, DEFAULT_MAP_SIZE } from "./constants";
import { Ball } from "./Ball";
export let map: Map;
let canvas: HTMLCanvasElement;
let gameCanvas: HTMLCanvasElement;
let context: CanvasRenderingContext2D;
let wallWidth = 20;
let wallHeight = 80;
@ -14,65 +15,95 @@
const MAX_WALLS = 5;
onMount(() => {
if (canvas) {
canvas.width = map.size.x;
canvas.height = map.size.y;
context = canvas.getContext("2d");
if (gameCanvas) {
gameCanvas.width = map.size.x;
gameCanvas.height = map.size.y;
context = gameCanvas.getContext("2d");
drawMap();
}
});
$: {
if (canvas) {
canvas.width = map.size.x;
canvas.height = map.size.y;
}
drawMap();
}
function drawMap() {
if (canvas && context) {
if (gameCanvas && context) {
context.fillStyle = "black";
context.fillRect(0, 0, map.size.x, map.size.y);
for (const wall of map.walls) {
wall.draw(context, "white");
}
const ball = new Ball(
new Point(map.size.x / 2, map.size.y / 2),
DEFAULT_BALL_SIZE
);
ball.draw(context, "white");
}
}
function click(e: MouseEvent, rightClick: boolean) {
if (rightClick) removeWall(e);
else addWall(e);
if (rightClick) {
e.preventDefault();
removeWall(e);
} else {
addWall(e);
}
drawMap();
}
function addWall(e: MouseEvent) {
const rect: any = gameCanvas.getBoundingClientRect();
const wall = new Rect(
new Point(e.offsetX, e.offsetY),
getMapXY(e),
new Point(wallWidth, wallHeight)
);
const ballSpawnArea = new Rect(
new Point(map.size.x / 2, map.size.y / 2),
new Point(DEFAULT_BALL_SIZE.x * 5, DEFAULT_BALL_SIZE.y * 5)
);
if (map.walls.length < MAX_WALLS && !wall.collides(ballSpawnArea))
map.walls.push(wall);
}
function removeWall(e: MouseEvent) {
e.preventDefault();
const click = new Rect(new Point(e.offsetX, e.offsetY), new Point(1, 1));
const click = new Rect(getMapXY(e), new Point(1, 1));
const index = map.walls.findIndex((w) => w.collides(click));
if (index != -1) map.walls.splice(index, 1);
}
function getCanvasXY(pagePoint: Point): Point {
const rect: any = gameCanvas.getBoundingClientRect();
const x = pagePoint.x - rect.left;
const y = pagePoint.y - rect.top;
return new Point(x, y);
}
function getMapXY(e: MouseEvent): Point {
const canvasPoint: Point = getCanvasXY(new Point(e.pageX, e.pageY));
const x = canvasPoint.x * gameCanvas.width / gameCanvas.clientWidth;
const y = canvasPoint.y * gameCanvas.height / gameCanvas.clientHeight;
return new Point(x, y);
}
</script>
<div>
<h1>Map Customization:</h1>
Right click to add walls, left click to remove walls. (Max {MAX_WALLS} walls)
<button
on:click={() => {
map.walls = [];
drawMap();
}}>Clear</button
>
<canvas
bind:this={canvas}
bind:this={gameCanvas}
on:click={(e) => click(e, false)}
on:contextmenu={(e) => click(e, true)}
class="renderCanvas"
/>
</div>
<style>
.renderCanvas {
width: 100%;
height: 100%;
}
</style>

60
front/volume/src/components/Pong/Pong.svelte

@ -19,38 +19,47 @@
let spectateWindow: boolean = false;
let gamePlaying: boolean = false;
let matchmaking: boolean = false;
let gameCanvas: HTMLCanvasElement;
let connected: boolean = false;
let loggedIn: boolean = false;
let failedLogIn: boolean = false;
let socket: WebSocket;
let username: string = $store.username;
let elementsColor: string = "#FFFFFF";
let backgroundColor: string = "#000000";
let game: Game;
let renderCanvas: HTMLCanvasElement;
let canvas: HTMLCanvasElement;
let context: CanvasRenderingContext2D;
function setupSocket(
canvas: HTMLCanvasElement,
context: CanvasRenderingContext2D
_renderCanvas: HTMLCanvasElement,
_canvas: HTMLCanvasElement,
_context: CanvasRenderingContext2D
) {
socket = new WebSocket(SERVER_URL);
game = new Game(canvas, context, elementsColor, backgroundColor);
renderCanvas = _renderCanvas;
canvas = _canvas;
context = _context;
game = new Game(_renderCanvas, canvas, context, elementsColor, backgroundColor);
socket.onmessage = function (e) {
const event_json = JSON.parse(e.data);
const event = event_json.event;
const data = event_json.data;
if (event == GAME_EVENTS.START_GAME) {
matchmaking = false;
game.start(socket);
} else if (event == GAME_EVENTS.GAME_TICK) {
game.update(data);
} else if (event == GAME_EVENTS.GET_GAME_INFO) {
if (data && data.gameId != game.id) {
if (gamePlaying && data.gameId == '') {
resetMenus();
gamePlaying = false;
}
if (data.yourPaddleIndex !== -2) {
gamePlaying = true;
game.setInfo(data);
} else gamePlaying = false;
}
}
} else if (event == GAME_EVENTS.REGISTER_PLAYER) {
if (data) {
@ -78,26 +87,29 @@
);
}
};
socket.onopen = () => {
void logIn();
connected = true;
};
socket.onclose = () => {
connected = false;
setupSocket(canvas, context);
};
socket.onopen = onSocketOpen
socket.onclose = onSocketClose
}
async function onSocketOpen() {
await getUser();
void logIn();
connected = true;
};
async function onSocketClose() {
connected = false;
setupSocket(renderCanvas, canvas, context);
};
function updateGameInfo() {
socket.send(formatWebsocketData(GAME_EVENTS.GET_GAME_INFO));
}
async function logIn() {
await getUser();
const socketKey = $store.socketKey;
const data: { playerName: StringDto; socketKey: StringDto } = {
playerName: { value: username },
socketKey: { value: socketKey },
playerName: { value: $store.username },
socketKey: { value: $store.socketKey },
};
socket.send(formatWebsocketData(GAME_EVENTS.REGISTER_PLAYER, data));
}
@ -112,6 +124,12 @@
socket.send(formatWebsocketData(GAME_EVENTS.MATCHMAKING, data));
}
function resetMenus() {
createMatchWindow = false;
spectateWindow = false;
matchmaking = false;
}
$: {
if (game !== undefined) {
game.updateColors(elementsColor, backgroundColor);
@ -120,7 +138,7 @@
</script>
<main>
<GameComponent {gameCanvas} {gamePlaying} {setupSocket} {socket} />
<GameComponent {gamePlaying} {setupSocket} {socket} />
{#if gamePlaying}
<div />
{:else if loggedIn}
@ -145,7 +163,7 @@
on:click={() => (createMatchWindow = false)}
on:keydown={() => (createMatchWindow = false)}
>
<GameCreation {socket} {username} />
<GameCreation {socket} />
</div>
{:else if spectateWindow}
<div

Loading…
Cancel
Save