Global move emittance.

master
Ben Burlingham 5 years ago
parent 917c9db2ab
commit a1a88ea319
  1. 21
      README.txt
  2. 11
      client/connection.js
  3. 113
      client/content.js
  4. 12
      client/controls.js
  5. 16
      server.js
  6. 19
      server/game.js

@ -3,16 +3,23 @@
- Incoming global messages are broadcast as custom events prefixed with `G` - Incoming global messages are broadcast as custom events prefixed with `G`
## TODO ## TODO
- move websocket server to /core
- robot icons with personality - robot icons with personality
- dynamic socket server resolution - robot GUIDs
- namespace server to /ricochet - move guess and move logic out of server (clean up server file)
- cookie room link - countdown skip
- no cancel from name prompt - no cancel from name prompt
- limit concurrent players, make sure connections are closed
- window resize update board - window resize update board
- donate link
- tutorial
- walls algorigthm - walls algorigthm
- win declare/add/remove - win declare/add/remove
- be able to "back up" in a move sequence
- restore state on join - restore state on join
- limit concurrent players, make sure connections are closed, clean up empty rooms
- cookie room link, add to all messages, namespace them
- move websocket server to /core
- dynamic socket server resolution
- namespace server to /ricochet
- tutorial
- donate link

@ -18,6 +18,12 @@ const Connection = function() {
this.ws.send(JSON.stringify({ type: 'guess', rawBody: evt.detail })); this.ws.send(JSON.stringify({ type: 'guess', rawBody: evt.detail }));
}); });
document.addEventListener('L-move', (evt) => {
if (evt.detail.emitIf) {
this.ws.send(JSON.stringify({ type: 'move', rawBody: evt.detail }));
}
});
document.addEventListener('L-robots', () => { document.addEventListener('L-robots', () => {
this.ws.send(JSON.stringify({ type: 'robots' })); this.ws.send(JSON.stringify({ type: 'robots' }));
}); });
@ -46,7 +52,7 @@ Connection.prototype.connect = function(){
//===== Connection event handlers //===== Connection event handlers
Connection.prototype.onOpen = function() { Connection.prototype.onOpen = function(aaa) {
const evt = new Event('L-conn-open'); const evt = new Event('L-conn-open');
document.dispatchEvent(evt); document.dispatchEvent(evt);
}; };
@ -70,10 +76,13 @@ Connection.prototype.onReceiveMessage = function({ data }) {
let eventName; let eventName;
switch (msg.type) { switch (msg.type) {
case 'connected': eventName = 'G-connected'; break;
case 'guess': eventName = 'G-guess'; break; case 'guess': eventName = 'G-guess'; break;
case 'move': eventName = 'G-move'; break;
case 'players': eventName = 'G-players'; break; case 'players': eventName = 'G-players'; break;
case 'robots': eventName = 'G-robots'; break; case 'robots': eventName = 'G-robots'; break;
case 'skip': eventName = 'G-skip'; break; case 'skip': eventName = 'G-skip'; break;
case 'solve': eventName = 'G-solve'; break;
case 'start': eventName = 'G-start'; break; case 'start': eventName = 'G-start'; break;
case 'stop': eventName = 'G-stop'; break; case 'stop': eventName = 'G-stop'; break;
case 'walls': eventName = 'G-walls'; break; case 'walls': eventName = 'G-walls'; break;

@ -9,23 +9,22 @@ const Content = function({ parent, squares }) {
this.listeners = {}; this.listeners = {};
this.initialRobotState = []; this.initialRobotState = [];
this.playerId = null;
this.isSolving = false;
this.isSolver = false;
this.drawSquares(); this.drawSquares();
document.addEventListener('L-reset', this.onReset.bind(this)); document.addEventListener('L-reset', this.msgReset.bind(this));
document.addEventListener('G-connected', this.msgConnected.bind(this));
document.addEventListener('G-walls', this.msgWalls.bind(this)); document.addEventListener('G-walls', this.msgWalls.bind(this));
document.addEventListener('G-robots', this.msgRobots.bind(this)); document.addEventListener('G-robots', this.msgRobots.bind(this));
document.addEventListener('G-solve', this.msgSolve.bind(this));
document.addEventListener('G-move', this.msgMove.bind(this));
}; };
//===== Event handlers //===== UI
Content.prototype.msgRobots = function(evt) {
this.initialRobotState = evt.detail.body;
this.drawRobots()
}
//===== Event handlers
Content.prototype.drawRobots = function() { Content.prototype.drawRobots = function() {
this.robots = {}; this.robots = {};
@ -127,9 +126,7 @@ Content.prototype.drawSquares = function() {
} }
}; };
Content.prototype.msgWalls = function(msg) { Content.prototype.drawWalls = function(edges) {
const edges = msg.detail.body;
this.walls = {}; this.walls = {};
this.parent.querySelectorAll('.content-wall-x').forEach(el => el.parentNode.removeChild(el)); this.parent.querySelectorAll('.content-wall-x').forEach(el => el.parentNode.removeChild(el));
@ -189,10 +186,7 @@ Content.prototype.moveRobot = function({ id, i, j }) {
arrows.style.top = (y - s) + 'px'; arrows.style.top = (y - s) + 'px';
this.updateArrowVisibilities(); this.updateArrowVisibilities();
};
var event = new Event('L-move');
document.dispatchEvent(event);
}
Content.prototype.updateArrowVisibilities = function() { Content.prototype.updateArrowVisibilities = function() {
const keys = Object.keys(this.robots); const keys = Object.keys(this.robots);
@ -219,29 +213,6 @@ Content.prototype.updateArrowVisibilities = function() {
arrows.querySelector("[data-direction='up']").style.display = (this.robots[ijU] || this.walls[edgeU] || j === 0) ? 'none' : 'block'; arrows.querySelector("[data-direction='up']").style.display = (this.robots[ijU] || this.walls[edgeU] || j === 0) ? 'none' : 'block';
arrows.querySelector("[data-direction='down']").style.display = (this.robots[ijD] || this.walls[edgeD] || j === (this.squares.perSide - 1)) ? 'none' : 'block'; arrows.querySelector("[data-direction='down']").style.display = (this.robots[ijD] || this.walls[edgeD] || j === (this.squares.perSide - 1)) ? 'none' : 'block';
}); });
}
Content.prototype.onArrowClick = function(evt) {
const direction = evt.currentTarget.dataset.direction;
const id = evt.currentTarget.dataset.parent;
const robot = document.getElementById(`robot-${id}`);
const i = robot.dataset.i * 1;
const j = robot.dataset.j * 1;
delete this.robots[`${i}-${j}`];
const { i: i2, j: j2 } = this.findNextObstacle({ direction, i, j });
this.moveRobot({ id, i: i2, j: j2 })
};
Content.prototype.onReceiveGuess = function() {
console.log("Board onReceiveGuess()")
}
Content.prototype.onReset = function() {
this.drawRobots();
}; };
Content.prototype.findNextObstacle = function({ direction, i, j }) { Content.prototype.findNextObstacle = function({ direction, i, j }) {
@ -291,4 +262,66 @@ Content.prototype.findNextObstacle = function({ direction, i, j }) {
} }
throw Error("Could not find next obstacle, no direction found. ", direction, i, j); throw Error("Could not find next obstacle, no direction found. ", direction, i, j);
};
//===== Click handlers
Content.prototype.onArrowClick = function(evt) {
const direction = evt.currentTarget.dataset.direction;
const id = evt.currentTarget.dataset.parent;
const robot = document.getElementById(`robot-${id}`);
const i = robot.dataset.i * 1;
const j = robot.dataset.j * 1;
delete this.robots[`${i}-${j}`];
const { i: i2, j: j2 } = this.findNextObstacle({ direction, i, j });
this.moveRobot({ id, i: i2, j: j2 });
const detail = { id, i: i2, j: j2, emitIf: this.isSolving };
const evtMove = new CustomEvent('L-move', { detail });
document.dispatchEvent(evtMove);
};
//===== Message handlers
Content.prototype.msgRobots = function(evt) {
this.initialRobotState = evt.detail.body;
this.drawRobots()
};
Content.prototype.msgWalls = function(evt) {
this.drawWalls(evt.detail.body);
};
Content.prototype.msgMove = function(evt) {
const { id, i, j } = evt.detail.body;
this.moveRobot({ id, i, j });
};
Content.prototype.msgSolve = function(evt) {
this.isSolving = true;
this.isSolver = (this.playerId === evt.detail.id);
if (this.isSolver) {
console.error("The current player is attempting a solve.");
} else {
console.error("A different player is attempting a solve.");
//...modal.
}
};
Content.prototype.msgJoin = function(evt) {
};
Content.prototype.msgConnected = function(evt) {
this.playerId = evt.detail.body;
} }
Content.prototype.msgReset = function() {
this.drawRobots();
};

