diff --git a/client.ts b/client.ts index d10a49f..0956233 100644 --- a/client.ts +++ b/client.ts @@ -4,19 +4,44 @@ import * as Phaser from "phaser"; interface ICoords { - x: number; - y: number; + [key: string]: { + x: number; + y: number; + frame: number; + } +} +function uuid( + a?: any // placeholder +): string { + return a // if the placeholder was passed, return + ? ( // a random number from 0 to 15 + a ^ // unless b is 8, + Math.random() // in which case + * 16 // a random number from + >> a / 4 // 8 to 11 + ).toString(16) // in hexadecimal + : ( // or otherwise a concatenated string: + 1e7.toString() + // 10000000 + + -1e3 + // -1000 + + -4e3 + // -4000 + + -8e3 + // -80000000 + + -1e11 // -100000000000, + ).replace( // replacing + /[018]/g, // zeroes, ones, and eights with + uuid // random hex digits + ) } - const DEBUG = false; // Render debug physics entities class GameScene extends Phaser.Scene { private HOST = window.location.hostname; // localhost and 127.0.0.1 handled - private PORT = 8080; // change this if needed + private PORT = 8000; // change this if needed private VELOCITY = 100; private wsClient?: WebSocket; - private player?: Phaser.GameObjects.Sprite; + // private player?: Phaser.GameObjects.Sprite; + private id = uuid(); + private players: {[key: string]: Phaser.GameObjects.Sprite} = {}; private leftKey?: Phaser.Input.Keyboard.Key; private rightKey?: Phaser.Input.Keyboard.Key; private upKey?: Phaser.Input.Keyboard.Key; @@ -44,9 +69,32 @@ class GameScene extends Phaser.Scene { this.wsClient.onopen = (event) => console.log(event); // TODO: multiplayer functionality this.wsClient.onmessage = (wsMsgEvent) => { - console.log(wsMsgEvent) + const allCoords: ICoords = JSON.parse(wsMsgEvent.data); + for (const playerId of Object.keys(allCoords)) { + if (playerId === this.id) { + // we don't need to update ourselves + continue; + } + const { x, y, frame } = allCoords[playerId]; + if (playerId in this.players) { + // We have seen this player before, update it! + const player = this.players[playerId]; + if (player.texture.key === "__MISSING") { + // Player was instantiated before texture was ready, reinstantiate + player.destroy(); + this.players[playerId] = this.add.sprite(x, y, "player", frame); + } else { + player.setX(x); + player.setY(y); + player.setFrame(frame); + } + } else { + // We have not seen this player before, create it! + this.players[playerId] = this.add.sprite(x, y, "player", frame); + } } } + } /** * Create the game objects required by the scene @@ -88,9 +136,9 @@ class GameScene extends Phaser.Scene { }); // Player game object - this.player = this.physics.add.sprite(48, 48, "player", 1); - this.physics.add.collider(this.player, layer); - this.cameras.main.startFollow(this.player); + this.players[this.id] = this.physics.add.sprite(48, 48, "player", 1); + this.physics.add.collider(this.players[this.id], layer); + this.cameras.main.startFollow(this.players[this.id]); this.cameras.main.setBounds( 0, 0, tileMap.widthInPixels, tileMap.heightInPixels ); @@ -103,35 +151,51 @@ class GameScene extends Phaser.Scene { } public update() { - if (this.player) { + for (const playerId of Object.keys(this.players)) { + const player = this.players[playerId]; + if (playerId !== this.id) { + player.setTint(0x0000aa); // so we can tell our guy apart + player.update(); + continue; + } + } + if (this.players[this.id]) { + const player = this.players[this.id]; let moving = false; if (this.leftKey && this.leftKey.isDown) { - (this.player.body as Phaser.Physics.Arcade.Body).setVelocityX(-this.VELOCITY); - this.player.play("left", true); + (player.body as Phaser.Physics.Arcade.Body).setVelocityX(-this.VELOCITY); + player.play("left", true); moving = true; } else if (this.rightKey && this.rightKey.isDown) { - (this.player.body as Phaser.Physics.Arcade.Body).setVelocityX(this.VELOCITY); - this.player.play("right", true); + (player.body as Phaser.Physics.Arcade.Body).setVelocityX(this.VELOCITY); + player.play("right", true); moving = true; } else { - (this.player.body as Phaser.Physics.Arcade.Body).setVelocityX(0); + (player.body as Phaser.Physics.Arcade.Body).setVelocityX(0); } if (this.upKey && this.upKey.isDown) { - (this.player.body as Phaser.Physics.Arcade.Body).setVelocityY(-this.VELOCITY); - this.player.play("up", true); + (player.body as Phaser.Physics.Arcade.Body).setVelocityY(-this.VELOCITY); + player.play("up", true); moving = true; } else if (this.downKey && this.downKey.isDown) { - (this.player.body as Phaser.Physics.Arcade.Body).setVelocityY(this.VELOCITY); - this.player.play("down", true); + (player.body as Phaser.Physics.Arcade.Body).setVelocityY(this.VELOCITY); + player.play("down", true); moving = true; } else { - (this.player.body as Phaser.Physics.Arcade.Body).setVelocityY(0); + (player.body as Phaser.Physics.Arcade.Body).setVelocityY(0); } if (!moving) { - (this.player.body as Phaser.Physics.Arcade.Body).setVelocity(0); - this.player.anims.stop(); + (player.body as Phaser.Physics.Arcade.Body).setVelocity(0); + player.anims.stop(); + }else if (this.wsClient) { + this.wsClient.send(JSON.stringify({ + id: this.id, + x: player.x, + y: player.y, + frame: player.frame.name + })); } - this.player.update(); + player.update(); } } } @@ -159,4 +223,4 @@ class LabDemoGame extends Phaser.Game { window.addEventListener("load", () => { new LabDemoGame(config); -}); +}); \ No newline at end of file diff --git a/server.js b/server.js index 0238033..c7c8e29 100755 --- a/server.js +++ b/server.js @@ -1,13 +1,13 @@ #!/usr/bin/env node -const { Server: WebSocketServer } = require("ws"); -const express = require("express"); -const http = require("http"); -const ParcelBundler = require("parcel-bundler"); +const { Server: WebSocketServer } = require('ws'); +const express = require('express'); +const http = require('http'); +const ParcelBundler = require('parcel-bundler'); -const PORT = process.env.PORT || 8080; -const PUBLIC_DIR = "public"; -const STATIC_DIR = "static"; +const PORT = process.env.PORT || 8000; +const PUBLIC_DIR = 'public'; +const STATIC_DIR = 'static'; /** * Build and minify all client code for Express @@ -18,9 +18,9 @@ function bundleClient() { contentHash: true, bundleNodeModules: true, watch: false, - detailedReport: true + detailedReport: true, }; - const bundler = new ParcelBundler("index.html", options); + const bundler = new ParcelBundler('index.html', options); return bundler.bundle(); } @@ -30,24 +30,30 @@ function bundleClient() { function setupWSServer(server) { const wss = new WebSocketServer({ server, - autoAcceptConnections: false + autoAcceptConnections: false, }); let actorCoordinates = { x: 100, y: 100 }; - wss.on("connection", (ws) => { - ws.on("message", (rawMsg) => { + wss.on('connection', (ws) => { + ws.on('message', (rawMsg) => { console.log(`RECV: ${rawMsg}`); const incommingMessage = JSON.parse(rawMsg); - actorCoordinates.x = incommingMessage.x; - actorCoordinates.y = incommingMessage.y; + // actorCoordinates.x = incommingMessage.x; + // actorCoordinates.y = incommingMessage.y; + actorCoordinates[incommingMessage.id] = { + x: incommingMessage.x, + y: incommingMessage.y, + frame: incommingMessage.frame, + }; wss.clients.forEach((wsClient) => { wsClient.send(JSON.stringify(actorCoordinates)); - }) + }); }); ws.send(JSON.stringify(actorCoordinates)); }); - wss.on("listening", () => { + wss.on('listening', () => { const addr = server.address(); - const bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port; + const bind = + typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; console.log(`WebSocketServer listening on ${bind}`); }); return wss; @@ -59,19 +65,20 @@ function setupWSServer(server) { function setupServer() { // Setup the Express application const app = express(); - app.set("port", PORT) - app.use("/", express.static(PUBLIC_DIR)) - app.use("/static", express.static(STATIC_DIR)) + app.set('port', PORT); + app.use('/', express.static(PUBLIC_DIR)); + app.use('/static', express.static(STATIC_DIR)); // Setup the HTTP Web Server const server = http.createServer(app); server.listen(PORT); - server.on("listening", () => { + server.on('listening', () => { const addr = server.address(); - const bind = typeof addr === "string" ? "pipe " + addr : "port " + addr.port; + const bind = + typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port; console.log(`WebServer listening on ${bind}`); }); - server.on("error", (err) => { + server.on('error', (err) => { console.error(err); process.exit(1); }); @@ -83,4 +90,4 @@ if (require.main === module) { const server = setupServer(); setupWSServer(server); }); -} +} \ No newline at end of file