Browse Source

* More DTOs for pong game

* Pong games get deleted properly
* Added bounce angles to pong walls
master
vvandenb 2 years ago
parent
commit
babe1abcdd
  1. 12
      back/volume/src/pong/dtos/GameCreationDtoValidated.ts
  2. 12
      back/volume/src/pong/dtos/GameInfo.ts
  3. 7
      back/volume/src/pong/dtos/GameUpdate.ts
  4. 23
      back/volume/src/pong/dtos/MapDtoValidated.ts
  5. 10
      back/volume/src/pong/dtos/PointDtoValidated.ts
  6. 14
      back/volume/src/pong/dtos/RectDtoValidated.ts
  7. 3
      back/volume/src/pong/dtos/StringDto.ts
  8. 7
      back/volume/src/pong/dtos/StringDtoValidated.ts
  9. 16
      back/volume/src/pong/game/Ball.ts
  10. 38
      back/volume/src/pong/game/Game.ts
  11. 55
      back/volume/src/pong/game/Games.ts
  12. 15
      back/volume/src/pong/game/Map.ts
  13. 4
      back/volume/src/pong/game/Paddle.ts
  14. 32
      back/volume/src/pong/game/constants.ts
  15. 50
      back/volume/src/pong/pong.gateway.ts
  16. 8
      front/volume/src/App.svelte
  17. 24
      front/volume/src/components/Chat2.svelte
  18. 10
      front/volume/src/components/Pong/Game.ts
  19. 12
      front/volume/src/components/Pong/MapCustomization.svelte
  20. 59
      front/volume/src/components/Pong/Pong.svelte
  21. 32
      front/volume/src/components/Pong/constants.ts
  22. 12
      front/volume/src/components/Pong/dtos/GameInfo.ts
  23. 7
      front/volume/src/components/Pong/dtos/GameUpdate.ts
  24. 3
      front/volume/src/components/Pong/dtos/StringDto.ts

12
back/volume/src/pong/dtos/GameCreationDto.ts → back/volume/src/pong/dtos/GameCreationDtoValidated.ts