12
client/controls.js vendored

@ -8,7 +8,7 @@ const Controls = function() {
this.drawGuesses(); this.drawGuesses();
document.addEventListener('L-conn-open', this.msgJoin.bind(this)); document.addEventListener('L-connected', this.msgConnected.bind(this));
document.addEventListener('L-move', this.msgMove.bind(this)); document.addEventListener('L-move', this.msgMove.bind(this));
// Message handlers: "Local message" and "Global message" // Message handlers: "Local message" and "Global message"
@ -38,7 +38,7 @@ Controls.prototype.countdownStart = function(seconds) {
this.timers.countdown = this.countdownTick.bind(this); this.timers.countdown = this.countdownTick.bind(this);
const countdown = document.getElementById('controls-countdown'); const countdown = document.getElementById('controls-countdown');
countdown.dataset.tick = seconds + 1; countdown.dataset.tick = seconds;
this.countdownTick(); this.countdownTick();
}; };
@ -48,14 +48,14 @@ Controls.prototype.countdownTick = function() {
const tick = countdown.dataset.tick * 1; const tick = countdown.dataset.tick * 1;
countdown.dataset.tick = tick - 1; countdown.dataset.tick = tick - 1;
const s = (tick !== 1) ? 's' : '';
countdown.innerHTML = `${tick} second${s}!`;
if (tick === 0) { if (tick === 0) {
this.countdownComplete(); this.countdownComplete();
return; return;
} }
const s = (tick !== 1) ? 's' : '';
countdown.innerHTML = `${tick} second${s}!`;
this.timers.countdown = setTimeout(this.countdownTick.bind(this), 1000); this.timers.countdown = setTimeout(this.countdownTick.bind(this), 1000);
}; };
@ -126,7 +126,7 @@ Controls.prototype.msgGuess = function(evt) {
this.countdownStart(5); this.countdownStart(5);
} }
Controls.prototype.msgJoin = function() { Controls.prototype.msgConnected = function() {
this.showWaiting(); this.showWaiting();
}; };

