mirror of
https://github.com/danbulant/slightlyComplicatedTicTacToe
synced 2026-05-19 04:08:52 +00:00
overlay + test game
This commit is contained in:
parent
2cac7aea5f
commit
7240f0a539
9 changed files with 171 additions and 18 deletions
4
client/src/hooks.js
Normal file
4
client/src/hooks.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// @ts-ignore
|
||||
export async function handle({ event, resolve }) {
|
||||
return resolve(event, { ssr: false });
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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} />
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
onMount(() => {
|
||||
let i = setTimeout(() => {
|
||||
visible = false;
|
||||
}, 3000);
|
||||
}, 2000);
|
||||
return () => clearTimeout(i);
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import Button from '../components/button.svelte';
|
||||
|
||||
function startGame() {
|
||||
|
||||
$connection!.startGame();
|
||||
}
|
||||
let content = "";
|
||||
function sendMessage() {
|
||||
|
|
|
|||
BIN
client/static/assets/heart.png
Normal file
BIN
client/static/assets/heart.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
Loading…
Reference in a new issue