mirror of
https://github.com/thib8956/tic-tac-toe-ws.git
synced 2026-02-21 07:48:12 +00:00
fix: minor fixes
This commit is contained in:
28
client.ts
28
client.ts
@@ -31,6 +31,7 @@ let pendingEvts: Point[] = [];
|
|||||||
let isSpectator = false; // is this client in spectator mode?
|
let isSpectator = false; // is this client in spectator mode?
|
||||||
let myId: number | null = null;
|
let myId: number | null = null;
|
||||||
let mySymbol: "x" | "o" | null = null;
|
let mySymbol: "x" | "o" | null = null;
|
||||||
|
let animationId: number;
|
||||||
let canvasMsg: string = "Offline...";
|
let canvasMsg: string = "Offline...";
|
||||||
|
|
||||||
function drawGridBackground(ctx: CanvasRenderingContext2D, origin: Point) {
|
function drawGridBackground(ctx: CanvasRenderingContext2D, origin: Point) {
|
||||||
@@ -43,7 +44,7 @@ function drawGridBackground(ctx: CanvasRenderingContext2D, origin: Point) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let y = 1; y < 3; ++y) {
|
for (let y = 1; y < 3; ++y) {
|
||||||
ctx.moveTo(origin.x + 0, origin.y + y * CELL_SIZE);
|
ctx.moveTo(origin.x, origin.y + y * CELL_SIZE);
|
||||||
ctx.lineTo(origin.x + GRID_SIZE, origin.y + y * CELL_SIZE);
|
ctx.lineTo(origin.x + GRID_SIZE, origin.y + y * CELL_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,13 +54,13 @@ function drawGridBackground(ctx: CanvasRenderingContext2D, origin: Point) {
|
|||||||
function resizeCanvas(ctx: CanvasRenderingContext2D) {
|
function resizeCanvas(ctx: CanvasRenderingContext2D) {
|
||||||
ctx.canvas.width = window.innerWidth;
|
ctx.canvas.width = window.innerWidth;
|
||||||
ctx.canvas.height = window.innerHeight;
|
ctx.canvas.height = window.innerHeight;
|
||||||
ctx.clearRect(0, 0, ctx.canvas.height, ctx. canvas.width);
|
ctx.clearRect(0, 0, ctx.canvas.width, ctx. canvas.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
function coordToGridIndex(origin: Point, clientPos: Point): [number, number] | undefined {
|
function coordToGridIndex(origin: Point, clientPos: Point): [number, number] | undefined {
|
||||||
// Coord relative to origin of the grid (origin)
|
// Coord relative to origin of the grid (origin)
|
||||||
const pt = { x: clientPos.x - origin.x, y: clientPos.y - origin.y };
|
const pt = { x: clientPos.x - origin.x, y: clientPos.y - origin.y };
|
||||||
const gridIndex: [number, number] = [Math.floor(3 * pt.x / GRID_SIZE), Math.floor(3 * pt.y / GRID_SIZE)];
|
const gridIndex: [number, number] = [Math.floor(pt.x / CELL_SIZE), Math.floor(pt.y / CELL_SIZE)];
|
||||||
if (gridIndex[0] >= 0 && gridIndex[0] <= 2 && gridIndex[1] >= 0 && gridIndex[1] <= 2) {
|
if (gridIndex[0] >= 0 && gridIndex[0] <= 2 && gridIndex[1] >= 0 && gridIndex[1] <= 2) {
|
||||||
return gridIndex;
|
return gridIndex;
|
||||||
}
|
}
|
||||||
@@ -169,7 +170,7 @@ function update(ctx: CanvasRenderingContext2D, time: number, ws: WebSocket) {
|
|||||||
handlePendingEvts(ws, gridOrigin);
|
handlePendingEvts(ws, gridOrigin);
|
||||||
updateGridState(ctx, time, gridOrigin);
|
updateGridState(ctx, time, gridOrigin);
|
||||||
|
|
||||||
window.requestAnimationFrame(t => update(ctx, t, ws));
|
animationId = window.requestAnimationFrame(t => update(ctx, t, ws));
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
@@ -190,12 +191,26 @@ function init() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// websocket stuff
|
// websocket stuff
|
||||||
ws.onopen = (e) => {
|
ws.onopen = () => {
|
||||||
console.log("connected to websocket server");
|
console.log("connected to websocket server");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ws.onerror = () => {
|
||||||
|
canvasMsg = "Connection error!";
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = () => {
|
||||||
|
canvasMsg = "Disconnected";
|
||||||
|
};
|
||||||
|
|
||||||
ws.onmessage = (evt) => {
|
ws.onmessage = (evt) => {
|
||||||
const msg: Message = JSON.parse(evt.data);
|
let msg: Message;
|
||||||
|
try {
|
||||||
|
msg = JSON.parse(evt.data);
|
||||||
|
} catch {
|
||||||
|
console.debug("received non-JSON message, ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
switch (msg.kind) {
|
switch (msg.kind) {
|
||||||
case "hello": {
|
case "hello": {
|
||||||
@@ -260,6 +275,7 @@ function init() {
|
|||||||
|
|
||||||
window.addEventListener('resize', () => resizeCanvas(ctx));
|
window.addEventListener('resize', () => resizeCanvas(ctx));
|
||||||
window.requestAnimationFrame(t => update(ctx, t, ws));
|
window.requestAnimationFrame(t => update(ctx, t, ws));
|
||||||
|
window.addEventListener('beforeunload', () => cancelAnimationFrame(animationId));
|
||||||
}
|
}
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|||||||
36
server.ts
36
server.ts
@@ -1,14 +1,15 @@
|
|||||||
import type { Message, Update, Hello, EndGame, Symbol, SymbolWithHue } from "common.js"
|
import type { Message, Update, Hello, EndGame, Symbol, SymbolWithHue } from "common.js"
|
||||||
import { WebSocket, WebSocketServer, MessageEvent } from "ws";
|
import { WebSocket, WebSocketServer, MessageEvent } from "ws";
|
||||||
|
|
||||||
const port = 1234
|
const PORT = 1234;
|
||||||
const wss = new WebSocketServer({ port });
|
const GRID_SIZE = 3;
|
||||||
|
const wss = new WebSocketServer({ port: PORT });
|
||||||
|
|
||||||
let grid = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
let grid = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
let hues = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
let hues = [0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
let endGame = false;
|
let endGame = false;
|
||||||
|
|
||||||
console.log(`waiting for connection on ws://localhost:${port}`);
|
console.log(`waiting for connection on ws://localhost:${PORT}`);
|
||||||
|
|
||||||
interface Client {
|
interface Client {
|
||||||
id: number,
|
id: number,
|
||||||
@@ -36,7 +37,12 @@ wss.on("connection", (ws, req) => {
|
|||||||
if (playerId === 0) {
|
if (playerId === 0) {
|
||||||
spectateData.push(undefined);
|
spectateData.push(undefined);
|
||||||
} else {
|
} else {
|
||||||
const sym = clients.find(c => c.id === playerId)!.symbol;
|
const client = clients.find(c => c.id === playerId);
|
||||||
|
if (!client) {
|
||||||
|
spectateData.push(undefined);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const sym = client.symbol;
|
||||||
const hue = hues[i];
|
const hue = hues[i];
|
||||||
spectateData.push({ symbol: sym, hue: hue });
|
spectateData.push({ symbol: sym, hue: hue });
|
||||||
}
|
}
|
||||||
@@ -55,15 +61,25 @@ wss.on("connection", (ws, req) => {
|
|||||||
const helloMsg: Message = {
|
const helloMsg: Message = {
|
||||||
kind: "hello",
|
kind: "hello",
|
||||||
data: { id, symbol } as Hello
|
data: { id, symbol } as Hello
|
||||||
}
|
};
|
||||||
clients.push({id, ws, symbol});
|
clients.push({id, ws, symbol});
|
||||||
ws.send(JSON.stringify(helloMsg));
|
ws.send(JSON.stringify(helloMsg));
|
||||||
const addr = req.headers["x-forwarded-for"] || req.socket.remoteAddress;
|
const addr = req.headers["x-forwarded-for"] || req.socket.remoteAddress;
|
||||||
console.log(`player #${id} connected with address ${addr}. total clients ${clients.length}`);
|
console.log(`player #${id} connected with address ${addr}. total clients ${clients.length}`);
|
||||||
|
|
||||||
ws.addEventListener("message", (event: MessageEvent) => {
|
ws.addEventListener("message", (event: MessageEvent) => {
|
||||||
const message = JSON.parse(event.data as string);
|
let message;
|
||||||
|
try {
|
||||||
|
message = JSON.parse(event.data as string);
|
||||||
|
} catch {
|
||||||
|
console.warn("received non-JSON message, ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const {x, y} = message;
|
const {x, y} = message;
|
||||||
|
if (x < 0 || x >= GRID_SIZE || y < 0 || y >= GRID_SIZE) {
|
||||||
|
console.warn("received invalid move, ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const hue = Math.floor(Math.random() * 361); // hue is a value in degrees
|
const hue = Math.floor(Math.random() * 361); // hue is a value in degrees
|
||||||
const player = clients.find(x => x.ws === ws);
|
const player = clients.find(x => x.ws === ws);
|
||||||
if (!player) throw new Error("player not found");
|
if (!player) throw new Error("player not found");
|
||||||
@@ -93,12 +109,12 @@ wss.on("connection", (ws, req) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clients.length < 2 || player.id != currentPlayer?.id || endGame) {
|
if (clients.length < 2 || player.id !== currentPlayer?.id || endGame) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (grid[y*3+x] === 0) {
|
if (grid[y * GRID_SIZE + x] === 0) {
|
||||||
grid[y*3+x] = player.id;
|
grid[y * GRID_SIZE + x] = player.id;
|
||||||
hues[y*3+x] = hue;
|
hues[y*3+x] = hue;
|
||||||
const msg = JSON.stringify({
|
const msg = JSON.stringify({
|
||||||
kind: "update",
|
kind: "update",
|
||||||
@@ -151,7 +167,7 @@ wss.on("connection", (ws, req) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ws.on("close", (code: number) => {
|
ws.on("close", () => {
|
||||||
spectators = spectators.filter(s => s.readyState !== WebSocket.CLOSED);
|
spectators = spectators.filter(s => s.readyState !== WebSocket.CLOSED);
|
||||||
const isClientDisconnect = clients.some(c => c.ws === ws);
|
const isClientDisconnect = clients.some(c => c.ws === ws);
|
||||||
if (isClientDisconnect) {
|
if (isClientDisconnect) {
|
||||||
|
|||||||
Reference in New Issue
Block a user