Global move emittance.

master
Ben Burlingham 5 years ago
parent 917c9db2ab
commit a1a88ea319
  1. 23
      README.txt
  2. 13
      client/connection.js
  3. 113
      client/content.js
  4. 16
      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`
## TODO
- move websocket server to /core
- robot icons with personality
- dynamic socket server resolution
- namespace server to /ricochet
- cookie room link
- robot GUIDs
- move guess and move logic out of server (clean up server file)
- countdown skip
- 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
- be able to "back up" in a move sequence
- 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 }));
});
document.addEventListener('L-move', (evt) => {
if (evt.detail.emitIf) {
this.ws.send(JSON.stringify({ type: 'move', rawBody: evt.detail }));
}
});
document.addEventListener('L-robots', () => {
this.ws.send(JSON.stringify({ type: 'robots' }));
});
@ -46,7 +52,7 @@ Connection.prototype.connect = function(){
//===== Connection event handlers
Connection.prototype.onOpen = function() {
Connection.prototype.onOpen = function(aaa) {
const evt = new Event('L-conn-open');
document.dispatchEvent(evt);
};
@ -70,10 +76,13 @@ Connection.prototype.onReceiveMessage = function({ data }) {
let eventName;
switch (msg.type) {
case 'guess': eventName = 'G-guess'; break;
case 'connected': eventName = 'G-connected'; break;
case 'guess': eventName = 'G-guess'; break;
case 'move': eventName = 'G-move'; break;
case 'players': eventName = 'G-players'; break;
case 'robots': eventName = 'G-robots'; break;
case 'skip': eventName = 'G-skip'; break;
case 'solve': eventName = 'G-solve'; break;
case 'start': eventName = 'G-start'; break;
case 'stop': eventName = 'G-stop'; break;
case 'walls': eventName = 'G-walls'; break;

@ -9,23 +9,22 @@ const Content = function({ parent, squares }) {
this.listeners = {};
this.initialRobotState = [];
this.playerId = null;
this.isSolving = false;
this.isSolver = false;
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-robots', this.msgRobots.bind(this));
document.addEventListener('G-solve', this.msgSolve.bind(this));
document.addEventListener('G-move', this.msgMove.bind(this));
};
//===== Event handlers
Content.prototype.msgRobots = function(evt) {
this.initialRobotState = evt.detail.body;
this.drawRobots()
}
//===== Event handlers
//===== UI
Content.prototype.drawRobots = function() {
this.robots = {};
@ -127,9 +126,7 @@ Content.prototype.drawSquares = function() {
}
};
Content.prototype.msgWalls = function(msg) {
const edges = msg.detail.body;
Content.prototype.drawWalls = function(edges) {
this.walls = {};
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';
this.updateArrowVisibilities();
var event = new Event('L-move');
document.dispatchEvent(event);
}
};
Content.prototype.updateArrowVisibilities = function() {
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='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 }) {
@ -291,4 +262,66 @@ Content.prototype.findNextObstacle = function({ 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();
};

16
client/controls.js vendored

@ -8,7 +8,7 @@ const Controls = function() {
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));
// Message handlers: "Local message" and "Global message"
@ -38,7 +38,7 @@ Controls.prototype.countdownStart = function(seconds) {
this.timers.countdown = this.countdownTick.bind(this);
const countdown = document.getElementById('controls-countdown');
countdown.dataset.tick = seconds + 1;
countdown.dataset.tick = seconds;
this.countdownTick();
};
@ -46,15 +46,15 @@ Controls.prototype.countdownStart = function(seconds) {
Controls.prototype.countdownTick = function() {
const countdown = document.getElementById('controls-countdown');
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) {
this.countdownComplete();
return;
}
const s = (tick !== 1) ? 's' : '';
countdown.innerHTML = `${tick} second${s}!`;
}
this.timers.countdown = setTimeout(this.countdownTick.bind(this), 1000);
};
@ -126,7 +126,7 @@ Controls.prototype.msgGuess = function(evt) {
this.countdownStart(5);
}
Controls.prototype.msgJoin = function() {
Controls.prototype.msgConnected = function() {
this.showWaiting();
};

@ -67,6 +67,7 @@ const Server = {
Server.messageAll({ type: 'players', body: G.getPlayers() });
Server.messageOne(ws, { type: 'walls', body: G.getWalls()});
Server.messageOne(ws, { type: 'robots', body: G.getRobots()});
Server.messageOne(ws, { type: 'connected', body: ws.id});
},
onMessage: (ws, json) => {
@ -87,7 +88,20 @@ const Server = {
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;
case 'robots':
Server.messageAll({ type: 'robots', body: G.getRobots()});

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

Loading…
Cancel
Save