Messaging taxonomy update.

master
Ben Burlingham 5 years ago
parent 94130bd067
commit 917c9db2ab
  1. 18
      README.txt
  2. 2
      client/connection.js
  3. 42
      client/content.js
  4. 37
      client/controls.js
  5. 2
      index.html
  6. 13
      notes.txt
  7. 3
      server.js
  8. 15
      server/game.js

@ -0,0 +1,18 @@
## Architecture:
- Local events are broadcast as custom events prefixed `L-`
- Incoming global messages are broadcast as custom events prefixed with `G`
## TODO
- move websocket server to /core
- robot icons with personality
- dynamic socket server resolution
- namespace server to /ricochet
- cookie room link
- no cancel from name prompt
- limit concurrent players, make sure connections are closed
- window resize update board
- donate link
- tutorial
- walls algorigthm
- win declare/add/remove
- restore state on join

@ -60,7 +60,7 @@ Connection.prototype.onError = function(err) {
Connection.prototype.onReceiveMessage = function({ data }) { Connection.prototype.onReceiveMessage = function({ data }) {
const msg = JSON.parse(data); const msg = JSON.parse(data);
console.warn(msg); console.warn(JSON.stringify(msg));
if (!msg.type) { if (!msg.type) {
console.warn("Unprocessable message: ", msg) console.warn("Unprocessable message: ", msg)

@ -9,29 +9,31 @@ const Content = function({ parent, squares }) {
this.listeners = {}; this.listeners = {};
this.initialRobotState = []; this.initialRobotState = [];
// this.drawSquares(); this.drawSquares();
// document.addEventListener('L-conn-open', this.msgStartGame.bind(this));
// document.addEventListener('G-walls', this.msgStart.bind(this)); document.addEventListener('L-reset', this.onReset.bind(this));
// document.addEventListener('G-robots', this.msgStart.bind(this));
// document.addEventListener('board-reset', this.onReset.bind(this)); document.addEventListener('G-walls', this.msgWalls.bind(this));
// from connection: board.drawRobots(data.body); document.addEventListener('G-robots', this.msgRobots.bind(this));
// from connection: board.drawWalls(data.body);
// from connection: board.onReceiveGuess(data.body);
}; };
//===== Event handlers //===== Event handlers
Content.prototype.msgRobots = function(evt) {
this.initialRobotState = evt.detail.body;
this.drawRobots()
}
//===== Event handlers //===== Event handlers
Content.prototype.drawRobots = function(robots) { Content.prototype.drawRobots = function() {
this.initialRobotState = robots;
this.robots = {}; this.robots = {};
this.parent.querySelectorAll('.content-robot').forEach(el => el.parentNode.removeChild(el)); this.parent.querySelectorAll('.content-robot').forEach(el => el.parentNode.removeChild(el));
this.parent.querySelectorAll('.content-arrows').forEach(el => el.parentNode.removeChild(el)); this.parent.querySelectorAll('.content-arrows').forEach(el => el.parentNode.removeChild(el));
robots.forEach(({ color, i, j }) => { this.initialRobotState.forEach(({ color, i, j }) => {
const { x, y } = this.squares.ijToXy({ i, j }); const { x, y } = this.squares.ijToXy({ i, j });
const s = this.squares.sideLength; const s = this.squares.sideLength;
const id = color.replace('#', '').toUpperCase(); const id = color.replace('#', '').toUpperCase();
@ -61,19 +63,19 @@ Content.prototype.drawRobots = function(robots) {
arrows.style.top = (y - s) + 'px'; arrows.style.top = (y - s) + 'px';
const up = this.drawArrow({ const up = this.drawArrow({
direction: 'up', label: '▲', i, j, left: s, top: 0, parentId: id direction: 'up', label: '▲', i, j, left: (s * 1.25), top: (s * 0.5), parentId: id
}); });
const down = this.drawArrow({ const down = this.drawArrow({
direction: 'down', label: '▼', i, j, left: s, top: (2 * s), parentId: id direction: 'down', label: '▼', i, j, left: (s * 1.25), top: (s * 2), parentId: id
}); });
const left = this.drawArrow({ const left = this.drawArrow({
direction: 'left', label: '◀', i, j, left: 0, top: s, parentId: id direction: 'left', label: '◀', i, j, left: (s * 0.5), top: (s * 1.25), parentId: id
}); });
const right = this.drawArrow({ const right = this.drawArrow({
direction: 'right', label: '▶', i, j, left: (2 * s), top: s, parentId: id direction: 'right', label: '▶', i, j, left: (s * 2), top: (s * 1.25), parentId: id
}); });
arrows.appendChild(up); arrows.appendChild(up);
@ -89,7 +91,7 @@ Content.prototype.drawRobots = function(robots) {
}; };
Content.prototype.drawArrow = function({ direction, label, i, j, left, top, parentId }) { Content.prototype.drawArrow = function({ direction, label, i, j, left, top, parentId }) {
const s = this.squares.sideLength; const s = this.squares.sideLength / 2;
const arrow = document.createElement('div'); const arrow = document.createElement('div');
arrow.className = 'content-arrow'; arrow.className = 'content-arrow';
@ -125,7 +127,9 @@ Content.prototype.drawSquares = function() {
} }
}; };
Content.prototype.drawWalls = function(edges) { Content.prototype.msgWalls = function(msg) {
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));
@ -186,7 +190,7 @@ Content.prototype.moveRobot = function({ id, i, j }) {
this.updateArrowVisibilities(); this.updateArrowVisibilities();
var event = new Event('move-increment'); var event = new Event('L-move');
document.dispatchEvent(event); document.dispatchEvent(event);
} }
@ -237,7 +241,7 @@ Content.prototype.onReceiveGuess = function() {
} }
Content.prototype.onReset = function() { Content.prototype.onReset = function() {
this.drawRobots(this.initialRobotState); this.drawRobots();
}; };
Content.prototype.findNextObstacle = function({ direction, i, j }) { Content.prototype.findNextObstacle = function({ direction, i, j }) {

37
client/controls.js vendored

@ -3,6 +3,8 @@
const Controls = function() { const Controls = function() {
this.moves = 0; this.moves = 0;
this.names = {}; this.names = {};
this.timers = {};
this.currentWinningGuess = Infinity;
this.drawGuesses(); this.drawGuesses();
@ -12,6 +14,7 @@ const Controls = function() {
// Message handlers: "Local message" and "Global message" // Message handlers: "Local message" and "Global message"
// document.addEventListener('G-move', this.msgMove.bind(this)); // document.addEventListener('G-move', this.msgMove.bind(this));
// document.addEventListener('G-win', this.msgWin.bind(this)); // document.addEventListener('G-win', this.msgWin.bind(this));
document.addEventListener('G-attempt', this.msgAttempt.bind(this));
document.addEventListener('G-guess', this.msgGuess.bind(this)); document.addEventListener('G-guess', this.msgGuess.bind(this));
document.addEventListener('G-skip', this.msgSkip.bind(this)); document.addEventListener('G-skip', this.msgSkip.bind(this));
document.addEventListener('G-start', this.msgStart.bind(this)); document.addEventListener('G-start', this.msgStart.bind(this));
@ -31,10 +34,13 @@ const Controls = function() {
//===== UI //===== UI
Controls.prototype.countdownStart = function(seconds) { Controls.prototype.countdownStart = function(seconds) {
clearTimeout(this.timers.countdown);
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 + 1;
setTimeout(this.countdownTick.bind(this), 1000); this.countdownTick();
}; };
Controls.prototype.countdownTick = function() { Controls.prototype.countdownTick = function() {
@ -49,12 +55,13 @@ Controls.prototype.countdownTick = function() {
const s = (tick !== 1) ? 's' : ''; const s = (tick !== 1) ? 's' : '';
countdown.innerHTML = `${tick} second${s}!`; countdown.innerHTML = `${tick} second${s}!`;
setTimeout(this.countdownTick.bind(this), 1000);
this.timers.countdown = setTimeout(this.countdownTick.bind(this), 1000);
}; };
Controls.prototype.countdownComplete = function() { Controls.prototype.countdownComplete = function() {
alert("boom") document.getElementById('controls-countdown').dataset.tick = 0;
}; } ;
Controls.prototype.drawGuesses = function() { Controls.prototype.drawGuesses = function() {
const container = document.getElementById('controls-guesses'); const container = document.getElementById('controls-guesses');
@ -99,6 +106,10 @@ Controls.prototype.showPanic = function() {
//===== Message handlers //===== Message handlers
Controls.prototype.msgAttempt = function() {
alert("Ready for winning attempt!");
};
Controls.prototype.msgGuess = function(evt) { Controls.prototype.msgGuess = function(evt) {
const blurbs = [ " has a solution: ", " can do it in ", " says, maybe ", " wagers ", const blurbs = [ " has a solution: ", " can do it in ", " says, maybe ", " wagers ",
" reckons ", " is pretty sure it's ", ", confidently: ", " wants it to be ", " reckons ", " is pretty sure it's ", ", confidently: ", " wants it to be ",
@ -108,9 +119,11 @@ Controls.prototype.msgGuess = function(evt) {
const msg = evt.detail; const msg = evt.detail;
const guess = msg.guess; const guess = msg.guess;
this.currentWinningGuess = guess;
document.getElementById('controls-panic').querySelector('.controls-alert-urgent').innerHTML = (`${this.names[msg.id]}${blurb}${guess} moves.`); document.getElementById('controls-panic').querySelector('.controls-alert-urgent').innerHTML = (`${this.names[msg.id]}${blurb}${guess} moves.`);
this.showPanic(); this.showPanic();
this.countdownStart(30); this.countdownStart(5);
} }
Controls.prototype.msgJoin = function() { Controls.prototype.msgJoin = function() {
@ -176,7 +189,17 @@ Controls.prototype.dispatch = function(evt, data) {
} }
Controls.prototype.onClickGuess = function(evt) { Controls.prototype.onClickGuess = function(evt) {
this.dispatch('L-guess', { moves: evt.currentTarget.dataset.value }); const guess = evt.currentTarget.dataset.value * 1;
if (!guess || guess < 1) {
return;
}
if (guess < this.currentWinningGuess) {
this.dispatch('L-guess', { moves: evt.currentTarget.dataset.value });
} else {
alert(`That doesn't beat ${this.currentWinningGuess} - try again!`)
}
} }
Controls.prototype.onClickRobots = function() { Controls.prototype.onClickRobots = function() {

@ -75,7 +75,7 @@
<div class='controls-subtitle'>Local</div> <div class='controls-subtitle'>Local</div>
<div class="controls-row"> <div class="controls-row">
<div>Moves:</div> <div>Moves:</div>
<div id="controls-moves">-</div> <div id="controls-moves">0</div>
<div class='controls-button' id='controls-reset'>Reset</div> <div class='controls-button' id='controls-reset'>Reset</div>
</div> </div>

@ -1,13 +0,0 @@
// TODO move websocket server to /core
// TODO dynamic socket server resolution
// TODO namespace server to /ricochet
// TODO cookie room link
// TODO no cancel from name prompt
// TODO limit concurrent players, make sure connections are closed
// TODO window resize update board
// TODO donate link
// TODO tutorial
// TODO walls algorigthm
// TODO fix overlapping robot arrows
// TODO win declare/add/remove
// TODO restore state on join

@ -84,7 +84,10 @@ const Server = {
switch (message.type) { switch (message.type) {
case 'guess': case 'guess':
const santizedGuess = message.rawBody.moves * 1; const santizedGuess = message.rawBody.moves * 1;
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 }));
break; break;
case 'robots': case 'robots':
Server.messageAll({ type: 'robots', body: G.getRobots()}); Server.messageAll({ type: 'robots', body: G.getRobots()});

@ -4,6 +4,8 @@ const players = {};
const Game = function() { const Game = function() {
this.id = uuid.v4(); this.id = uuid.v4();
this.countdownTimer = null;
this.winningGuess = Infinity;
} }
Game.prototype.addPlayer = function(id, name) { Game.prototype.addPlayer = function(id, name) {
@ -95,4 +97,17 @@ Game.prototype.getWalls = function() {
return edges; return edges;
}; };
Game.prototype.onGuess = function(guess) {
return new Promise((resolve, reject) => {
if (guess < 1 || guess >= this.guess) {
reject();
}
this.guess = guess;
clearTimeout(this.countdownTimer);
this.countdownTimer = setTimeout(resolve, 5 * 1000);
});
};
module.exports = Game; module.exports = Game;
Loading…
Cancel
Save