overlay + test game

This commit is contained in:
Daniel Bulant 2022-07-28 10:50:01 +02:00
parent 2cac7aea5f
commit 7240f0a539
9 changed files with 171 additions and 18 deletions

4
client/src/hooks.js Normal file
View file

@ -0,0 +1,4 @@
// @ts-ignore
export async function handle({ event, resolve }) {
return resolve(event, { ssr: false });
}

View file

@ -22,6 +22,8 @@ class ConnectedClient extends EventTarget {
readyState: number = 0;
pings: number[] = [];
score: number = 0;
lives: number = 3;
lastScoreChange: number = 0;
constructor(public ws: WebsocketConnection, public name: string) {
super();
@ -84,8 +86,17 @@ class ConnectedClient extends EventTarget {
this.dispatchEvent(new FastEvent("message", msg.d));
messages.update(t => { t.push({ author: this.name, content: msg.d });return t})
break;
case "lives":
this.lives = msg.d;
players.update(t => t);
break;
case "score":
this.score = msg.d;
this.lastScoreChange = Date.now();
players.update(t => t);
break;
case "start":
gameData.set({ score: 0 });
gameData.set({ score: 0, lives: 3, lastScoreChange: 0 });
// break not on purpose
default:
console.log("MSG", msg);
@ -236,6 +247,9 @@ export class WebsocketConnection extends EventTarget {
this.fast.delete(msg.client);
players.set(this.fast);
messages.update(t => { t.push({ author: " SYS ", content: `${msg.client} left`});return t})
if(this.fast.size == 0) {
gameData.set(null);
}
break;
}
case "host": {
@ -280,6 +294,17 @@ export class WebsocketConnection extends EventTarget {
}
}
setScore(score: number) {
if (!this.roomName) return console.log("Not in a room");
this.broadcast({ t: "score", d: score });
gameData.update(t => { t!.score = score; t!.lastScoreChange = Date.now(); return t});
}
setLives(lives: number) {
if (!this.roomName) return console.log("Not in a room");
this.broadcast({ t: "lives", d: lives });
gameData.update(t => { t!.lives = lives; return t});
}
createGame(name: string) {
this.ws.send(JSON.stringify({ t: "create", name: name }));
}
@ -290,6 +315,7 @@ export class WebsocketConnection extends EventTarget {
for(const [, client] of this.fast) {
client.score = 0;
}
gameData.set({ score: 0, lives: 3, lastScoreChange: 0 });
}
join(name: string) {
@ -313,4 +339,4 @@ export const lastError: Writable<string> = writable("");
export const room: Writable<{ name: string, host: string } | null> = writable(null);
export const players: Writable<Map<string, ConnectedClient>> = writable(new Map);
export const messages: Writable<{ author: string, content: string }[]> = writable([]);
export const gameData: Writable<{ score: number }|null> = writable(null);
export const gameData: Writable<{ score: number, lives: number, lastScoreChange: number }|null> = writable(null);

View file

@ -79,7 +79,7 @@
transform: rotate3d(1, 0, 0, 0deg);
transform-style: preserve-3d;
box-sizing: border-box;
animation: dice 1.8s 0.7s ease-in-out;
animation: dice 1.2s 0.5s ease-in-out;
animation-fill-mode: both;
}
@keyframes dice {

View file

@ -1,2 +1,95 @@
<script lang="ts">
import { connection, gameData, players } from "$lib/Websocket";
import { flip } from "svelte/animate";
<slot />
let scoreboard: { name: string, score: number, lives: number, lastScoreChange: number }[] = [];
$: {
scoreboard = [...$players.values(), { name: $connection!.name, score: $gameData!.score, lives: $gameData!.lives, lastScoreChange: $gameData!.lastScoreChange }].sort((a, b) => (b.score - a.score) || (b.lives - a.lives) || (a.lastScoreChange - b.lastScoreChange) || a.name.localeCompare(b.name));
}
</script>
<div class="container">
<div class="left">
<div class="hearts">
{#each [...Array($gameData?.lives).keys()] as i}
<img src="/assets/heart.png" alt="">
{/each}
</div>
<ul>
{#each scoreboard as player (player.name)}
<li animate:flip class:dead-player={!player.lives}>
{player.name}
<span class="score">{player.score}</span>
{#if !player.lives}
<div class="dead">DEAD</div>
{/if}
</li>
{/each}
</ul>
</div>
<main>
<slot />
</main>
<div class="right">
</div>
</div>
<style>
.hearts img {
width: 20px;
height: 20px;
margin: 0 5px;
}
.hearts {
height: 30px;
}
.container {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
height: 100vh;
width: 100vw;
background-color: #85e65c;
}
main {
max-width: calc(100vw - 310px);
border-left: 10px solid #bd5ce6;
}
.left {
flex-grow: 1;
width: 300px;
height: calc(100% - 10px);
margin: 5px;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
li {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.5rem;
border-bottom: 1px solid #ccc;
}
li:last-child {
border-bottom: none;
}
li.dead-player {
color: #ccc;
}
.dead {
font-weight: bold;
font-size: 1.2rem;
margin-left: 1rem;
}
.score {
font-size: 1.5em;
font-weight: bold;
background-color: #bd5ce6;
color: #85e65c;
}
</style>

View file

@ -4,22 +4,19 @@ import { GameScene } from "./scene";
var ratio = window.devicePixelRatio || 1;
export function resize() {
if(!game || !htmlcanvas) return;
try {
game.scale.resize(htmlcanvas.parentElement!.clientWidth * ratio, htmlcanvas.parentElement!.clientHeight * ratio);
} catch(e) {
// @ts-ignore
console.error(e, new ErrorEvent(e.type, { colno: e.colno, error: e, lineno: e.lineno, message: e.message, filename: e.filename }));
window.dispatchEvent(new ErrorEvent("error", e as any));
}
// try {
// game.scale.resize(htmlcanvas.parentElement!.clientWidth * ratio, htmlcanvas.parentElement!.clientHeight * ratio);
// } catch(e) {
// // @ts-ignore
// console.error(e, new ErrorEvent(e.type, { colno: e.colno, error: e, lineno: e.lineno, message: e.message, filename: e.filename }));
// window.dispatchEvent(new ErrorEvent("error", e as any));
// }
// console.log("size", htmlcanvas.parentElement!.clientWidth * ratio, htmlcanvas.parentElement!.clientHeight * ratio);
}
/** @type {HTMLCanvasElement} */
var htmlcanvas: HTMLCanvasElement;
/** @type {Game} */
var game: Game;
/** @type {GameScene} */
var gs: GameScene;
var gs: GameScene | null = null;
export function setCanvas(canvas: HTMLCanvasElement) {
htmlcanvas = canvas;
var ctx = canvas.getContext("webgl2") || canvas.getContext("webgl");
@ -43,7 +40,12 @@ export function setCanvas(canvas: HTMLCanvasElement) {
title: "Multidie",
version: "0",
scene: [gs],
backgroundColor: "#01021B",
backgroundColor: "#85e65c",
banner: false
});
}
export function stop() {
game.destroy(false);
gs = null;
}

View file

@ -0,0 +1,28 @@
<script lang="ts">
import { connection, gameData } from "$lib/Websocket";
import { onMount } from "svelte";
import { setCanvas, resize, stop } from "./init";
var canvas: HTMLCanvasElement;
onMount(() => {
console.log("Started");
setCanvas(canvas);
return () => {
console.log("Stopped");
stop();
}
});
function increaseScore() {
$connection!.setScore($gameData!.score + 1);
}
function decreaseLives() {
$connection!.setLives($gameData!.lives - 1);
}
</script>
<svelte:window on:resize={resize} />
<canvas bind:this={canvas} on:click={increaseScore} on:contextmenu={decreaseLives} />

View file

@ -7,7 +7,7 @@
onMount(() => {
let i = setTimeout(() => {
visible = false;
}, 3000);
}, 2000);
return () => clearTimeout(i);
});
</script>

View file

@ -3,7 +3,7 @@
import Button from '../components/button.svelte';
function startGame() {
$connection!.startGame();
}
let content = "";
function sendMessage() {

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB