From 0aca1d58e6b92ac000c3127bd4799d5513d1a16e Mon Sep 17 00:00:00 2001 From: Jens Date: Tue, 24 Feb 2026 21:02:37 +0100 Subject: [PATCH] format --- .prettierrc.json | 3 + src/main.ts | 138 ++++++++++++++++++++++----------------------- src/multiplayer.ts | 110 ++++++++++++++++++++++++++++-------- src/types.ts | 29 ++++++++++ 4 files changed, 188 insertions(+), 92 deletions(-) create mode 100644 .prettierrc.json create mode 100644 src/types.ts diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..cce9d3c --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "semi": false +} diff --git a/src/main.ts b/src/main.ts index d2e7b59..154305e 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,33 +1,33 @@ -import { crew } from "@kaplayjs/crew"; -import kaplay from "kaplay"; -import { createCards } from "./card"; -import { WOBBLE_ANGLE, SPEED } from "./constants"; -import "kaplay/global"; // uncomment if you want to use without the prefix -import { initWebRTC } from "./multiplayer"; +import { crew } from "@kaplayjs/crew" +import kaplay from "kaplay" +import { createCards } from "./card" +import { WOBBLE_ANGLE, SPEED } from "./constants" +import "kaplay/global" // uncomment if you want to use without the prefix +import { initWebRTC } from "./multiplayer" export const k = kaplay({ plugins: [crew], background: "#4e495f", scale: 2, debugKey: "r", -}); +}) -loadRoot("./"); // A good idea for Itch.io publishing later -loadSprite("card", "sprites/card.png"); -loadSprite("octo", "sprites/octo.png"); -loadSprite("dead", "sprites/dead.png"); -loadSprite("triboi", "sprites/triboi.png"); -loadSprite("wolfi", "sprites/wolfi.png"); -loadSprite("bubble", "sprites/bubble.png"); +loadRoot("./") // A good idea for Itch.io publishing later +loadSprite("card", "sprites/card.png") +loadSprite("octo", "sprites/octo.png") +loadSprite("dead", "sprites/dead.png") +loadSprite("triboi", "sprites/triboi.png") +loadSprite("wolfi", "sprites/wolfi.png") +loadSprite("bubble", "sprites/bubble.png") -k.loadCrew("sprite", "cursor"); -k.loadCrew("sprite", "pointer"); -k.loadCrew("sprite", "kat"); -k.loadCrew("sprite", "pineapple"); -k.loadCrew("sprite", "been"); -k.loadCrew("font", "happy"); +k.loadCrew("sprite", "cursor") +k.loadCrew("sprite", "pointer") +k.loadCrew("sprite", "kat") +k.loadCrew("sprite", "pineapple") +k.loadCrew("sprite", "been") +k.loadCrew("font", "happy") -setLayers(["game", "hover", "ui"], "game"); +setLayers(["game", "hover", "ui"], "game") const createPlayer = (scravatar: string) => { const player = add([ @@ -41,48 +41,48 @@ const createPlayer = (scravatar: string) => { animate(), named("player"), "player", - ]); + ]) player.animate("angle", [WOBBLE_ANGLE, -WOBBLE_ANGLE], { easing: easings.easeInOutCubic, direction: "ping-pong", duration: 1, - }); + }) - const bubble = player.add([sprite("bubble"), anchor("center"), pos(30, -50)]); + const bubble = player.add([sprite("bubble"), anchor("center"), pos(30, -50)]) const bubbleText = bubble.add([ text("9", { font: "happy", size: 24 }), pos(-5, -24), color(Color.BLACK), timer(), - ]); + ]) - bubble.hidden = true; + bubble.hidden = true player.on("countdown", () => { - bubble.hidden = false; - let time = 9; + bubble.hidden = false + let time = 9 bubbleText.loop( 1, () => { if (time === -1) { - bubble.hidden = true; + bubble.hidden = true } - bubbleText.text = time.toString(); - time--; + bubbleText.text = time.toString() + time-- }, 11, - ); - }); + ) + }) - return player; -}; + return player +} scene("menu", () => { - add([text("Choose your Scravatar", { font: "happy" })]); - ["wolfi", "octo", "dead", "triboi"].forEach((image, i) => { + add([text("Choose your Scravatar", { font: "happy" })]) + ;["wolfi", "octo", "dead", "triboi"].forEach((image, i) => { const selection = add([ pos(88 * i + 100, 100), anchor("center"), @@ -90,74 +90,74 @@ scene("menu", () => { opacity(0.1), z(-1), area(), - ]); + ]) selection.add([ text(image.toUpperCase(), { font: "happy", size: 14 }), anchor("center"), pos(0, 40), - ]); + ]) const avatar = selection.add([ sprite(image), rotate(), animate(), anchor("center"), - ]); + ]) selection.onHover(() => { - selection.opacity = 1; - setCursor("pointer"); - }); + selection.opacity = 1 + setCursor("pointer") + }) selection.onHoverEnd(() => { - selection.opacity = 0.1; - setCursor("default"); - }); + selection.opacity = 0.1 + setCursor("default") + }) selection.onClick(() => { - pushScene("game", image); - }, "left"); + pushScene("game", image) + }, "left") avatar.animate("angle", [WOBBLE_ANGLE, -WOBBLE_ANGLE], { easing: easings.easeInOutCubic, direction: "ping-pong", duration: 1, - }); - }); + }) + }) - const peerIDToConnect = location.pathname.replace("/", ""); - initWebRTC(peerIDToConnect); -}); + const peerIDToConnect = location.pathname.replace("/", "") + initWebRTC((gameState) => {}, peerIDToConnect) +}) scene("game", (scravatar: string) => { - createCards(); - const player = createPlayer(scravatar); + createCards() + const player = createPlayer(scravatar) onUpdate(() => { - setCamPos(lerp(getCamPos(), player.pos, 0.1)); - }); + setCamPos(lerp(getCamPos(), player.pos, 0.1)) + }) onKeyDown(["w", "up"], () => { - player.moveBy(0, -SPEED); - }); + player.moveBy(0, -SPEED) + }) onKeyDown(["a", "left"], () => { - player.moveBy(-SPEED, 0); - }); + player.moveBy(-SPEED, 0) + }) onKeyDown(["s", "down"], () => { - player.moveBy(0, SPEED); - }); + player.moveBy(0, SPEED) + }) onKeyDown(["d", "right"], () => { - player.moveBy(SPEED, 0); - }); + player.moveBy(SPEED, 0) + }) onKeyDown("u", () => { - player.trigger("countdown"); - }); -}); + player.trigger("countdown") + }) +}) -pushScene("menu"); +pushScene("menu") // pushScene("game", "wolfi"); diff --git a/src/multiplayer.ts b/src/multiplayer.ts index 6f9db8c..48634f0 100644 --- a/src/multiplayer.ts +++ b/src/multiplayer.ts @@ -1,4 +1,6 @@ -import { Peer } from "peerjs"; +import { DataConnection, DataConnectionErrorType, Peer } from "peerjs" +import { GameState, Message } from "./types" + const configuration: RTCConfiguration = { iceServers: [ { @@ -25,43 +27,105 @@ const configuration: RTCConfiguration = { credential: "N3Bhe64kpGzogdjY", }, ], -}; +} -type Message = { - type: "HeartBeat" | "GameState" | "UpdatePosition"; -}; +const peers: Record[] = + [] -export async function initWebRTC(peerId?: string) { +const gameState: GameState = { + players: [], +} + +export async function initWebRTC( + render: (gameState: GameState) => void, + peerId?: string, +) { const peer = new Peer({ config: configuration, - }); + }) + // Host Part peer.on("connection", (conn) => { - console.log(`Connection received from: ${conn.peer}`); + console.log(`Connection received from: ${conn.peer}`) + + peers[conn.peer] = { + lastHeartBeat: new Date().toISOString(), + conn, + } conn.on("open", () => { conn.on("data", (data: Message) => { - console.log(`Data: ${data}`); - }); - - conn.send("Hello from HOST?!"); - }); - }); + switch (data.type) { + case "HeartBeat": + peers[conn.peer].lastHeartBeat = new Date().toISOString() + console.log("Updating peers", peers) + break + case "GameState": + console.error("Clients shouldn't send GameState messages") + break + case "UpdatePosition": + gameState.players.map((p) => { + if (p.peerId == conn.peer) { + return { ...p, position: data.pos } + } + return p + }) + break + case "Register": + console.log() + gameState.players.push(data.player) + break + } + }) + }) + }) peer.on("open", (id) => { - console.log(`My peer ID is: ${id}`); - if (peerId) { - console.log(`Connecting to: ${peerId}`); - const conn = peer.connect(peerId); + // Client Part + console.log(`Connecting to: ${peerId}`) + const conn = peer.connect(peerId) conn.on("open", () => { conn.on("data", (data: Message) => { - console.log(`Data: ${data}`); - }); + if (data.type === "GameState") { + render(data.state) + } + }) - conn.send("Hello from CLIENT!"); - }); + const registerMsg: Message = { + type: "Register", + player: { + peerId: id, + name: "peter", + position: vec2(0), + scravatar: "wolfi", + }, + } + conn.send(registerMsg) + + setInterval(() => { + console.log("Sending HeartBeat") + const msg: Message = { + type: "HeartBeat", + } + + conn.send(msg) + }, 500) + }) + } else { + console.log(`${window.location}${id}`) + // Host Part + setInterval(() => { + const msg: Message = { + type: "GameState", + state: gameState, + } + + peers.forEach((r) => { + r.value.conn.send(msg) + }) + }, 60) } - }); + }) } diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..fa80efc --- /dev/null +++ b/src/types.ts @@ -0,0 +1,29 @@ +import { Vec2 } from "kaplay" + +export type Player = { + peerId: string + name: string + scravatar: string + position: Vec2 +} + +export type GameState = { + players: Player[] +} + +export type Message = + | { + type: "HeartBeat" + } + | { + type: "GameState" + state: GameState + } + | { + type: "UpdatePosition" + pos: Vec2 + } + | { + type: "Register" + player: Player + }