this merge with master should come with the right backend stuff to make friendship requests work
This commit is contained in:
@@ -1,53 +0,0 @@
|
||||
|
||||
@font-face {
|
||||
font-family: "Bit5x3";
|
||||
src: url("http://localhost:8080/Bit5x3.woff2") format("woff2"),
|
||||
url("http://localhost:8080/Bit5x3.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
#preload_font {
|
||||
font-family: "Bit5x3";
|
||||
opacity:0;
|
||||
height:0;
|
||||
width:0;
|
||||
display:inline-block;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: #222425;
|
||||
}
|
||||
#canvas_container {
|
||||
text-align: center;
|
||||
/* border: dashed rgb(245, 245, 245) 5px; */
|
||||
/* max-height: 80vh; */
|
||||
/* overflow: hidden; */
|
||||
}
|
||||
#div_game_options {
|
||||
text-align: center;
|
||||
font-family: "Bit5x3";
|
||||
color: rgb(245, 245, 245);
|
||||
font-size: x-large;
|
||||
}
|
||||
#div_game_options fieldset {
|
||||
max-width: 50vw;
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#div_game_options fieldset div {
|
||||
padding: 10px;
|
||||
}
|
||||
#play_pong_button {
|
||||
font-family: "Bit5x3";
|
||||
color: rgb(245, 245, 245);
|
||||
background-color: #333333;
|
||||
font-size: x-large;
|
||||
padding: 10px;
|
||||
}
|
||||
canvas {
|
||||
background-color: #333333;
|
||||
max-width: 75vw;
|
||||
/* max-height: 100vh; */
|
||||
width: 80%;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<link rel="stylesheet" href="pong.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="preload_font">.</div>
|
||||
|
||||
<div id="div_game_options">
|
||||
<fieldset>
|
||||
<legend>game options</legend>
|
||||
<div>
|
||||
<input type="checkbox" id="multi_balls" name="multi_balls">
|
||||
<label for="multi_balls">multiples balls</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="moving_walls" name="moving_walls">
|
||||
<label for="moving_walls">moving walls</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>sound :</label>
|
||||
<input type="radio" id="sound_on" name="sound_selector" checked>
|
||||
<label for="sound_on">on</label>
|
||||
<input type="radio" id="sound_off" name="sound_selector">
|
||||
<label for="sound_off">off</label>
|
||||
</div>
|
||||
<div>
|
||||
<button id="play_pong_button">PLAY</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div id="canvas_container">
|
||||
<!-- <p> =) </p> -->
|
||||
</div>
|
||||
|
||||
<script src="http://localhost:8080/js/pong.js" type="module" defer></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
export * from "../shared_js/constants.js"
|
||||
|
||||
// 15ms == 1000/66.666
|
||||
export const serverGameLoopIntervalMS = 15; // millisecond
|
||||
export const fixedDeltaTime = serverGameLoopIntervalMS/1000; // second
|
||||
|
||||
// 33.333ms == 1000/30
|
||||
export const clientsUpdateIntervalMS = 1000/30; // millisecond
|
||||
@@ -1,8 +0,0 @@
|
||||
|
||||
export * from "../shared_js/utils.js"
|
||||
|
||||
function shortId(id: string): string {
|
||||
return id.substring(0, id.indexOf("-"));
|
||||
}
|
||||
|
||||
export {shortId}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB |
@@ -2,8 +2,8 @@
|
||||
import { WebSocket } from "../wsServer.js";
|
||||
import { Racket } from "../../shared_js/class/Rectangle.js";
|
||||
import { GameSession } from "./GameSession.js";
|
||||
import * as ev from "../../shared_js/class/Event.js"
|
||||
import * as en from "../../shared_js/enums.js"
|
||||
import * as ev from "./Event.js"
|
||||
import * as en from "../enums.js"
|
||||
|
||||
class Client {
|
||||
socket: WebSocket;
|
||||
65
JEU2/src/server/class/GameComponents.ts
Normal file
65
JEU2/src/server/class/GameComponents.ts
Normal file
@@ -0,0 +1,65 @@
|
||||
|
||||
import * as c from "../constants.js"
|
||||
import * as en from "../enums.js"
|
||||
import { VectorInteger } from "./Vector.js";
|
||||
import { Rectangle, MovingRectangle, Racket, Ball } from "./Rectangle.js";
|
||||
import { random } from "../utils.js";
|
||||
|
||||
class GameComponents {
|
||||
wallTop: Rectangle | MovingRectangle;
|
||||
wallBottom: Rectangle | MovingRectangle;
|
||||
playerLeft: Racket;
|
||||
playerRight: Racket;
|
||||
ballsArr: Ball[] = [];
|
||||
constructor(options: en.MatchOptions)
|
||||
{
|
||||
const pos = new VectorInteger;
|
||||
|
||||
// Rackets
|
||||
pos.assign(0+c.pw, c.h_mid-c.ph/2);
|
||||
this.playerLeft = new Racket(pos, c.pw, c.ph, c.racketSpeed);
|
||||
pos.assign(c.w-c.pw-c.pw, c.h_mid-c.ph/2);
|
||||
this.playerRight = new Racket(pos, c.pw, c.ph, c.racketSpeed);
|
||||
|
||||
// Balls
|
||||
let ballsCount = 1;
|
||||
if (options & en.MatchOptions.multiBalls) {
|
||||
ballsCount = c.multiBallsCount;
|
||||
}
|
||||
pos.assign(-c.ballSize, -c.ballSize); // ball out =)
|
||||
while (this.ballsArr.length < ballsCount) {
|
||||
this.ballsArr.push(new Ball(pos, c.ballSize, c.ballSpeed, c.ballSpeedIncrease))
|
||||
}
|
||||
this.ballsArr.forEach((ball) => {
|
||||
ball.dir.x = 1;
|
||||
if (random() > 0.5) {
|
||||
ball.dir.x *= -1;
|
||||
}
|
||||
|
||||
ball.dir.y = random(0, 0.2);
|
||||
if (random() > 0.5) {
|
||||
ball.dir.y *= -1;
|
||||
}
|
||||
|
||||
ball.dir = ball.dir.normalized();
|
||||
});
|
||||
|
||||
// Walls
|
||||
if (options & en.MatchOptions.movingWalls) {
|
||||
pos.assign(0, 0);
|
||||
this.wallTop = new MovingRectangle(pos, c.w, c.wallSize, c.movingWallSpeed);
|
||||
(<MovingRectangle>this.wallTop).dir.y = -1;
|
||||
pos.assign(0, c.h-c.wallSize);
|
||||
this.wallBottom = new MovingRectangle(pos, c.w, c.wallSize, c.movingWallSpeed);
|
||||
(<MovingRectangle>this.wallBottom).dir.y = 1;
|
||||
}
|
||||
else {
|
||||
pos.assign(0, 0);
|
||||
this.wallTop = new Rectangle(pos, c.w, c.wallSize);
|
||||
pos.assign(0, c.h-c.wallSize);
|
||||
this.wallBottom = new Rectangle(pos, c.w, c.wallSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export {GameComponents}
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
import * as c from "../constants.js"
|
||||
import * as en from "../../shared_js/enums.js"
|
||||
import * as en from "../enums.js"
|
||||
import { GameComponents } from "../../shared_js/class/GameComponents.js";
|
||||
|
||||
class GameComponentsServer extends GameComponents {
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
import * as en from "../../shared_js/enums.js"
|
||||
import * as ev from "../../shared_js/class/Event.js"
|
||||
import * as en from "../enums.js"
|
||||
import * as ev from "./Event.js"
|
||||
import * as c from "../constants.js"
|
||||
import { ClientPlayer } from "./Client";
|
||||
import { GameComponentsServer } from "./GameComponentsServer.js";
|
||||
35
JEU2/src/server/constants.ts
Normal file
35
JEU2/src/server/constants.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
export * from "../shared_js/constants.js"
|
||||
|
||||
// 15ms == 1000/66.666
|
||||
export const serverGameLoopIntervalMS = 15; // millisecond
|
||||
export const fixedDeltaTime = serverGameLoopIntervalMS/1000; // second
|
||||
|
||||
// 33.333ms == 1000/30
|
||||
export const clientsUpdateIntervalMS = 1000/30; // millisecond
|
||||
|
||||
export const CanvasWidth = 1500;
|
||||
export const CanvasRatio = 1.66666;
|
||||
/* ratio 5/3 (1.66) */
|
||||
|
||||
export const w = CanvasWidth;
|
||||
export const h = CanvasWidth / CanvasRatio;
|
||||
export const w_mid = Math.floor(w/2);
|
||||
export const h_mid = Math.floor(h/2);
|
||||
export const pw = Math.floor(w*0.017);
|
||||
export const ph = pw*6;
|
||||
export const ballSize = pw;
|
||||
export const wallSize = Math.floor(w*0.01);
|
||||
export const racketSpeed = Math.floor(w*0.66); // pixel per second
|
||||
export const ballSpeed = Math.floor(w*0.66); // pixel per second
|
||||
export const ballSpeedIncrease = Math.floor(ballSpeed*0.05); // pixel per second
|
||||
|
||||
export const normalizedSpeed = false; // for consistency in speed independent of direction
|
||||
|
||||
export const matchStartDelay = 3000; // millisecond
|
||||
export const newRoundDelay = 1500; // millisecond
|
||||
|
||||
// Game Variantes
|
||||
export const multiBallsCount = 3;
|
||||
export const movingWallPosMax = Math.floor(w*0.12);
|
||||
export const movingWallSpeed = Math.floor(w*0.08);
|
||||
33
JEU2/src/server/utils.ts
Normal file
33
JEU2/src/server/utils.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { MovingRectangle } from "./class/Rectangle.js";
|
||||
export * from "../shared_js/utils.js"
|
||||
|
||||
function shortId(id: string): string {
|
||||
return id.substring(0, id.indexOf("-"));
|
||||
}
|
||||
|
||||
export {shortId}
|
||||
|
||||
function random(min: number = 0, max: number = 1) {
|
||||
return Math.random() * (max - min) + min;
|
||||
}
|
||||
|
||||
function sleep (ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
function clamp(n: number, min: number, max: number) : number
|
||||
{
|
||||
if (n < min)
|
||||
n = min;
|
||||
else if (n > max)
|
||||
n = max;
|
||||
return (n);
|
||||
}
|
||||
|
||||
// Typescript hack, unused
|
||||
function assertMovingRectangle(value: unknown): asserts value is MovingRectangle {
|
||||
// if (value !== MovingRectangle) throw new Error("Not a MovingRectangle");
|
||||
return;
|
||||
}
|
||||
|
||||
export {random, sleep, clamp, assertMovingRectangle}
|
||||
@@ -8,8 +8,8 @@ export class WebSocket extends BaseLibWebSocket {
|
||||
import { IncomingMessage } from "http";
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import * as en from "../shared_js/enums.js"
|
||||
import * as ev from "../shared_js/class/Event.js"
|
||||
import * as en from "./enums.js"
|
||||
import * as ev from "./class/Event.js"
|
||||
import { Client, ClientPlayer } from "./class/Client.js"
|
||||
import { GameSession } from "./class/GameSession.js"
|
||||
import { shortId } from "./utils.js";
|
||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"name": "group_transcendence",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
@@ -3,9 +3,9 @@ import { FriendshipStatus } from '../entities/friendship.entity';
|
||||
|
||||
export class CreateFriendshipDto {
|
||||
@IsString()
|
||||
readonly requesterId: string;
|
||||
readonly requesterUsername: string;
|
||||
@IsString()
|
||||
readonly addresseeId: string;
|
||||
readonly addresseeUsername: string;
|
||||
@IsEnum(FriendshipStatus)
|
||||
readonly status: FriendshipStatus;
|
||||
}
|
||||
|
||||
@@ -18,12 +18,12 @@ export class Friendship {
|
||||
date : Date;
|
||||
|
||||
@Column()
|
||||
@ManyToOne(type => User, user => user.requesterId)
|
||||
requesterId: string;
|
||||
@ManyToOne(type => User, user => user.username)
|
||||
requesterUsername: string;
|
||||
|
||||
@Column()
|
||||
@ManyToOne(type => User, user => user.addresseeId)
|
||||
addresseeId: string;
|
||||
@ManyToOne(type => User, user => user.username)
|
||||
addresseeUsername: string;
|
||||
|
||||
@Column({ type: 'enum', enum: FriendshipStatus, default: FriendshipStatus.REQUESTED})
|
||||
status: FriendshipStatus;
|
||||
|
||||
@@ -36,14 +36,8 @@ export class FriendshipController {
|
||||
@UseGuards(TwoFactorGuard)
|
||||
create(@Body() createFriendshipDto: CreateFriendshipDto, @Req() req) {
|
||||
const user = req.user;
|
||||
|
||||
console.log("WHAT IS UP MY GUYS IT IS YOUR BOI THAT IDIOT YOU HATE 22222");
|
||||
|
||||
// console.log(`User id: ${user.id}\nFriend id: ${createFriendshipDto.requesterId}\nStatus: ${createFriendshipDto.status}`);
|
||||
// console.log(`My User id: ${createFriendshipDto.requesterId}`)
|
||||
console.log(`My User id: ${user.id}`)
|
||||
console.log(`User id: ${user.id}\nFriend id: ${createFriendshipDto.addresseeId}\nStatus: ${createFriendshipDto.status}`);
|
||||
if (user.id === +createFriendshipDto.requesterId)
|
||||
console.log(`User id: ${user.id}\nFriend id: ${createFriendshipDto.requesterUsername}\nStatus: ${createFriendshipDto.status}`);
|
||||
if (user.username === createFriendshipDto.requesterUsername)
|
||||
return this.friendshipService.create(createFriendshipDto, user);
|
||||
return new HttpException('You can\'t request a frienship for another user', HttpStatus.FORBIDDEN);
|
||||
}
|
||||
@@ -73,7 +67,7 @@ export class FriendshipController {
|
||||
@UseGuards(TwoFactorGuard)
|
||||
findAllBlocked(@Req() req) {
|
||||
const user = req.user;
|
||||
return this.friendshipService.findAllBlockedFriends(user.id);
|
||||
return this.friendshipService.findAllBlockedFriends(user.username);
|
||||
}
|
||||
|
||||
// GET http://transcendance:8080/api/v2/network/pending
|
||||
|
||||
@@ -3,7 +3,6 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { User } from 'src/users/entities/user.entity';
|
||||
import { Repository } from 'typeorm';
|
||||
import { CreateFriendshipDto } from './dto/create-friendship.dto';
|
||||
import { UpdateFriendshipDto } from './dto/update-friendship.dto';
|
||||
import { Friendship, FriendshipStatus } from './entities/friendship.entity';
|
||||
|
||||
@Injectable()
|
||||
@@ -17,8 +16,8 @@ export class FriendshipService {
|
||||
) { }
|
||||
|
||||
|
||||
async findOneFriend(friendshipId: string, userId: string) {
|
||||
const friendship = await this.friendshipRepository.find({ where: { id: +friendshipId, requesterId: userId, status: FriendshipStatus.ACCEPTED } });
|
||||
async findOneFriend(friendshipId: string, username: string) {
|
||||
const friendship = await this.friendshipRepository.find({ where: { id: +friendshipId, requesterUsername: username, status: FriendshipStatus.ACCEPTED } });
|
||||
if (!friendship)
|
||||
throw new HttpException(`The requested friend not found.`, HttpStatus.NOT_FOUND);
|
||||
return friendship;
|
||||
@@ -31,12 +30,12 @@ export class FriendshipService {
|
||||
return friendship;
|
||||
}
|
||||
|
||||
async findAllFriends(userId: string) {
|
||||
async findAllFriends(username: string) {
|
||||
const friendship = await this.friendshipRepository
|
||||
.createQueryBuilder('friendship')
|
||||
.where('friendship.status = :status', { status: FriendshipStatus.ACCEPTED })
|
||||
.andWhere('friendship.addresseeId = :addressee', { addressee: userId })
|
||||
.orWhere('friendship.requesterId = :requester', { requester: userId })
|
||||
.andWhere('friendship.addresseeUsername = :addressee', { addressee: username })
|
||||
.orWhere('friendship.requesterUsername = :requester', { requester: username })
|
||||
.andWhere('friendship.status = :status', { status: FriendshipStatus.ACCEPTED })
|
||||
.getMany();
|
||||
for (const friend of friendship)
|
||||
@@ -44,40 +43,39 @@ export class FriendshipService {
|
||||
return friendship;
|
||||
}
|
||||
|
||||
async findAllBlockedFriends(userId: string) {
|
||||
async findAllBlockedFriends(username: string) {
|
||||
return await this.friendshipRepository
|
||||
.createQueryBuilder('friendship')
|
||||
.where('friendship.requesterId = :requestee', { requestee: userId })
|
||||
.orWhere('friendship.addresseeId = :addressee', { addressee: userId })
|
||||
.where('friendship.requesterUsername = :requestee', { requestee: username })
|
||||
.andWhere('friendship.status = :status', { status: FriendshipStatus.BLOCKED })
|
||||
.getMany();
|
||||
}
|
||||
|
||||
async findAllPendantRequestsForFriendship(userId: string) {
|
||||
async findAllPendantRequestsForFriendship(username: string) {
|
||||
return await this.friendshipRepository
|
||||
.createQueryBuilder('friendship')
|
||||
.where('friendship.requesterId = :requestee', { requestee: userId })
|
||||
.where('friendship.requesterUsername = :requestee', { requestee: username })
|
||||
.andWhere('friendship.status = :status', { status: FriendshipStatus.REQUESTED })
|
||||
.getMany();
|
||||
}
|
||||
|
||||
async findAllReceivedRequestsForFriendship(userId: string) {
|
||||
async findAllReceivedRequestsForFriendship(username: string) {
|
||||
return await this.friendshipRepository
|
||||
.createQueryBuilder('friendship')
|
||||
.where('friendship.addresseeId = :addressee', { addressee: userId })
|
||||
.where('friendship.addresseeUsername = :addressee', { addressee: username })
|
||||
.andWhere('friendship.status = :status', { status: FriendshipStatus.REQUESTED })
|
||||
.getMany();
|
||||
}
|
||||
//GROS CHANTIER
|
||||
async create(createFriendshipDto: CreateFriendshipDto, creator : User) {
|
||||
const addressee = await this.userRepository.findOneBy({ id: +createFriendshipDto.addresseeId });
|
||||
const addressee = await this.userRepository.findOneBy({username: createFriendshipDto.requesterUsername});
|
||||
if (!addressee)
|
||||
throw new HttpException(`The addressee does not exist.`, HttpStatus.NOT_FOUND);
|
||||
if (creator.id === addressee.id)
|
||||
throw new HttpException(`You can't add yourself.`, HttpStatus.FORBIDDEN);
|
||||
if (createFriendshipDto.status !== FriendshipStatus.REQUESTED && createFriendshipDto.status !== FriendshipStatus.BLOCKED)
|
||||
throw new HttpException(`The status is not valid.`, HttpStatus.NOT_FOUND);
|
||||
const friendship = await this.friendshipRepository.findOneBy({ requesterId: createFriendshipDto.requesterId, addresseeId: createFriendshipDto.addresseeId });
|
||||
const friendship = await this.friendshipRepository.findOneBy({ requesterUsername: createFriendshipDto.requesterUsername, addresseeUsername: createFriendshipDto.addresseeUsername });
|
||||
if (friendship) {
|
||||
if (friendship.status && friendship.status === FriendshipStatus.ACCEPTED)
|
||||
throw new HttpException(`The friendship request has already been accepted.`, HttpStatus.OK);
|
||||
@@ -96,7 +94,7 @@ export class FriendshipService {
|
||||
const relation = await this.friendshipRepository.findOneBy({ id: +relationshipId });
|
||||
if (!relation)
|
||||
throw new HttpException(`The requested relationship not found.`, HttpStatus.NOT_FOUND);
|
||||
if (+relation.requesterId === user.id) {
|
||||
if (+relation.requesterUsername === user.id) {
|
||||
throw new HttpException(`You can't accept your own request.`, HttpStatus.NOT_FOUND);
|
||||
}
|
||||
if (status === FriendshipStatus.ACCEPTED)
|
||||
@@ -122,8 +120,8 @@ export class FriendshipService {
|
||||
async findIfUserIsBlockedOrHasBlocked(userConnectedId: string, userToCheckId: string) {
|
||||
const friendship = await this.friendshipRepository
|
||||
.createQueryBuilder('friendship')
|
||||
.where('friendship.requesterId = :requestee', { requestee: userConnectedId })
|
||||
.orWhere('friendship.requesterId = :requesteeBis', { requesteeBis: userToCheckId })
|
||||
.where('friendship.requesterUsername = :requestee', { requestee: userConnectedId })
|
||||
.orWhere('friendship.requesterUsername = :requesteeBis', { requesteeBis: userToCheckId })
|
||||
.andWhere('friendship.status = :status', { status: FriendshipStatus.BLOCKED })
|
||||
.getOne();
|
||||
if (friendship)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { IsBoolean, IsEmail, IsNotEmpty, IsString } from 'class-validator';
|
||||
|
||||
export class CreateUsersDto {
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
readonly username: string;
|
||||
readonly fortyTwoId: string;
|
||||
@IsEmail()
|
||||
readonly email: string;
|
||||
@IsString()
|
||||
readonly image_url: string;
|
||||
@IsString()
|
||||
readonly status: string;
|
||||
@IsBoolean()
|
||||
readonly isEnabledTwoFactorAuth: boolean;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||
|
||||
|
||||
|
||||
@Entity('gameParty')
|
||||
export class gameParty {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
playerOne: string
|
||||
|
||||
@Column()
|
||||
playerTwo: string
|
||||
|
||||
@Column()
|
||||
resultOfTheMatch: string
|
||||
|
||||
@Column()
|
||||
gameServerIdOfTheMatch: string
|
||||
}
|
||||
@@ -44,11 +44,11 @@ export class User {
|
||||
secretTwoFactorAuth: string;
|
||||
|
||||
@JoinTable()
|
||||
@OneToMany(type => Friendship , (friendship) => friendship.requesterId)
|
||||
@OneToMany(type => Friendship , (friendship) => friendship.requesterUsername)
|
||||
requesterId: Friendship[];
|
||||
|
||||
@JoinTable()
|
||||
@OneToMany(type => Friendship , (friendship) => friendship.addresseeId)
|
||||
@OneToMany(type => Friendship , (friendship) => friendship.addresseeUsername)
|
||||
addresseeId: Friendship[];
|
||||
|
||||
@JoinColumn()
|
||||
|
||||
107
srcs/requirements/svelte/api_front/public/game/class/Event.ts
Normal file
107
srcs/requirements/svelte/api_front/public/game/class/Event.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
|
||||
import * as en from "../enums.js"
|
||||
|
||||
/* From Server */
|
||||
class ServerEvent {
|
||||
type: en.EventTypes;
|
||||
constructor(type: en.EventTypes = 0) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
class EventAssignId extends ServerEvent {
|
||||
id: string;
|
||||
constructor(id: string) {
|
||||
super(en.EventTypes.assignId);
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
class EventMatchmakingComplete extends ServerEvent {
|
||||
side: en.PlayerSide;
|
||||
constructor(side: en.PlayerSide) {
|
||||
super(en.EventTypes.matchmakingComplete);
|
||||
this.side = side;
|
||||
}
|
||||
}
|
||||
|
||||
class EventGameUpdate extends ServerEvent {
|
||||
playerLeft = {
|
||||
y: 0
|
||||
};
|
||||
playerRight = {
|
||||
y: 0
|
||||
};
|
||||
ballsArr: {
|
||||
x: number,
|
||||
y: number,
|
||||
dirX: number,
|
||||
dirY: number,
|
||||
speed: number
|
||||
}[] = [];
|
||||
wallTop? = {
|
||||
y: 0
|
||||
};
|
||||
wallBottom? = {
|
||||
y: 0
|
||||
};
|
||||
lastInputId = 0;
|
||||
constructor() { // TODO: constructor that take GameComponentsServer maybe ?
|
||||
super(en.EventTypes.gameUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
class EventScoreUpdate extends ServerEvent {
|
||||
scoreLeft: number;
|
||||
scoreRight: number;
|
||||
constructor(scoreLeft: number, scoreRight: number) {
|
||||
super(en.EventTypes.scoreUpdate);
|
||||
this.scoreLeft = scoreLeft;
|
||||
this.scoreRight = scoreRight;
|
||||
}
|
||||
}
|
||||
|
||||
class EventMatchEnd extends ServerEvent {
|
||||
winner: en.PlayerSide;
|
||||
constructor(winner: en.PlayerSide) {
|
||||
super(en.EventTypes.matchEnd);
|
||||
this.winner = winner;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* From Client */
|
||||
class ClientEvent {
|
||||
type: en.EventTypes; // readonly ?
|
||||
constructor(type: en.EventTypes = 0) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
class ClientAnnounce extends ClientEvent {
|
||||
role: en.ClientRole;
|
||||
clientId: string;
|
||||
matchOptions: en.MatchOptions;
|
||||
constructor(role: en.ClientRole, matchOptions: en.MatchOptions, clientId: string = "") {
|
||||
super(en.EventTypes.clientAnnounce);
|
||||
this.role = role;
|
||||
this.clientId = clientId;
|
||||
this.matchOptions = matchOptions;
|
||||
}
|
||||
}
|
||||
|
||||
class EventInput extends ClientEvent {
|
||||
input: en.InputEnum;
|
||||
id: number;
|
||||
constructor(input: en.InputEnum = en.InputEnum.noInput, id: number = 0) {
|
||||
super(en.EventTypes.clientInput);
|
||||
this.input = input;
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
ServerEvent, EventAssignId, EventMatchmakingComplete,
|
||||
EventGameUpdate, EventScoreUpdate, EventMatchEnd,
|
||||
ClientEvent, ClientAnnounce, EventInput
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
|
||||
import { Vector, VectorInteger } from "./Vector.js";
|
||||
import { Component, Moving } from "./interface.js";
|
||||
import * as c from "../constants.js"
|
||||
|
||||
class Rectangle implements Component {
|
||||
pos: VectorInteger;
|
||||
width: number;
|
||||
height: number;
|
||||
constructor(pos: VectorInteger, width: number, height: number) {
|
||||
this.pos = new VectorInteger(pos.x, pos.y);
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
collision(collider: Rectangle): boolean {
|
||||
const thisLeft = this.pos.x;
|
||||
const thisRight = this.pos.x + this.width;
|
||||
const thisTop = this.pos.y;
|
||||
const thisBottom = this.pos.y + this.height;
|
||||
const colliderLeft = collider.pos.x;
|
||||
const colliderRight = collider.pos.x + collider.width;
|
||||
const colliderTop = collider.pos.y;
|
||||
const colliderBottom = collider.pos.y + collider.height;
|
||||
if ((thisBottom < colliderTop)
|
||||
|| (thisTop > colliderBottom)
|
||||
|| (thisRight < colliderLeft)
|
||||
|| (thisLeft > colliderRight)) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MovingRectangle extends Rectangle implements Moving {
|
||||
dir: Vector = new Vector(0,0);
|
||||
speed: number;
|
||||
readonly baseSpeed: number;
|
||||
constructor(pos: VectorInteger, width: number, height: number, baseSpeed: number) {
|
||||
super(pos, width, height);
|
||||
this.baseSpeed = baseSpeed;
|
||||
this.speed = baseSpeed;
|
||||
}
|
||||
move(delta: number) { // Math.floor WIP until VectorInteger debug
|
||||
// console.log(`delta: ${delta}, speed: ${this.speed}, speed*delta: ${this.speed * delta}`);
|
||||
// this.pos.x += Math.floor(this.dir.x * this.speed * delta);
|
||||
// this.pos.y += Math.floor(this.dir.y * this.speed * delta);
|
||||
this.pos.x += this.dir.x * this.speed * delta;
|
||||
this.pos.y += this.dir.y * this.speed * delta;
|
||||
}
|
||||
moveAndCollide(delta: number, colliderArr: Rectangle[]) {
|
||||
this._moveAndCollideAlgo(delta, colliderArr);
|
||||
}
|
||||
protected _moveAndCollideAlgo(delta: number, colliderArr: Rectangle[]) {
|
||||
let oldPos = new VectorInteger(this.pos.x, this.pos.y);
|
||||
this.move(delta);
|
||||
if (colliderArr.some(this.collision, this)) {
|
||||
this.pos = oldPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Racket extends MovingRectangle {
|
||||
constructor(pos: VectorInteger, width: number, height: number, baseSpeed: number) {
|
||||
super(pos, width, height, baseSpeed);
|
||||
}
|
||||
moveAndCollide(delta: number, colliderArr: Rectangle[]) {
|
||||
// let oldPos = new VectorInteger(this.pos.x, this.pos.y); // debug
|
||||
this._moveAndCollideAlgo(delta, colliderArr);
|
||||
// console.log(`y change: ${this.pos.y - oldPos.y}`);
|
||||
}
|
||||
}
|
||||
|
||||
class Ball extends MovingRectangle {
|
||||
readonly speedIncrease: number;
|
||||
ballInPlay: boolean = false;
|
||||
constructor(pos: VectorInteger, size: number, baseSpeed: number, speedIncrease: number) {
|
||||
super(pos, size, size, baseSpeed);
|
||||
this.speedIncrease = speedIncrease;
|
||||
}
|
||||
bounce(collider?: Rectangle) {
|
||||
this._bounceAlgo(collider);
|
||||
}
|
||||
protected _bounceAlgo(collider?: Rectangle) {
|
||||
/* Could be more generic, but testing only Racket is enough,
|
||||
because in Pong collider can only be Racket or Wall. */
|
||||
if (collider instanceof Racket) {
|
||||
this._bounceRacket(collider);
|
||||
}
|
||||
else {
|
||||
this._bounceWall();
|
||||
}
|
||||
}
|
||||
moveAndBounce(delta: number, colliderArr: Rectangle[]) {
|
||||
this.move(delta);
|
||||
let i = colliderArr.findIndex(this.collision, this);
|
||||
if (i != -1)
|
||||
{
|
||||
this.bounce(colliderArr[i]);
|
||||
this.move(delta);
|
||||
}
|
||||
}
|
||||
protected _bounceWall() { // Should be enough for Wall
|
||||
this.dir.y = this.dir.y * -1;
|
||||
}
|
||||
protected _bounceRacket(racket: Racket) {
|
||||
this._bounceRacketAlgo(racket);
|
||||
}
|
||||
protected _bounceRacketAlgo(racket: Racket) {
|
||||
this.speed += this.speedIncrease;
|
||||
|
||||
let x = this.dir.x * -1;
|
||||
|
||||
const angleFactorDegree = 60;
|
||||
const angleFactor = angleFactorDegree / 90;
|
||||
const racketHalf = racket.height/2;
|
||||
const ballMid = this.pos.y + this.height/2;
|
||||
const racketMid = racket.pos.y + racketHalf;
|
||||
|
||||
let impact = ballMid - racketMid;
|
||||
const horizontalMargin = racketHalf * 0.15;
|
||||
if (impact < horizontalMargin && impact > -horizontalMargin) {
|
||||
impact = 0;
|
||||
}
|
||||
else if (impact > 0) {
|
||||
impact = impact - horizontalMargin;
|
||||
}
|
||||
else if (impact < 0) {
|
||||
impact = impact + horizontalMargin;
|
||||
}
|
||||
|
||||
let y = impact / (racketHalf - horizontalMargin) * angleFactor;
|
||||
|
||||
this.dir.assign(x, y);
|
||||
// Normalize Vector (for consistency in speed independent of direction)
|
||||
if (c.normalizedSpeed) {
|
||||
this.dir = this.dir.normalized();
|
||||
}
|
||||
// console.log(`x: ${this.dir.x}, y: ${this.dir.y}`);
|
||||
}
|
||||
}
|
||||
|
||||
export {Rectangle, MovingRectangle, Racket, Ball}
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
class Vector {
|
||||
x: number;
|
||||
y: number;
|
||||
constructor(x: number = 0, y: number = 0) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
assign(x: number, y: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
normalized() : Vector {
|
||||
const normalizationFactor = Math.abs(this.x) + Math.abs(this.y);
|
||||
return new Vector(this.x/normalizationFactor, this.y/normalizationFactor);
|
||||
}
|
||||
}
|
||||
|
||||
class VectorInteger extends Vector {
|
||||
// PLACEHOLDER
|
||||
// VectorInteger with set/get dont work (No draw on the screen). Why ?
|
||||
}
|
||||
|
||||
/*
|
||||
class VectorInteger {
|
||||
// private _x: number = 0;
|
||||
// private _y: number = 0;
|
||||
// constructor(x: number = 0, y: number = 0) {
|
||||
// this._x = x;
|
||||
// this._y = y;
|
||||
// }
|
||||
// get x(): number {
|
||||
// return this._x;
|
||||
// }
|
||||
// set x(v: number) {
|
||||
// // this._x = Math.floor(v);
|
||||
// this._x = v;
|
||||
// }
|
||||
// get y(): number {
|
||||
// return this._y;
|
||||
// }
|
||||
// set y(v: number) {
|
||||
// // this._y = Math.floor(v);
|
||||
// this._y = v;
|
||||
// }
|
||||
}
|
||||
*/
|
||||
|
||||
export {Vector, VectorInteger}
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
import { Vector, VectorInteger } from "./Vector.js";
|
||||
|
||||
interface Component {
|
||||
pos: VectorInteger;
|
||||
}
|
||||
|
||||
interface GraphicComponent extends Component {
|
||||
ctx: CanvasRenderingContext2D;
|
||||
color: string;
|
||||
update: () => void;
|
||||
clear: (pos?: VectorInteger) => void;
|
||||
}
|
||||
|
||||
interface Moving {
|
||||
dir: Vector;
|
||||
speed: number; // pixel per second
|
||||
move(delta: number): void;
|
||||
}
|
||||
|
||||
export {Component, GraphicComponent, Moving}
|
||||
47
srcs/requirements/svelte/api_front/public/game/enums.ts
Normal file
47
srcs/requirements/svelte/api_front/public/game/enums.ts
Normal file
@@ -0,0 +1,47 @@
|
||||
|
||||
enum EventTypes {
|
||||
// Class Implemented
|
||||
gameUpdate = 1,
|
||||
scoreUpdate,
|
||||
matchEnd,
|
||||
assignId,
|
||||
matchmakingComplete,
|
||||
|
||||
// Generic
|
||||
matchmakingInProgress,
|
||||
matchStart,
|
||||
matchNewRound, // unused
|
||||
matchPause, // unused
|
||||
matchResume, // unused
|
||||
|
||||
// Client
|
||||
clientAnnounce,
|
||||
clientPlayerReady,
|
||||
clientInput,
|
||||
|
||||
}
|
||||
|
||||
enum InputEnum {
|
||||
noInput = 0,
|
||||
up = 1,
|
||||
down,
|
||||
}
|
||||
|
||||
enum PlayerSide {
|
||||
left = 1,
|
||||
right
|
||||
}
|
||||
|
||||
enum ClientRole {
|
||||
player = 1,
|
||||
spectator
|
||||
}
|
||||
|
||||
enum MatchOptions {
|
||||
// binary flags, can be mixed
|
||||
noOption = 0b0,
|
||||
multiBalls = 1 << 0,
|
||||
movingWalls = 1 << 1
|
||||
}
|
||||
|
||||
export {EventTypes, InputEnum, PlayerSide, ClientRole, MatchOptions}
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
import * as c from "./constants.js";
|
||||
import { MovingRectangle } from "../shared_js/class/Rectangle.js";
|
||||
import { GameComponents } from "./class/GameComponents.js";
|
||||
|
||||
function wallsMovements(delta: number, gc: GameComponents)
|
||||
{
|
||||
const wallTop = <MovingRectangle>gc.wallTop;
|
||||
const wallBottom = <MovingRectangle>gc.wallBottom;
|
||||
if (wallTop.pos.y <= 0 || wallTop.pos.y >= c.movingWallPosMax) {
|
||||
wallTop.dir.y *= -1;
|
||||
}
|
||||
if (wallBottom.pos.y >= c.h-c.wallSize || wallBottom.pos.y <= c.h-c.movingWallPosMax) {
|
||||
wallBottom.dir.y *= -1;
|
||||
}
|
||||
wallTop.moveAndCollide(delta, [gc.playerLeft, gc.playerRight]);
|
||||
wallBottom.moveAndCollide(delta, [gc.playerLeft, gc.playerRight]);
|
||||
}
|
||||
|
||||
export {wallsMovements}
|
||||
@@ -0,0 +1,99 @@
|
||||
|
||||
<script>
|
||||
import "public/game/pong.js"
|
||||
</script>
|
||||
|
||||
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="preload_font">.</div>
|
||||
|
||||
<div id="div_game_options">
|
||||
<fieldset>
|
||||
<legend>game options</legend>
|
||||
<div>
|
||||
<input type="checkbox" id="multi_balls" name="multi_balls">
|
||||
<label for="multi_balls">multiples balls</label>
|
||||
</div>
|
||||
<div>
|
||||
<input type="checkbox" id="moving_walls" name="moving_walls">
|
||||
<label for="moving_walls">moving walls</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>sound :</label>
|
||||
<input type="radio" id="sound_on" name="sound_selector" checked>
|
||||
<label for="sound_on">on</label>
|
||||
<input type="radio" id="sound_off" name="sound_selector">
|
||||
<label for="sound_off">off</label>
|
||||
</div>
|
||||
<div>
|
||||
<button id="play_pong_button">PLAY</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div id="canvas_container">
|
||||
<!-- <p> =) </p> -->
|
||||
</div>
|
||||
|
||||
<script src="public/game/pong.js" type="module" defer></script>
|
||||
</body>
|
||||
|
||||
<style>
|
||||
|
||||
@font-face {
|
||||
font-family: "Bit5x3";
|
||||
src: url("/fonts/Bit5x3.woff2") format("woff2"),local("Bit5x3"), url("/fonts/Bit5x3.woff") format("woff");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
}
|
||||
#preload_font {
|
||||
font-family: "Bit5x3";
|
||||
opacity:0;
|
||||
height:0;
|
||||
width:0;
|
||||
display:inline-block;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
background-color: #222425;
|
||||
}
|
||||
#canvas_container {
|
||||
text-align: center;
|
||||
/* border: dashed rgb(245, 245, 245) 5px; */
|
||||
/* max-height: 80vh; */
|
||||
/* overflow: hidden; */
|
||||
}
|
||||
#div_game_options {
|
||||
text-align: center;
|
||||
font-family: "Bit5x3";
|
||||
color: rgb(245, 245, 245);
|
||||
font-size: x-large;
|
||||
}
|
||||
#div_game_options fieldset {
|
||||
max-width: 50vw;
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
#div_game_options fieldset div {
|
||||
padding: 10px;
|
||||
}
|
||||
#play_pong_button {
|
||||
font-family: "Bit5x3";
|
||||
color: rgb(245, 245, 245);
|
||||
background-color: #333333;
|
||||
font-size: x-large;
|
||||
padding: 10px;
|
||||
}
|
||||
canvas {
|
||||
background-color: #333333;
|
||||
max-width: 75vw;
|
||||
/* max-height: 100vh; */
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
|
||||
"include": ["src/**/*"],
|
||||
"include": ["src/**/*", "public/game"],
|
||||
"exclude": ["node_modules/*", "__sapper__/*", "public/*"]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user