@ -67,6 +67,7 @@ const Server = {
Server.messageAll({ type: 'players', body: G.getPlayers() }); Server.messageAll({ type: 'players', body: G.getPlayers() });
Server.messageOne(ws, { type: 'walls', body: G.getWalls()}); Server.messageOne(ws, { type: 'walls', body: G.getWalls()});
Server.messageOne(ws, { type: 'robots', body: G.getRobots()}); Server.messageOne(ws, { type: 'robots', body: G.getRobots()});
Server.messageOne(ws, { type: 'connected', body: ws.id});
}, },
onMessage: (ws, json) => { onMessage: (ws, json) => {
@ -87,7 +88,20 @@ const Server = {
santizedGuess && Server.messageAll({ type: 'guess', guess: santizedGuess, id: ws.id }); santizedGuess && Server.messageAll({ type: 'guess', guess: santizedGuess, id: ws.id });
G.onGuess(santizedGuess).then(Server.messageAll.bind(null, { type: 'attempt', id: ws.id })); G.onGuess(santizedGuess).then(Server.messageAll.bind(null, { type: 'solve', id: ws.id }));
break;
case 'move':
const sanitizedRobotId = message.rawBody.id.replace(/[^0-9a-zA-Z]/g, '');
const sanitizedI = message.rawBody.i * 1;
const sanitizedJ = message.rawBody.j * 1;
const body = {
i: sanitizedI,
j: sanitizedJ,
id: sanitizedRobotId
};
Server.messageOthers(ws, { type: 'move', body });
break; break;
case 'robots': case 'robots':
Server.messageAll({ type: 'robots', body: G.getRobots()}); Server.messageAll({ type: 'robots', body: G.getRobots()});

@ -5,7 +5,7 @@ const players = {};
const Game = function() { const Game = function() {
this.id = uuid.v4(); this.id = uuid.v4();
this.countdownTimer = null; this.countdownTimer = null;
this.winningGuess = Infinity; this.guess = Infinity;
} }
Game.prototype.addPlayer = function(id, name) { Game.prototype.addPlayer = function(id, name) {
@ -99,14 +99,25 @@ Game.prototype.getWalls = function() {
Game.prototype.onGuess = function(guess) { Game.prototype.onGuess = function(guess) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (guess < 1 || guess >= this.guess) { const timeIsUp = () => {
reject(); this.guess = Infinity;
resolve();
};
if (guess < 1) {
reject(`${guess} is less than 1.`);
return;
}
if (guess >= this.guess) {
reject(`${guess} is greater than ${this.guess}.`);
return;
} }
this.guess = guess; this.guess = guess;
clearTimeout(this.countdownTimer); clearTimeout(this.countdownTimer);
this.countdownTimer = setTimeout(resolve, 5 * 1000); this.countdownTimer = setTimeout(timeIsUp, 5 * 1000);
}); });
}; };

Loading…
Cancel
Save