major rework in Game.svelte and GameSpectator.svelte

+ WIP match draw
This commit is contained in:
LuckyLaszlo
2023-01-06 20:04:40 +01:00
parent 68ae8ac333
commit 711f971333
8 changed files with 191 additions and 188 deletions

View File

@@ -13,25 +13,20 @@
let allUsers;
//Game's stuff
let optionsAreNotSet = true;
const options = new pong.InitOptions();
//Game's stuff client side only
const gameAreaId = "game_area";
//html boolean for pages
let showWaitPage = false;
let showInvitations = false;
let showGameOption = true;
let showError = false;
//boolean for html page
let hiddenGame = true;
let showMatchEnded = false;
let optionsAreNotSet = true;
let showGameOptions = true;
let showInvitations = false;
let showError = false;
let errorMessage = "";
let showWaitPage = false;
let isThereAnyInvitation = false;
let invitations = [];
let waitingMessage = "Please wait...";
let errorMessageWhenAttemptingToGetATicket = "";
let watchGameStateInterval;
const watchGameStateIntervalRate = 142;
@@ -48,6 +43,17 @@
pong.destroy();
})
function resetPage() {
hiddenGame = true;
optionsAreNotSet = true;
showGameOptions = true;
showInvitations = false;
showError = false;
showWaitPage = false;
options.reset(user.username);
pong.destroy();
};
const initGame = async() =>
{
optionsAreNotSet = false;
@@ -63,31 +69,29 @@
gameOptions : matchOptions,
isGameIsWithInvitation : options.isSomeoneIsInvited
})
})
});
const responseFromServer = await responseWhenGrantToken;
const responseInjson = await responseFromServer.json();
const token : string = responseInjson.token;
showWaitPage = false;
console.log("status : " + responseFromServer.status)
console.log("status : " + responseFromServer.status);
if (responseFromServer.status != 200)
{
console.log(responseInjson)
console.log(responseInjson);
console.log("On refuse le ticket");
errorMessageWhenAttemptingToGetATicket = responseInjson.message;
errorMessage = responseInjson.message;
showError = true;
options.reset();
options.playerOneUsername = user.username;
options.reset(user.username);
setTimeout(() => {
optionsAreNotSet = true
optionsAreNotSet = true;
showError = false;
// showWaitPage = false // ???
errorMessage = "";
}, 5000);
}
else if (token)
{
watchGameStateInterval = setInterval(watchGameState, watchGameStateIntervalRate);
// options.isInvitedPerson = false // ???
pong.init(options, gameAreaId, token);
pong.init(matchOptions, options, gameAreaId, token);
hiddenGame = false;
}
// TODO: Un "else" peut-être ? Si pas de token on fait un truc ?
@@ -96,25 +100,25 @@
const initGameForInvitedPlayer = async(invitation : any) =>
{
optionsAreNotSet = false
showWaitPage = true
console.log("invitation : ")
console.log(invitation)
optionsAreNotSet = false;
showWaitPage = true;
console.log("invitation : ");
console.log(invitation);
if (invitation.token)
{
watchGameStateInterval = setInterval(watchGameState, watchGameStateIntervalRate);
options.playerOneUsername = invitation.playerOneUsername;
options.playerTwoUsername = invitation.playerTwoUsername;
options.isSomeoneIsInvited = true;
options.isInvitedPerson = true
pong.init(options, gameAreaId, invitation.token);
showWaitPage = false
options.isInvitedPerson = true;
pong.init(invitation.gameOptions, options, gameAreaId, invitation.token);
showWaitPage = false;
hiddenGame = false;
}
}
const watchGameState = () => {
console.log("watchGameState")
console.log("watchGameState");
if (gameState) { // trigger Svelte reactivity
gameState.matchStarted = gameState.matchStarted;
gameState.matchEnded = gameState.matchEnded;
@@ -123,34 +127,24 @@
if (gameState.matchAborted || gameState.matchEnded)
{
clearInterval(watchGameStateInterval);
console.log("watchGameState, end")
showWaitPage = false
gameState.matchAborted ?
errorMessageWhenAttemptingToGetATicket = "The match has been aborted"
: errorMessageWhenAttemptingToGetATicket = "The match is finished !"
gameState.matchAborted ? showError = true : showMatchEnded = true;
console.log("watchGameState, end");
setTimeout(() => {
resetPage();
errorMessageWhenAttemptingToGetATicket = "";
isThereAnyInvitation = false;
invitations = []; // ???
console.log("watchGameState : setTimeout")
console.log("watchGameState : setTimeout");
}, 5000);
}
}
const showOptions = () => {
showGameOption = true
showInvitations = false
const switchToGameOptions = () => {
showGameOptions = true;
showInvitations = false;
}
const showInvitation = async() => {
showGameOption = false;
const fetchInvitations = async() => {
showGameOptions = false;
showInvitations = true;
invitations = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/invitations`)
.then(x => x.json())
invitations.length !== 0 ? isThereAnyInvitation = true : isThereAnyInvitation = false
.then(x => x.json());
}
const rejectInvitation = async(invitation) => {
@@ -162,30 +156,23 @@
})
})
.then(x => x.json())
.catch(error => console.log(error))
showInvitation()
.catch(error => console.log(error));
fetchInvitations();
}
const acceptInvitation = async(invitation : any) => {
const res = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/accept`, {
const acceptInvitation = async(invitation : any) =>
{
const res = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/accept`, {
method: "POST",
headers: { 'Content-Type': 'application/json'},
body: JSON.stringify({
token : invitation.token
})
})
.then(x => x.json())
.catch(error => {
console.log(error)
})
if (res.status === 200)
{
showInvitation()
initGameForInvitedPlayer(invitation)
}
//Au final c'est utile !
}).catch(error => console.log(error));
initGameForInvitedPlayer(invitation) // Luke: normal de initGameForInvitedPlayer() sur un "res.status" different de 200 ?
if (res && res.ok) {
initGameForInvitedPlayer(invitation);
}
}
function leaveMatch() {
@@ -193,16 +180,6 @@
resetPage();
};
function resetPage() {
hiddenGame = true;
optionsAreNotSet = true
showError = false;
showMatchEnded = false;
options.reset();
options.playerOneUsername = user.username;
pong.destroy();
};
</script>
<Header />
@@ -210,53 +187,61 @@
Might become useless after CSS rework. -->
<div id="game_page">
{#if showMatchEnded === true}
<div id="div_game" in:fly="{{ y: 10, duration: 1000 }}">
<p>{errorMessageWhenAttemptingToGetATicket}</p>
</div>
{/if}
{#if showError === true}
<div id="div_game" in:fly="{{ y: 10, duration: 1000 }}">
{#if showError}
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
<fieldset>
<legend>Error</legend>
<p>{errorMessageWhenAttemptingToGetATicket}</p>
<p>{errorMessage}</p>
</fieldset>
</div>
{/if}
{#if !hiddenGame}
{#if gameState.matchEnded}
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
<p>The match is finished !</p>
</div>
{:else if gameState.matchAborted}
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
<p>The match has been aborted</p>
</div>
{/if}
{/if}
<div id="canvas_container" hidden={hiddenGame}>
<canvas id={gameAreaId}/>
</div>
{#if !hiddenGame}
{#if !hiddenGame && gameState.matchStarted && !gameState.matchEnded}
<div id="div_game">
<button id="pong_button" on:click={leaveMatch}>forfeit</button>
{#if gameState.matchStarted && !gameState.matchEnded}
<div class="div_game">
<button class="pong_button" on:click={leaveMatch}>forfeit</button>
</div>
{:else if !hiddenGame && !gameState.matchStarted}
<div id="div_game">
<button id="pong_button" on:click={leaveMatch}>leave matchmaking</button>
{:else if !gameState.matchStarted}
<div class="div_game">
<button class="pong_button" on:click={leaveMatch}>leave matchmaking</button>
</div>
{/if}
{/if}
{#if showWaitPage === true}
<div id="div_game" in:fly="{{ y: 10, duration: 1000 }}">
{#if showWaitPage}
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
<fieldset>
<legend>Connecting to the game...</legend>
<p>{waitingMessage}</p>
<p>Please wait...</p>
</fieldset>
</div>
{/if}
<!-- -->
{#if optionsAreNotSet}
{#if showGameOption === true}
{#if showGameOptions}
<div id="game_option">
<div id="div_game">
<button id="pong_button" on:click={showInvitation}>Show invitations</button>
<fieldset>
<div class="div_game">
<button class="pong_button" on:click={fetchInvitations}>Show invitations</button>
<fieldset in:fly="{{ y: 10, duration: 1000 }}">
<legend>game options</legend>
<div>
<input type="checkbox" id="multi_balls" name="multi_balls" bind:checked={options.multi_balls}>
@@ -277,7 +262,7 @@
<input type="checkbox" id="isSomeoneIsInvited" bind:checked={options.isSomeoneIsInvited}>
<label for="moving_walls">Invite a friend</label>
</div>
{#if options.isSomeoneIsInvited === true}
{#if options.isSomeoneIsInvited}
<select bind:value={options.playerTwoUsername}>
{#each allUsers as user }
<option value={user.username}>{user.username}</option>
@@ -285,7 +270,7 @@
</select>
{/if}
<div>
<button id="pong_button" on:click={initGame}>PLAY</button>
<button class="pong_button" on:click={initGame}>PLAY</button>
</div>
</fieldset>
</div>
@@ -293,26 +278,23 @@
{/if}
{#if showInvitations}
<div id="invitations_options" in:fly="{{ y: 10, duration: 1000 }}">
<div id="div_game">
<button id="pong_button" on:click={showOptions}>Play a Game</button>
<fieldset>
<legend>Current invitation(s)</legend>
{#if isThereAnyInvitation}
{#each invitations as invitation }
<div>
{invitation.playerOneUsername} has invited you to play a pong !
<button id="pong_button" on:click={() => acceptInvitation(invitation)}>V</button>
<button id="pong_button" on:click={() => rejectInvitation(invitation)}>X</button>
</div>
{/each}
{/if}
{#if isThereAnyInvitation === false}
<p>Currently, no one asked to play with you.</p>
<button id="pong_button" on:click={showInvitation}>Reload</button>
{/if}
</fieldset>
</div>
<div class="div_game">
<button class="pong_button" on:click={switchToGameOptions}>Play a Game</button>
<fieldset in:fly="{{ y: 10, duration: 1000 }}">
<legend>invitations</legend>
<button class="pong_button" on:click={fetchInvitations}>Reload</button>
{#if invitations.length !== 0}
{#each invitations as invitation}
<div>
{invitation.playerOneUsername} has invited you to play a pong !
<button class="pong_button" on:click={() => acceptInvitation(invitation)}>V</button>
<button class="pong_button" on:click={() => rejectInvitation(invitation)}>X</button>
</div>
{/each}
{:else}
<p>Currently, no one asked to play with you.</p>
{/if}
</fieldset>
</div>
{/if}
{/if}
@@ -352,22 +334,22 @@ canvas {
width: 80%;
}
#div_game {
.div_game {
margin-top: 20px;
text-align: center;
font-family: "Bit5x3";
color: rgb(245, 245, 245);
font-size: x-large;
}
#div_game fieldset {
.div_game fieldset {
max-width: 50vw;
width: auto;
margin: 0 auto;
}
#div_game fieldset div {
.div_game fieldset div {
padding: 10px;
}
#pong_button {
.pong_button {
font-family: "Bit5x3";
color: rgb(245, 245, 245);
background-color: #333333;
@@ -375,18 +357,4 @@ canvas {
padding: 10px;
}
#users_name { /* UNUSED */
text-align: center;
font-family: "Bit5x3";
color: rgb(245, 245, 245);
font-size: x-large;
}
#error_notification { /* UNUSED */
text-align: center;
display: block;
font-family: "Bit5x3";
color: rgb(143, 19, 19);
font-size: x-large;
}
</style>

View File

@@ -20,8 +20,9 @@
//html boolean for pages
let hiddenGame = true;
let hiddenMatchList = false;
let watchGameStateInterval;
const watchGameStateIntervalRate = 142;
onMount( async() => {
user = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/user`)
@@ -31,34 +32,55 @@
const responseForMatchList = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/match/all`)
const jsonForMatchList = await responseForMatchList.json();
matchList = jsonForMatchList;
if (matchList.length <= 0) {
hiddenMatchList = true;
}
})
onDestroy( async() => {
clearInterval(watchGameStateInterval);
pongSpectator.destroy();
})
async function initGameSpectator(gameSessionId: string, matchOptions: pongSpectator.MatchOptions) {
async function initGameSpectator(gameSessionId: string, matchOptions: pongSpectator.MatchOptions)
{
watchGameStateInterval = setInterval(watchGameState, watchGameStateIntervalRate);
pongSpectator.init(matchOptions, sound, gameAreaId, gameSessionId);
hiddenGame = false;
};
const watchGameState = () => {
console.log("watchGameState")
if (gameState) { // trigger Svelte reactivity
gameState.matchStarted = gameState.matchStarted;
gameState.matchEnded = gameState.matchEnded;
gameState.matchAborted = gameState.matchAborted;
}
if (gameState.matchAborted || gameState.matchEnded)
{
clearInterval(watchGameStateInterval);
console.log("watchGameState, end")
setTimeout(() => {
resetPage();
console.log("watchGameState : setTimeout")
}, 5000);
}
}
function leaveMatch() {
clearInterval(watchGameStateInterval);
resetPage();
};
async function resetPage() {
hiddenGame = true;
pongSpectator.destroy();
fetchMatchList();
};
async function fetchMatchList() {
matchList = await fetch(`http://${process.env.WEBSITE_HOST}:${process.env.WEBSITE_PORT}/api/v2/game/match/all`)
.then( x => x.json() );
if (matchList.length <= 0) {
hiddenMatchList = true;
}
};
</script>
<!-- -->
@@ -67,38 +89,50 @@
Might become useless after CSS rework. -->
<div id="game_page">
{#if !hiddenGame}
{#if gameState.matchEnded}
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
<p>The match is finished !</p>
</div>
{/if}
{/if}
<div id="canvas_container" hidden={hiddenGame}>
<canvas id={gameAreaId}/>
</div>
{#if hiddenGame}
<div id="div_game">
<div id="game_options">
<fieldset>
{#if hiddenMatchList}
<legend>no match available</legend>
{:else}
<legend>options</legend>
<div>
<p>sound :</p>
<input type="radio" id="sound_on" name="sound_selector" bind:group={sound} value="on">
<label for="sound_on">on</label>
<input type="radio" id="sound_off" name="sound_selector" bind:group={sound} value="off">
<label for="sound_off">off</label>
</div>
<menu id="match_list">
{#each matchList as match}
<MatchListElem match={match} on:click={(e) => initGameSpectator(match.gameServerIdOfTheMatch, match.gameOptions)} />
{/each}
</menu>
{/if}
</fieldset>
{#if !hiddenGame}
{#if !gameState.matchEnded}
<div class="div_game">
<button class="pong_button" on:click={leaveMatch}>leave</button>
</div>
{/if}
{/if}
</div>
{:else}
<div id="div_game">
<button id="pong_button" on:click={leaveMatch}>leave match</button>
<!-- -->
{#if hiddenGame}
<div class="div_game" in:fly="{{ y: 10, duration: 1000 }}">
<fieldset>
<legend>options</legend>
<button class="pong_button" on:click={fetchMatchList}>Reload</button>
<div>
<p>sound :</p>
<input type="radio" id="sound_on" name="sound_selector" bind:group={sound} value="on">
<label for="sound_on">on</label>
<input type="radio" id="sound_off" name="sound_selector" bind:group={sound} value="off">
<label for="sound_off">off</label>
</div>
</fieldset>
{#if matchList.length !== 0}
<menu id="match_list">
{#each matchList as match}
<MatchListElem match={match} on:click={(e) => initGameSpectator(match.gameServerIdOfTheMatch, match.gameOptions)} />
{/each}
</menu>
{:else}
<p>no match ongoing</p>
{/if}
</div>
{/if}
@@ -133,26 +167,26 @@ canvas {
width: 80%;
}
#div_game {
.div_game {
margin-top: 20px;
text-align: center;
font-family: "Bit5x3";
color: rgb(245, 245, 245);
font-size: x-large;
}
#div_game fieldset {
.div_game fieldset {
max-width: 50vw;
width: auto;
margin: 0 auto;
}
#div_game fieldset div {
.div_game fieldset div {
padding: 10px;
}
#match_list {
font-family: 'Courier New', Courier, monospace;
font-size: large;
}
#pong_button {
.pong_button {
font-family: "Bit5x3";
color: rgb(245, 245, 245);
background-color: #333333;

View File

@@ -7,13 +7,13 @@ export class InitOptions {
isInvitedPerson = false;
playerOneUsername = "";
playerTwoUsername = "";
reset() {
reset(playerOneUsername: string) {
this.sound = "off";
this.multi_balls = false;
this.moving_walls = false;
this.isSomeoneIsInvited = false;
this.isInvitedPerson = false;
this.playerOneUsername = "";
this.playerOneUsername = playerOneUsername;
this.playerTwoUsername = "";
}
}

View File

@@ -1,5 +1,6 @@
import * as c from "./constants.js"
import type * as en from "../shared_js/enums.js"
import { handleInput } from "./handleInput.js";
import { gameLoop } from "./gameLoop.js"
import { drawLoop } from "./draw.js";
@@ -10,16 +11,14 @@ export { InitOptions } from "./class/InitOptions.js";
import { initBase, destroyBase, computeMatchOptions } from "./init.js";
export { computeMatchOptions } from "./init.js";
/* TODO: A way to delay the init of variables, but still use "const" not "let" ? */
import { pong, gc } from "./global.js"
import { setStartFunction } from "./global.js"
let abortControllerKeydown: AbortController;
let abortControllerKeyup: AbortController;
export function init(options: InitOptions, gameAreaId: string, token: string)
export function init(matchOptions: en.MatchOptions, options: InitOptions, gameAreaId: string, token: string)
{
const matchOptions = computeMatchOptions(options);
initBase(matchOptions, options.sound, gameAreaId);
setStartFunction(start);
@@ -72,7 +71,6 @@ function start_after_countdown()
);
resume();
gameState.matchStarted = true;
}
function resume()

View File

@@ -101,6 +101,7 @@ function preMatchListener(this: WebSocket, event: MessageEvent)
msg.matchmakingComplete();
break;
case en.EventTypes.matchStart:
gameState.matchStarted = true;
socket.removeEventListener("message", preMatchListener);
socket.addEventListener("message", inGameListener);
startFunction();
@@ -244,6 +245,7 @@ export function preMatchListenerSpectator(this: WebSocket, event: MessageEvent)
const data: ev.ServerEvent = JSON.parse(event.data);
if (data.type === en.EventTypes.matchStart)
{
gameState.matchStarted = true;
socket.removeEventListener("message", preMatchListenerSpectator);
socket.addEventListener("message", inGameListenerSpectator);
socket.send(JSON.stringify( new ev.ClientEvent(en.EventTypes.clientSpectatorReady) ));
@@ -324,10 +326,5 @@ function matchEndSpectator(data: ev.EventMatchEnd)
console.log("matchEndSpectator");
gameState.matchEnded = true;
socket.close();
// WIP
/* msg.win();
if (data.forfeit) {
msg.forfeit(clientInfo.side);
} */
}

View File

@@ -31,6 +31,7 @@ export enum InputEnum {
}
export enum PlayerSide {
noSide = 0,
left = 1,
right
}