diff --git a/game.js b/game.js index b825de5..814983c 100644 --- a/game.js +++ b/game.js @@ -1,9 +1,26 @@ const uuid = require('node-uuid'); +const players = {}; + const Game = function() { this.id = uuid.v4(); } +Game.prototype.addPlayer = function(id, name) { + if (!players[id]) { + players[id] = name; + } +} + +Game.prototype.removePlayer = function(id) { + players[id] = undefined; + delete players[id]; +} + +Game.prototype.getPlayers = function() { + return players; +} + Game.prototype.getRobots = function() { const robots = [ {x: 3, y: 1, color: 'red' }, diff --git a/ricochet.css b/ricochet.css new file mode 100644 index 0000000..70f7cf7 --- /dev/null +++ b/ricochet.css @@ -0,0 +1,111 @@ +* { + box-sizing: border-box; + font-family: Montserrat; +} + +.controls-container { + background: #e7e7e7; + bottom: 0; + left: 0; + position: absolute; + top: 0; + width: 300px; +} + +.controls-subtitle { + background-color: #555; + color: #fff; +} + +.controls-title { + background-color: #222; + background-image: url('sprite-robots.png'); + color: #fff; + font-size: 12px; + line-height: 48px; + text-align: center; +} + +.controls-room { + line-height: 48px; + text-align: center; +} + +.controls-room span { + +} + +.controls-room input { + +} + +.controls-room button { + +} + +.board-container { + background: conic-gradient(lime 0 25%, yellow 25% 50%, red 50% 75%, blue 75% 100%); + bottom: 0; + left: 300px; + position: absolute; + right: 0; + top: 0; +} + +#board { + border-color: #aaa; + border-style: solid; + border-width: 1px 0 0 1px; + margin: 0 auto; + position: relative; +} + +.board-wall-x { + background: #222; + height: 8px; + margin-top: -4px; + position: absolute; + width: 40px; +} + +.board-wall-y { + background: #222; + height: 40px; + margin-left: -4px; + position: absolute; + width: 8px; +} + +.board-robot { + border-radius: 18px; + height: 36px; + margin: 2px; + position: absolute; + width: 36px; +} + +.square{ + background: #ddd; + border-style: solid; + border-color: #aaa; + border-width: 0 1px 1px 0; + float: left; + height: 40px; + width: 40px; +} + +.moves { + background: salmon; +} + +.move-count { + background: yellow; + border-radius: 8px; + float: left; + font-size: 12px; + height: 16px; + line-height: 16px; + margin: 4px; + text-align: center; + width: 16px; +} \ No newline at end of file diff --git a/ricochet.html b/ricochet.html index af3ac3a..cd0e90a 100644 --- a/ricochet.html +++ b/ricochet.html @@ -4,108 +4,26 @@ Document - - + +
+
Puzzle Robots
-
+
Room ID
-
+ -
-
Grendel
-
Barbarossa
-
Pi
-
Wendy
+
+
Players
@@ -176,44 +94,43 @@ } }; - var connection = new WebSocket('ws://localhost:8080/ricochet', ['soap', 'xmpp']); - - // connection.onopen = function (evt) {}; - connection.onerror = console.error; - - connection.onmessage = function (msg) { - const data = JSON.parse(msg.data) - if (!data.head || !data.body) { - console.warn("Unprocessable entity: ", msg) - return; - } - - switch(data.head.type) { - case 'connect': - break; + const Controls = { + addPlayer: () => { + const rawInput = prompt("What is your name?"); + connection.send(JSON.stringify({ head: { type: 'addPlayer' }, body: rawInput })) + }, - case 'disconnect': - break; + removePlayer: (rawInput) => { + connection.send(JSON.stringify({ head: { type: 'removePlayer' }, body: rawInput })) + }, - case 'walls': - Board.placeWalls(data.body); - break; + updatePlayers: (names) => { + const container = document.getElementById('controls-players'); + console.log(names) + + Object.keys(names).forEach(connectionId => { + const id = `player-${connectionId}`; - case 'robots': - Board.placeRobots(data.body); - break; + if (document.getElementById(id)) { + return; + } - default: - console.warn("Unhandled message: ", msg) - } + const n = document.createElement('div'); + n.id = id; + n.innerHTML = names[connectionId]; + n.className = 'controls-player'; + container.appendChild(n) + }); + + // container.querySelectorAll('.controls-player').forEach(el => { + // if (!names[el.id]) { + // container.removeChild(el); + // } + // }) + }, }; - - document.getElementById('game-start').addEventListener('click', () => { - connection.send('says hello!') - }) - const Board = { squaresPerSide: 20, squareSize: 40, @@ -241,7 +158,6 @@ placeRobots: (robots) => { robots.forEach(robot => { const [color, x, y] = robot; - console.warn(color) const r = document.createElement('div'); r.className = 'board-robot'; @@ -298,8 +214,49 @@ } } + ///////////////////// + window.addEventListener('load', Board.placeSquares) + var connection = new WebSocket('ws://localhost:8080/ricochet', ['soap', 'xmpp']); + + connection.onopen = Controls.addPlayer; + + connection.onerror = console.error; + + connection.onmessage = function (msg) { + const data = JSON.parse(msg.data) + if (!data.head || !data.body) { + console.warn("Unprocessable entity: ", msg) + return; + } + + console.log(msg) + + switch(data.head.type) { + case 'connect': + break; + + case 'disconnect': + break; + + case 'players': + Controls.updatePlayers(data.body) + break; + + case 'robots': + Board.placeRobots(data.body); + break; + + case 'walls': + Board.placeWalls(data.body); + break; + + default: + console.warn("Unhandled message: ", msg) + } + }; + \ No newline at end of file diff --git a/server.js b/server.js index a1251a3..496c0ec 100644 --- a/server.js +++ b/server.js @@ -8,6 +8,8 @@ const wss = new WebSocket.Server({ port: 8080 }); const DEBUG = true; +const G = new Game(); + // Global, for now. Is there a need for an instance? Ben 052220 const Server = { games: {}, @@ -21,7 +23,7 @@ const Server = { }); }, - messageAll: (ws, message) => { + messageAll: (message) => { DEBUG && console.log("Sending to all " + wss.clients.size + " clients.") wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { @@ -32,7 +34,14 @@ const Server = { onDisconnect: (ws) => { DEBUG && console.log('Disconnected ' + ws.id); + Server.messageOthers(ws, { head: { type: 'disconnect' }, body: { id: ws.id }}) + + + DEBUG && console.log('Removing player: '); + DEBUG && console.log(ws.id); + G.removePlayer(ws.id); + Server.messageOthers({ head: { type: 'players' }, body: G.getPlayers() }); }, onConnect: (ws, req) => { @@ -42,16 +51,35 @@ const Server = { ws.on('message', Server.onMessage.bind(null, ws)); ws.on('close', Server.onDisconnect.bind(null, ws)) - const G = new Game(); - - Server.messageAll(ws, { head: { type: 'connect' }, body: { id: ws.id }}); - Server.messageAll(ws, { head: { type: 'walls' }, body: G.getWalls()}) - Server.messageAll(ws, { head: { type: 'robots' }, body: G.getRobots()}) + Server.messageAll({ head: { type: 'connect' }, body: { id: ws.id }}); + Server.messageAll({ head: { type: 'walls' }, body: G.getWalls()}) + Server.messageAll({ head: { type: 'robots' }, body: G.getRobots()}) }, - onMessage: (ws, message) => { - DEBUG && console.log('Received: %s', message); - // Server.messageAll(ws, message); + onMessage: (ws, json) => { + const message = JSON.parse(json); + + DEBUG && console.log('Received message: '); + DEBUG && console.log(message); + + if (!message.head || !message.body) { + DEBUG && console.warn("Unprocessable message: ") + DEBUG && console.warn(message); + return; + } + + switch (message.head.type) { + case 'addPlayer': + DEBUG && console.log('Adding player: '); + DEBUG && console.log(ws.id); + DEBUG && console.log(message.body); + const santizedName = message.body.replace(/[^\w ]/g, ''); + G.addPlayer(ws.id, santizedName); + Server.messageAll({ head: { type: 'players' }, body: G.getPlayers() }); + break; + default: + console.warn("Unknown message type: ", message.head.type) + } }, }; diff --git a/sprite-robots.png b/sprite-robots.png new file mode 100644 index 0000000..15d90e6 Binary files /dev/null and b/sprite-robots.png differ