@ -2,24 +2,20 @@ import { Type } from 'class-transformer'
import {
ArrayMaxSize,
ArrayMinSize,
IsDefined,
IsNotEmptyObject,
IsObject,
IsString,
ValidateNested
} from 'class-validator'
import { Map } from '../game/Map'
import { MapDtoValidated } from './MapDtoValidated'
export class GameCreationDto {
export class GameCreationDtoValidated {
@IsString({ each: true })
@ArrayMaxSize(2)
@ArrayMinSize(2)
playerNames!: string[]
@IsDefined()
@IsObject()
@IsNotEmptyObject()
@ValidateNested()
@Type(() => Map)
map!: Map
@Type(() => MapDtoValidated)
map!: MapDtoValidated
}

12
back/volume/src/pong/dtos/GameInfo.ts

@ -0,0 +1,12 @@
import { type Point, type Rect } from '../game/utils'
export class GameInfo {
mapSize!: Point
yourPaddleIndex!: number
gameId!: string
walls!: Rect[]
paddleSize!: Point
playerXOffset!: number
ballSize!: Point
winScore!: number
}

7
back/volume/src/pong/dtos/GameUpdate.ts

@ -0,0 +1,7 @@
import { type Point } from '../game/utils'
export class GameUpdate {
paddlesPositions!: Point[]
ballPosition!: Point
scores!: number[]
}

23
back/volume/src/pong/dtos/MapDtoValidated.ts

@ -0,0 +1,23 @@
import { Type } from 'class-transformer'
import {
ArrayMaxSize,
IsArray,
IsDefined,
IsObject,
ValidateNested
} from 'class-validator'
import { PointDtoValidated } from './PointDtoValidated'
import { RectDtoValidated } from './RectDtoValidated'
export class MapDtoValidated {
@IsObject()
@IsDefined()
@Type(() => PointDtoValidated)
size!: PointDtoValidated
@IsArray()
@ArrayMaxSize(5)
@ValidateNested({ each: true })
@Type(() => RectDtoValidated)
walls!: RectDtoValidated[]
}

10
back/volume/src/pong/dtos/PointDtoValidated.ts

@ -0,0 +1,10 @@
import { IsNumber } from 'class-validator'
import { Point } from '../game/utils'
export class PointDtoValidated extends Point {
@IsNumber()
x!: number
@IsNumber()
y!: number
}

14
back/volume/src/pong/dtos/RectDtoValidated.ts

@ -0,0 +1,14 @@
import { Type } from 'class-transformer'
import { ValidateNested } from 'class-validator'
import { Rect } from '../game/utils'
import { PointDtoValidated } from './PointDtoValidated'
export class RectDtoValidated extends Rect {
@ValidateNested()
@Type(() => PointDtoValidated)
center!: PointDtoValidated
@ValidateNested()
@Type(() => PointDtoValidated)
size!: PointDtoValidated
}

3
back/volume/src/pong/dtos/StringDto.ts

@ -0,0 +1,3 @@
export class StringDto {
value!: string
}

7
back/volume/src/pong/dtos/StringDtoValidated.ts

@ -0,0 +1,7 @@
import { IsString } from 'class-validator'
import { StringDto } from './StringDto'
export class StringDtoValidated extends StringDto {
@IsString()
value!: string
}

16
back/volume/src/pong/game/Ball.ts

@ -1,7 +1,7 @@
import { gameInfoConstants } from './constants'
import { type Paddle } from './Paddle'
import { Point, Rect } from './utils'
import { type Map } from './Map'
import { type MapDtoValidated } from '../dtos/MapDtoValidated'
import { DEFAULT_BALL_SIZE } from './constants'
export class Ball {
rect: Rect
@ -11,7 +11,7 @@ export class Ball {
constructor (
spawn: Point,
size: Point = gameInfoConstants.ballSize,
size: Point = DEFAULT_BALL_SIZE,
speed: Point = new Point(10, 2)
) {
this.rect = new Rect(spawn, size)
@ -24,7 +24,7 @@ export class Ball {
return this.indexPlayerScored
}
update (canvasRect: Rect, paddles: Paddle[], map: Map): void {
update (canvasRect: Rect, paddles: Paddle[], map: MapDtoValidated): void {
if (!canvasRect.contains_x(this.rect)) {
this.indexPlayerScored = this.playerScored()
} else {
@ -33,7 +33,7 @@ export class Ball {
}
}
move (canvasRect: Rect, paddles: Paddle[], map: Map): void {
move (canvasRect: Rect, paddles: Paddle[], map: MapDtoValidated): void {
for (const paddle of paddles) {
if (paddle.rect.collides(this.rect)) {
if (this.speed.x < 0) {
@ -49,8 +49,12 @@ export class Ball {
for (const wall of map.walls) {
if (wall.collides(this.rect)) {
if (this.speed.x < 0) {
this.rect.center.x = wall.center.x + wall.size.x
} else this.rect.center.x = wall.center.x - wall.size.x
this.speed.x = this.speed.x * -1
this.speed.y = this.speed.y * -1
this.speed.y =
((this.rect.center.y - wall.center.y) / wall.size.y) * 20
break
}
}

38
back/volume/src/pong/game/Game.ts

@ -3,14 +3,17 @@ import { type WebSocket } from 'ws'
import { formatWebsocketData, Point, Rect } from './utils'
import { Player } from './Player'
import {
type GameInfo,
gameInfoConstants,
type GameUpdate,
DEFAULT_BALL_SIZE,
DEFAULT_PADDLE_SIZE,
DEFAULT_PLAYER_X_OFFSET,
DEFAULT_WIN_SCORE,
GAME_EVENTS
} from './constants'
import { randomUUID } from 'crypto'
import { Spectator } from './Spectator'
import { type Map } from './Map'
import { type MapDtoValidated } from '../dtos/MapDtoValidated'
import { type GameUpdate } from '../dtos/GameUpdate'
import { type GameInfo } from '../dtos/GameInfo'
const GAME_TICKS = 30
@ -28,7 +31,7 @@ function gameLoop (game: Game): void {
const indexPlayerScored: number = game.ball.getIndexPlayerScored()
if (indexPlayerScored !== -1) {
game.players[indexPlayerScored].score += 1
if (game.players[indexPlayerScored].score >= gameInfoConstants.winScore) {
if (game.players[indexPlayerScored].score >= DEFAULT_WIN_SCORE) {
console.log(`${game.players[indexPlayerScored].name} won!`)
game.stop()
}
@ -49,22 +52,25 @@ function gameLoop (game: Game): void {
export class Game {
id: string
timer: NodeJS.Timer | null
map: Map
map: MapDtoValidated
ball: Ball
players: Player[] = []
spectators: Spectator[] = []
playing: boolean
gameStoppedCallback: (name: string) => void
constructor (
sockets: WebSocket[],
uuids: string[],
names: string[],
map: Map
map: MapDtoValidated,
gameStoppedCallback: (name: string) => void
) {
this.id = randomUUID()
this.timer = null
this.playing = false
this.map = map
this.gameStoppedCallback = gameStoppedCallback
this.ball = new Ball(new Point(this.map.size.x / 2, this.map.size.y / 2))
for (let i = 0; i < uuids.length; i++) {
this.addPlayer(sockets[i], uuids[i], names[i])
@ -74,11 +80,14 @@ export class Game {
getGameInfo (name: string): GameInfo {
const yourPaddleIndex = this.players.findIndex((p) => p.name === name)
return {
...gameInfoConstants,
mapSize: this.map.size,
yourPaddleIndex,
gameId: this.id,
walls: this.map.walls
walls: this.map.walls,
paddleSize: DEFAULT_PADDLE_SIZE,
playerXOffset: DEFAULT_PLAYER_X_OFFSET,
ballSize: DEFAULT_BALL_SIZE,
winScore: DEFAULT_WIN_SCORE
}
}
@ -88,13 +97,10 @@ export class Game {
}
private addPlayer (socket: WebSocket, uuid: string, name: string): void {
let paddleCoords = new Point(
gameInfoConstants.playerXOffset,
this.map.size.y / 2
)
let paddleCoords = new Point(DEFAULT_PLAYER_X_OFFSET, this.map.size.y / 2)
if (this.players.length === 1) {
paddleCoords = new Point(
this.map.size.x - gameInfoConstants.playerXOffset,
this.map.size.x - DEFAULT_PLAYER_X_OFFSET,
this.map.size.y / 2
)
}
@ -130,10 +136,8 @@ export class Game {
this.players.forEach((p) => {
p.newGame()
})
this.timer = setInterval(gameLoop, 1000 / GAME_TICKS, this)
this.broadcastGame(formatWebsocketData(GAME_EVENTS.START_GAME))
console.log('Started game')
this.playing = true
return true
}
@ -142,11 +146,11 @@ export class Game {
stop (): void {
if (this.timer !== null) {
this.gameStoppedCallback(this.players[0].name)
clearInterval(this.timer)
this.timer = null
this.players = []
this.playing = false
console.log('Stopped game')
}
}

55
back/volume/src/pong/game/Games.ts

@ -1,10 +1,15 @@
import { type WebSocket } from 'ws'
import { type GameInfo } from './constants'
import { Game } from './Game'
import { Point } from './utils'
import { gameInfoConstants } from './constants'
import { type Map as GameMap } from './Map'
import { type GameCreationDto } from '../dtos/GameCreationDto'
import { type MapDtoValidated as GameMap } from '../dtos/MapDtoValidated'
import { type GameCreationDtoValidated } from '../dtos/GameCreationDtoValidated'
import { type GameInfo } from '../dtos/GameInfo'
import {
DEFAULT_BALL_SIZE,
DEFAULT_PADDLE_SIZE,
DEFAULT_PLAYER_X_OFFSET,
DEFAULT_WIN_SCORE
} from './constants'
export class Games {
private readonly playerNameToGameIndex = new Map<string, number>()
@ -13,15 +18,27 @@ export class Games {
newGame (
sockets: WebSocket[],
uuids: string[],
gameCreationDto: GameCreationDto
gameCreationDto: GameCreationDtoValidated
): void {
const names: string[] = gameCreationDto.playerNames
const map: GameMap = gameCreationDto.map
if (!this.isInAGame(names[0]) && !this.isInAGame(names[1])) {
this.games.push(new Game(sockets, uuids, names, map))
this.games.push(
new Game(
sockets,
uuids,
names,
map,
this.gameStopped.bind(this, names[0])
)
)
this.playerNameToGameIndex.set(names[0], this.games.length - 1)
this.playerNameToGameIndex.set(names[1], this.games.length - 1)
console.log(`Created game ${names[0]} vs ${names[1]}`)
console.log(
`Created game ${names[0]} vs ${names[1]} (${
this.games[this.games.length - 1].id
})`
)
}
}
@ -39,13 +56,16 @@ export class Games {
}
}
// stopGame (uuid: string): void {
// // if (this.isInAGame(uuid)) {
// // this.playerGame(uuid).stop()
// // delete this.playerNameToGameIndex[uuid]
// // delete this.games[this.playerNameToGameIndex[uuid]]
// // }
// }
private gameStopped (name: string): void {
const game: Game | null = this.playerGame(name)
if (game !== null) {
this.games.splice(this.games.indexOf(game), 1)
game.players.forEach((player) => {
this.playerNameToGameIndex.delete(player.name)
})
console.log(`Game stopped: ${game.id}`)
}
}
getGameInfo (name: string): GameInfo {
const game: Game | null = this.playerGame(name)
@ -53,11 +73,14 @@ export class Games {
return game.getGameInfo(name)
}
return {
...gameInfoConstants,
yourPaddleIndex: 0,
gameId: '',
mapSize: new Point(0, 0),
walls: []
walls: [],
paddleSize: DEFAULT_PADDLE_SIZE,
playerXOffset: DEFAULT_PLAYER_X_OFFSET,
ballSize: DEFAULT_BALL_SIZE,
winScore: DEFAULT_WIN_SCORE
}
}

15
back/volume/src/pong/game/Map.ts

@ -1,15 +0,0 @@
import { Type } from 'class-transformer'
import { ArrayMaxSize, IsArray, IsDefined, IsObject } from 'class-validator'
import { Point, Rect } from './utils'
export class Map {
@IsObject()
@IsDefined()
@Type(() => Point)
size!: Point
@IsArray()
@ArrayMaxSize(5)
@Type(() => Rect)
walls!: Rect[]
}

4
back/volume/src/pong/game/Paddle.ts

@ -1,4 +1,4 @@
import { gameInfoConstants } from './constants'
import { DEFAULT_PADDLE_SIZE } from './constants'
import { type Point, Rect } from './utils'
export class Paddle {
@ -9,7 +9,7 @@ export class Paddle {
constructor (
spawn: Point,
gameSize: Point,
size: Point = gameInfoConstants.paddleSize
size: Point = DEFAULT_PADDLE_SIZE
) {
this.rect = new Rect(spawn, size)
this.mapSize = gameSize

32
back/volume/src/pong/game/constants.ts

@ -1,4 +1,4 @@
import { Point, type Rect } from './utils'
import { Point } from './utils'
export const GAME_EVENTS = {
START_GAME: 'START_GAME',
@ -11,28 +11,8 @@ export const GAME_EVENTS = {
SPECTATE: 'SPECTATE'
}
export interface GameInfo extends GameInfoConstants {
yourPaddleIndex: number
gameId: string
walls: Rect[]
}
export interface GameInfoConstants {
mapSize: Point
paddleSize: Point
playerXOffset: number
ballSize: Point
winScore: number
}
export const gameInfoConstants: GameInfoConstants = {
mapSize: new Point(600, 400),
paddleSize: new Point(6, 50),
playerXOffset: 50,
ballSize: new Point(20, 20),
winScore: 9999
}
export interface GameUpdate {
paddlesPositions: Point[]
ballPosition: Point
scores: number[]
}
export const DEFAULT_MAP_SIZE = new Point(600, 400)
export const DEFAULT_PADDLE_SIZE = new Point(6, 50)
export const DEFAULT_BALL_SIZE = new Point(20, 20)
export const DEFAULT_PLAYER_X_OFFSET = 50
export const DEFAULT_WIN_SCORE = 5

50
back/volume/src/pong/pong.gateway.ts

@ -9,11 +9,14 @@ import {
} from '@nestjs/websockets'
import { randomUUID } from 'crypto'
import { Games } from './game/Games'
import { formatWebsocketData, Point, Rect } from './game/utils'
import { formatWebsocketData } from './game/utils'
import { GAME_EVENTS } from './game/constants'
import { GameCreationDto } from './dtos/GameCreationDto'
import { GameCreationDtoValidated } from './dtos/GameCreationDtoValidated'
import { UsePipes, ValidationPipe } from '@nestjs/common'
import { type Game } from './game/Game'
import { plainToClass } from 'class-transformer'
import { PointDtoValidated } from './dtos/PointDtoValidated'
import { StringDtoValidated } from './dtos/StringDtoValidated'
interface WebSocketWithId extends WebSocket {
id: string
@ -44,14 +47,15 @@ export class PongGateway implements OnGatewayConnection, OnGatewayDisconnect {
}
}
@UsePipes(new ValidationPipe({ whitelist: true }))
@SubscribeMessage(GAME_EVENTS.REGISTER_PLAYER)
registerPlayer (
@ConnectedSocket()
client: WebSocketWithId,
@MessageBody('playerName') playerName: string
): void {
this.socketToPlayerName.set(client, playerName)
console.log('Connected ', this.socketToPlayerName.get(client))
@MessageBody() playerName: StringDtoValidated
): { event: string, data: StringDtoValidated } {
this.socketToPlayerName.set(client, playerName.value)
return { event: GAME_EVENTS.REGISTER_PLAYER, data: playerName }
}
@SubscribeMessage(GAME_EVENTS.GET_GAME_INFO)
@ -67,14 +71,19 @@ export class PongGateway implements OnGatewayConnection, OnGatewayDisconnect {
}
}
@UsePipes(new ValidationPipe({ whitelist: true }))
@SubscribeMessage(GAME_EVENTS.PLAYER_MOVE)
movePlayer (
@ConnectedSocket()
client: WebSocketWithId,
@MessageBody('position') position: Point
@MessageBody() position: PointDtoValidated
): void {
const realPosition: PointDtoValidated = plainToClass(
PointDtoValidated,
position
)
const name: string | undefined = this.socketToPlayerName.get(client)
this.games.movePlayer(name, position)
this.games.movePlayer(name, realPosition)
}
@UsePipes(new ValidationPipe({ whitelist: true }))
@ -82,27 +91,27 @@ export class PongGateway implements OnGatewayConnection, OnGatewayDisconnect {
createGame (
@ConnectedSocket()
client: WebSocketWithId,
@MessageBody() gameCreationDto: GameCreationDto
@MessageBody() gameCreationDto: GameCreationDtoValidated
): void {
gameCreationDto.map.walls = gameCreationDto.map.walls.map((wall) => {
return new Rect(
new Point(wall.center.x, wall.center.y),
new Point(wall.size.x, wall.size.y)
)
})
const realGameCreationDto: GameCreationDtoValidated = plainToClass(
GameCreationDtoValidated,
gameCreationDto
)
if (this.socketToPlayerName.size >= 2) {
const player1Socket: WebSocketWithId | undefined = Array.from(
this.socketToPlayerName.keys()
).find(
(key) =>
this.socketToPlayerName.get(key) === gameCreationDto.playerNames[0]
this.socketToPlayerName.get(key) ===
realGameCreationDto.playerNames[0]
)
const player2Socket: WebSocketWithId | undefined = Array.from(
this.socketToPlayerName.keys()
).find(
(key) =>
this.socketToPlayerName.get(key) === gameCreationDto.playerNames[1]
this.socketToPlayerName.get(key) ===
realGameCreationDto.playerNames[1]
)
if (
@ -114,7 +123,7 @@ export class PongGateway implements OnGatewayConnection, OnGatewayDisconnect {
this.games.newGame(
[player1Socket, player2Socket],
[player1Socket.id, player2Socket.id],
gameCreationDto
realGameCreationDto
)
}
}
@ -131,15 +140,16 @@ export class PongGateway implements OnGatewayConnection, OnGatewayDisconnect {
}
}
@UsePipes(new ValidationPipe({ whitelist: true }))
@SubscribeMessage(GAME_EVENTS.SPECTATE)
spectate (
@ConnectedSocket()
client: WebSocketWithId,
@MessageBody('playerToSpectate') playerToSpectate: string
@MessageBody() playerToSpectate: StringDtoValidated
): void {
const name: string | undefined = this.socketToPlayerName.get(client)
if (name !== undefined) {
this.games.spectateGame(playerToSpectate, client, client.id, name)
this.games.spectateGame(playerToSpectate.value, client, client.id, name)
}
}
}

8
front/volume/src/App.svelte

@ -79,7 +79,13 @@
</script>
<main>
<Navbar {clickProfile} {clickHistory} {clickFriends} {clickSpectate} {clickChat} />
<Navbar
{clickProfile}
{clickHistory}
{clickFriends}
{clickSpectate}
{clickChat}
/>
{#if isChatOpen}
<div
on:click={() => (isChatOpen = false)}

24
front/volume/src/components/Chat2.svelte

@ -6,20 +6,16 @@
</script>
<script lang="ts">
const sendMessage = () => {
if (newText !== '')
{
const newMessage = {
name: 'You',
text: newText
};
chatMessages = [
...chatMessages,
newMessage
];
newText = '';
}
}
const sendMessage = () => {
if (newText !== "") {
const newMessage = {
name: "You",
text: newText,
};
chatMessages = [...chatMessages, newMessage];
newText = "";
}
};
export let chatMessages: Array<chatMessagesType> = [];
let newText = "";
</script>

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

@ -1,6 +1,7 @@
import { Ball } from "./Ball";
import { GAME_EVENTS } from "./constants";
import type { GameInfo, GameUpdate } from "./constants";
import type { GameInfo } from "./dtos/GameInfo";
import type { GameUpdate } from "./dtos/GameUpdate";
import { Paddle } from "./Paddle";
import { Player } from "./Player";
import { formatWebsocketData, Point, Rect } from "./utils";
@ -58,11 +59,8 @@ export class Game {
if (this.my_paddle) {
this.canvas.addEventListener("mousemove", (e) => {
this.my_paddle.move(e);
socket.send(
formatWebsocketData(GAME_EVENTS.PLAYER_MOVE, {
position: this.my_paddle.rect.center,
})
);
const data: Point = this.my_paddle.rect.center;
socket.send(formatWebsocketData(GAME_EVENTS.PLAYER_MOVE, data));
});
console.log("Game started!");
}

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

@ -2,7 +2,7 @@
import { onMount } from "svelte";
import { Point, Rect } from "./utils";
import type { Map } from "./Map";
import { gameInfoConstants } from "./constants";
import { DEFAULT_BALL_SIZE } from "./constants";
export let map: Map;
let canvas: HTMLCanvasElement;
@ -48,14 +48,12 @@
new Point(e.offsetX, e.offsetY),
new Point(wallWidth, wallHeight)
);
const ballSpawn = new Rect(
const ballSpawnArea = new Rect(
new Point(map.size.x / 2, map.size.y / 2),
new Point(
gameInfoConstants.ballSize.x * 5,
gameInfoConstants.ballSize.y * 5
)
new Point(DEFAULT_BALL_SIZE.x * 5, DEFAULT_BALL_SIZE.y * 5)
);
if (map.walls.length < 5 && !wall.collides(ballSpawn)) map.walls.push(wall);
if (map.walls.length < 5 && !wall.collides(ballSpawnArea))
map.walls.push(wall);
}
function removeWall(e: MouseEvent) {

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

@ -1,39 +1,36 @@
<script lang="ts">
import { gameInfoConstants, GAME_EVENTS } from "./constants";
import { DEFAULT_MAP_SIZE, GAME_EVENTS } from "./constants";
import type { GameCreationDto } from "./dtos/GameCreationDto";
import { Game } from "./Game";
import MapCustomization from "./MapCustomization.svelte";
import { formatWebsocketData, Point } from "./utils";
import { formatWebsocketData } from "./utils";
import { Map } from "./Map";
import { onMount } from "svelte";
import type { StringDto } from "./dtos/StringDto";
const FPS = 144;
const SERVER_URL = "ws://localhost:3001";
let gameCanvas: HTMLCanvasElement;
let connected: boolean = false;
let loggedIn: boolean = false;
let socket: WebSocket;
let username: string = "John";
let otherUsername: string = "Garfield";
let spectateUsername: string = "Garfield";
let map: Map = new Map(
new Point(gameInfoConstants.mapSize.x, gameInfoConstants.mapSize.y),
[]
);
let map: Map = new Map(DEFAULT_MAP_SIZE.clone(), []);
//Get canvas and its context
window.onload = () => {
const canvas: HTMLCanvasElement = document.getElementById(
"pong_canvas"
) as HTMLCanvasElement;
if (canvas) {
const context: CanvasRenderingContext2D = canvas.getContext(
onMount(() => {
if (gameCanvas) {
const context: CanvasRenderingContext2D = gameCanvas.getContext(
"2d"
) as CanvasRenderingContext2D;
if (context) {
setupSocket(canvas, context);
setupSocket(gameCanvas, context);
}
}
};
});
function setupSocket(
canvas: HTMLCanvasElement,
@ -58,8 +55,18 @@
}, 1000 / FPS);
console.log("Game updated!");
}
} else if (event == GAME_EVENTS.REGISTER_PLAYER) {
console.log("Registered player: " + data.value);
if (data.value == username) {
loggedIn = true;
setInterval(() => {
updateGameInfo();
}, 1000);
}
} else {
console.log("Unknown event from server: " + event);
console.log(
"Unknown event from server: " + event + " with data " + data
);
}
};
socket.onopen = () => {
@ -76,29 +83,21 @@
}
function spectate() {
socket.send(
formatWebsocketData(GAME_EVENTS.SPECTATE, {
playerToSpectate: spectateUsername,
})
);
const data: StringDto = { value: spectateUsername };
socket.send(formatWebsocketData(GAME_EVENTS.SPECTATE, data));
}
function logIn() {
socket.send(
formatWebsocketData(GAME_EVENTS.REGISTER_PLAYER, { playerName: username })
);
loggedIn = true;
setInterval(() => {
updateGameInfo();
}, 1000);
const data: StringDto = { value: username };
socket.send(formatWebsocketData(GAME_EVENTS.REGISTER_PLAYER, data));
}
function createGame() {
const gameCreationDto: GameCreationDto = {
const data: GameCreationDto = {
playerNames: [username, otherUsername],
map,
};
socket.send(formatWebsocketData(GAME_EVENTS.CREATE_GAME, gameCreationDto));
socket.send(formatWebsocketData(GAME_EVENTS.CREATE_GAME, data));
}
</script>
@ -130,7 +129,7 @@
{:else}
Connecting to game server...
{/if}
<canvas id="pong_canvas" />
<canvas bind:this={gameCanvas} />
</div>
<MapCustomization {map} />
</div>

32
front/volume/src/components/Pong/constants.ts

@ -1,4 +1,4 @@
import { Point, Rect } from "./utils";
import { Point } from "./utils";
export const GAME_EVENTS = {
START_GAME: "START_GAME",
@ -11,28 +11,8 @@ export const GAME_EVENTS = {
SPECTATE: "SPECTATE",
};
export interface GameInfo extends GameInfoConstants {
yourPaddleIndex: number;
gameId: string;
walls: Rect[];
}
export interface GameInfoConstants {
mapSize: Point;
paddleSize: Point;
playerXOffset: number;
ballSize: Point;
winScore: number;
}
export const gameInfoConstants: GameInfoConstants = {
mapSize: new Point(600, 400),
paddleSize: new Point(6, 50),
playerXOffset: 50,
ballSize: new Point(20, 20),
winScore: 9999,
};
export interface GameUpdate {
paddlesPositions: Point[];
ballPosition: Point;
scores: number[];
}
export const DEFAULT_MAP_SIZE = new Point(600, 400);
export const DEFAULT_PADDLE_SIZE = new Point(6, 50);
export const DEFAULT_BALL_SIZE = new Point(20, 20);
export const DEFAULT_PLAYER_X_OFFSET = 50;
export const DEFAULT_WIN_SCORE = 5;

12
front/volume/src/components/Pong/dtos/GameInfo.ts

@ -0,0 +1,12 @@
import type { Point, Rect } from "../utils";
export class GameInfo {
mapSize!: Point;
yourPaddleIndex!: number;
gameId!: string;
walls!: Rect[];
paddleSize!: Point;
playerXOffset!: number;
ballSize!: Point;
winScore!: number;
}

7
front/volume/src/components/Pong/dtos/GameUpdate.ts

@ -0,0 +1,7 @@
import type { Point } from "../utils";
export class GameUpdate {
paddlesPositions!: Point[];
ballPosition!: Point;
scores!: number[];
}

3
front/volume/src/components/Pong/dtos/StringDto.ts

@ -0,0 +1,3 @@
export class StringDto {
value!: string;
}
Loading…
Cancel
Save