format
This commit is contained in:
3
.prettierrc.json
Normal file
3
.prettierrc.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"semi": false
|
||||||
|
}
|
||||||
138
src/main.ts
138
src/main.ts
@@ -1,33 +1,33 @@
|
|||||||
import { crew } from "@kaplayjs/crew";
|
import { crew } from "@kaplayjs/crew"
|
||||||
import kaplay from "kaplay";
|
import kaplay from "kaplay"
|
||||||
import { createCards } from "./card";
|
import { createCards } from "./card"
|
||||||
import { WOBBLE_ANGLE, SPEED } from "./constants";
|
import { WOBBLE_ANGLE, SPEED } from "./constants"
|
||||||
import "kaplay/global"; // uncomment if you want to use without the prefix
|
import "kaplay/global" // uncomment if you want to use without the prefix
|
||||||
import { initWebRTC } from "./multiplayer";
|
import { initWebRTC } from "./multiplayer"
|
||||||
|
|
||||||
export const k = kaplay({
|
export const k = kaplay({
|
||||||
plugins: [crew],
|
plugins: [crew],
|
||||||
background: "#4e495f",
|
background: "#4e495f",
|
||||||
scale: 2,
|
scale: 2,
|
||||||
debugKey: "r",
|
debugKey: "r",
|
||||||
});
|
})
|
||||||
|
|
||||||
loadRoot("./"); // A good idea for Itch.io publishing later
|
loadRoot("./") // A good idea for Itch.io publishing later
|
||||||
loadSprite("card", "sprites/card.png");
|
loadSprite("card", "sprites/card.png")
|
||||||
loadSprite("octo", "sprites/octo.png");
|
loadSprite("octo", "sprites/octo.png")
|
||||||
loadSprite("dead", "sprites/dead.png");
|
loadSprite("dead", "sprites/dead.png")
|
||||||
loadSprite("triboi", "sprites/triboi.png");
|
loadSprite("triboi", "sprites/triboi.png")
|
||||||
loadSprite("wolfi", "sprites/wolfi.png");
|
loadSprite("wolfi", "sprites/wolfi.png")
|
||||||
loadSprite("bubble", "sprites/bubble.png");
|
loadSprite("bubble", "sprites/bubble.png")
|
||||||
|
|
||||||
k.loadCrew("sprite", "cursor");
|
k.loadCrew("sprite", "cursor")
|
||||||
k.loadCrew("sprite", "pointer");
|
k.loadCrew("sprite", "pointer")
|
||||||
k.loadCrew("sprite", "kat");
|
k.loadCrew("sprite", "kat")
|
||||||
k.loadCrew("sprite", "pineapple");
|
k.loadCrew("sprite", "pineapple")
|
||||||
k.loadCrew("sprite", "been");
|
k.loadCrew("sprite", "been")
|
||||||
k.loadCrew("font", "happy");
|
k.loadCrew("font", "happy")
|
||||||
|
|
||||||
setLayers(["game", "hover", "ui"], "game");
|
setLayers(["game", "hover", "ui"], "game")
|
||||||
|
|
||||||
const createPlayer = (scravatar: string) => {
|
const createPlayer = (scravatar: string) => {
|
||||||
const player = add([
|
const player = add([
|
||||||
@@ -41,48 +41,48 @@ const createPlayer = (scravatar: string) => {
|
|||||||
animate(),
|
animate(),
|
||||||
named("player"),
|
named("player"),
|
||||||
"player",
|
"player",
|
||||||
]);
|
])
|
||||||
|
|
||||||
player.animate("angle", [WOBBLE_ANGLE, -WOBBLE_ANGLE], {
|
player.animate("angle", [WOBBLE_ANGLE, -WOBBLE_ANGLE], {
|
||||||
easing: easings.easeInOutCubic,
|
easing: easings.easeInOutCubic,
|
||||||
direction: "ping-pong",
|
direction: "ping-pong",
|
||||||
duration: 1,
|
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([
|
const bubbleText = bubble.add([
|
||||||
text("9", { font: "happy", size: 24 }),
|
text("9", { font: "happy", size: 24 }),
|
||||||
pos(-5, -24),
|
pos(-5, -24),
|
||||||
color(Color.BLACK),
|
color(Color.BLACK),
|
||||||
timer(),
|
timer(),
|
||||||
]);
|
])
|
||||||
|
|
||||||
bubble.hidden = true;
|
bubble.hidden = true
|
||||||
|
|
||||||
player.on("countdown", () => {
|
player.on("countdown", () => {
|
||||||
bubble.hidden = false;
|
bubble.hidden = false
|
||||||
let time = 9;
|
let time = 9
|
||||||
bubbleText.loop(
|
bubbleText.loop(
|
||||||
1,
|
1,
|
||||||
() => {
|
() => {
|
||||||
if (time === -1) {
|
if (time === -1) {
|
||||||
bubble.hidden = true;
|
bubble.hidden = true
|
||||||
}
|
}
|
||||||
|
|
||||||
bubbleText.text = time.toString();
|
bubbleText.text = time.toString()
|
||||||
time--;
|
time--
|
||||||
},
|
},
|
||||||
11,
|
11,
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
|
|
||||||
return player;
|
return player
|
||||||
};
|
}
|
||||||
|
|
||||||
scene("menu", () => {
|
scene("menu", () => {
|
||||||
add([text("Choose your Scravatar", { font: "happy" })]);
|
add([text("Choose your Scravatar", { font: "happy" })])
|
||||||
["wolfi", "octo", "dead", "triboi"].forEach((image, i) => {
|
;["wolfi", "octo", "dead", "triboi"].forEach((image, i) => {
|
||||||
const selection = add([
|
const selection = add([
|
||||||
pos(88 * i + 100, 100),
|
pos(88 * i + 100, 100),
|
||||||
anchor("center"),
|
anchor("center"),
|
||||||
@@ -90,74 +90,74 @@ scene("menu", () => {
|
|||||||
opacity(0.1),
|
opacity(0.1),
|
||||||
z(-1),
|
z(-1),
|
||||||
area(),
|
area(),
|
||||||
]);
|
])
|
||||||
|
|
||||||
selection.add([
|
selection.add([
|
||||||
text(image.toUpperCase(), { font: "happy", size: 14 }),
|
text(image.toUpperCase(), { font: "happy", size: 14 }),
|
||||||
anchor("center"),
|
anchor("center"),
|
||||||
pos(0, 40),
|
pos(0, 40),
|
||||||
]);
|
])
|
||||||
|
|
||||||
const avatar = selection.add([
|
const avatar = selection.add([
|
||||||
sprite(image),
|
sprite(image),
|
||||||
rotate(),
|
rotate(),
|
||||||
animate(),
|
animate(),
|
||||||
anchor("center"),
|
anchor("center"),
|
||||||
]);
|
])
|
||||||
|
|
||||||
selection.onHover(() => {
|
selection.onHover(() => {
|
||||||
selection.opacity = 1;
|
selection.opacity = 1
|
||||||
setCursor("pointer");
|
setCursor("pointer")
|
||||||
});
|
})
|
||||||
|
|
||||||
selection.onHoverEnd(() => {
|
selection.onHoverEnd(() => {
|
||||||
selection.opacity = 0.1;
|
selection.opacity = 0.1
|
||||||
setCursor("default");
|
setCursor("default")
|
||||||
});
|
})
|
||||||
|
|
||||||
selection.onClick(() => {
|
selection.onClick(() => {
|
||||||
pushScene("game", image);
|
pushScene("game", image)
|
||||||
}, "left");
|
}, "left")
|
||||||
|
|
||||||
avatar.animate("angle", [WOBBLE_ANGLE, -WOBBLE_ANGLE], {
|
avatar.animate("angle", [WOBBLE_ANGLE, -WOBBLE_ANGLE], {
|
||||||
easing: easings.easeInOutCubic,
|
easing: easings.easeInOutCubic,
|
||||||
direction: "ping-pong",
|
direction: "ping-pong",
|
||||||
duration: 1,
|
duration: 1,
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
const peerIDToConnect = location.pathname.replace("/", "");
|
const peerIDToConnect = location.pathname.replace("/", "")
|
||||||
initWebRTC(peerIDToConnect);
|
initWebRTC((gameState) => {}, peerIDToConnect)
|
||||||
});
|
})
|
||||||
|
|
||||||
scene("game", (scravatar: string) => {
|
scene("game", (scravatar: string) => {
|
||||||
createCards();
|
createCards()
|
||||||
const player = createPlayer(scravatar);
|
const player = createPlayer(scravatar)
|
||||||
|
|
||||||
onUpdate(() => {
|
onUpdate(() => {
|
||||||
setCamPos(lerp(getCamPos(), player.pos, 0.1));
|
setCamPos(lerp(getCamPos(), player.pos, 0.1))
|
||||||
});
|
})
|
||||||
|
|
||||||
onKeyDown(["w", "up"], () => {
|
onKeyDown(["w", "up"], () => {
|
||||||
player.moveBy(0, -SPEED);
|
player.moveBy(0, -SPEED)
|
||||||
});
|
})
|
||||||
|
|
||||||
onKeyDown(["a", "left"], () => {
|
onKeyDown(["a", "left"], () => {
|
||||||
player.moveBy(-SPEED, 0);
|
player.moveBy(-SPEED, 0)
|
||||||
});
|
})
|
||||||
|
|
||||||
onKeyDown(["s", "down"], () => {
|
onKeyDown(["s", "down"], () => {
|
||||||
player.moveBy(0, SPEED);
|
player.moveBy(0, SPEED)
|
||||||
});
|
})
|
||||||
|
|
||||||
onKeyDown(["d", "right"], () => {
|
onKeyDown(["d", "right"], () => {
|
||||||
player.moveBy(SPEED, 0);
|
player.moveBy(SPEED, 0)
|
||||||
});
|
})
|
||||||
|
|
||||||
onKeyDown("u", () => {
|
onKeyDown("u", () => {
|
||||||
player.trigger("countdown");
|
player.trigger("countdown")
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
pushScene("menu");
|
pushScene("menu")
|
||||||
// pushScene("game", "wolfi");
|
// pushScene("game", "wolfi");
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import { Peer } from "peerjs";
|
import { DataConnection, DataConnectionErrorType, Peer } from "peerjs"
|
||||||
|
import { GameState, Message } from "./types"
|
||||||
|
|
||||||
const configuration: RTCConfiguration = {
|
const configuration: RTCConfiguration = {
|
||||||
iceServers: [
|
iceServers: [
|
||||||
{
|
{
|
||||||
@@ -25,43 +27,105 @@ const configuration: RTCConfiguration = {
|
|||||||
credential: "N3Bhe64kpGzogdjY",
|
credential: "N3Bhe64kpGzogdjY",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
};
|
}
|
||||||
|
|
||||||
type Message = {
|
const peers: Record<string, { conn: DataConnection; lastHeartBeat: string }>[] =
|
||||||
type: "HeartBeat" | "GameState" | "UpdatePosition";
|
[]
|
||||||
};
|
|
||||||
|
|
||||||
export async function initWebRTC(peerId?: string) {
|
const gameState: GameState = {
|
||||||
|
players: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function initWebRTC(
|
||||||
|
render: (gameState: GameState) => void,
|
||||||
|
peerId?: string,
|
||||||
|
) {
|
||||||
const peer = new Peer({
|
const peer = new Peer({
|
||||||
config: configuration,
|
config: configuration,
|
||||||
});
|
})
|
||||||
|
|
||||||
|
// Host Part
|
||||||
peer.on("connection", (conn) => {
|
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("open", () => {
|
||||||
conn.on("data", (data: Message) => {
|
conn.on("data", (data: Message) => {
|
||||||
console.log(`Data: ${data}`);
|
switch (data.type) {
|
||||||
});
|
case "HeartBeat":
|
||||||
|
peers[conn.peer].lastHeartBeat = new Date().toISOString()
|
||||||
conn.send("Hello from HOST?!");
|
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) => {
|
peer.on("open", (id) => {
|
||||||
console.log(`My peer ID is: ${id}`);
|
|
||||||
|
|
||||||
if (peerId) {
|
if (peerId) {
|
||||||
console.log(`Connecting to: ${peerId}`);
|
// Client Part
|
||||||
const conn = peer.connect(peerId);
|
console.log(`Connecting to: ${peerId}`)
|
||||||
|
const conn = peer.connect(peerId)
|
||||||
|
|
||||||
conn.on("open", () => {
|
conn.on("open", () => {
|
||||||
conn.on("data", (data: Message) => {
|
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)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
29
src/types.ts
Normal file
29
src/types.ts
Normal file
@@ -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
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user