You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

301 lines
10 KiB

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="ricochet.css">
<link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet">
</head>
<body>
<div class="controls-container">
<div class='controls-title'>Puzzle Robots</div>
<div class="controls-room">
<span>Room ID</span>
<input type="text" id='game-id'>
<button type='button'>&gt;</button>
</div>
<!-- <div class="rounds">
<button type='button' id='game-start'>Start New Round</button>
<div class="timer">0:42</div>
</div> -->
<div id="controls-players">
<div class='controls-subtitle'>Players</div>
</div>
<div id="controls-guesses">
<div class='controls-subtitle'>Guess</div>
</div>
</div>
<div class="board-container">
<div id="board-squares"></div>
</div>
<script>
// TODO dynamic sizing of squares based on available height
// TODO dynamic move population
// TODO move websocket server to /core
// TODO dynamic socket server resolution
// TODO namespace server to /ricochet
// TODO [soap, xmpp]
// TODO a message must have a head and a body
// TODO your favorite games
// TODO no cancel from name prompt
// TODO limit concurrent players
// TODO window resize update board
const Cookie = {
getCookie: function(name) {
var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)');
return v ? decodeURI(v[2]) : null;
},
setCookie: function(name, value, days) {
var d = new Date;
d.setTime(d.getTime() + 24*60*60*1000*days);
document.cookie = name + "=" + encodeURI(value) + ";path=/;expires=" + d.toGMTString();
},
deleteCookie: function(name) {
Util.setCookie(name, '', -1);
}
};
const Controls = {
guessBuild: () => {
const container = document.getElementById('controls-guesses');
container.querySelectorAll('.controls-guess').forEach(el => el.parentNode.removeChild(el));
for (let i = 1; i <= 30; i++) {
const guess = document.createElement('div');
guess.className = 'controls-guess';
guess.innerHTML = i;
guess.setAttribute('data-value', i);
guess.addEventListener('click', Controls.guessClick)
container.appendChild(guess);
}
},
guessClick: (evt) => {
alert(evt.currentTarget.dataset.value)
},
playerAdd: () => {
const rawInput = prompt("What is your name?");
connection.send(JSON.stringify({ head: { type: 'playerAdd' }, body: rawInput }))
},
playerRemove: (rawInput) => {
connection.send(JSON.stringify({ head: { type: 'playerRemove' }, body: rawInput }))
},
playersUpdate: (names) => {
const container = document.getElementById('controls-players');
console.log(names)
Object.keys(names).forEach(connectionId => {
const id = `player-${connectionId}`;
if (document.getElementById(id)) {
return;
}
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);
// }
// })
},
};
const Robot = function([color, x, y]) {
this.color = color;
const el = document.createElement('div');
el.className = 'board-robot';
el.style.background = color;
el.style.left = 40 * x + 'px';
el.style.top = 40 * y + 'px';
el.addEventListener('mousedown', this.onMouseDown.bind(this));
this.shadow = document.createElement('div');
this.shadow.className = 'board-robot-shadow';
this.shadow.style.display = 'none';
Board.el.appendChild(el);
Board.el.appendChild(this.shadow);
};
Robot.prototype.onMouseDown = function(evt) {
document.body.addEventListener('mouseup', this.onMouseUp.bind(this));
document.body.addEventListener('mousemove', this.onDrag.bind(this));
this.shadow.style.display = 'block';
this.shadow.style.left = (this.snapX(evt.pageX) + 2) + 'px';
this.shadow.style.top = (this.snapY(evt.pageY) + 2) + 'px';
};
Robot.prototype.onDrag = function(evt) {
// this.shadow.style.left = (evt.pageX - Board.bounds.left - 18) + 'px';
// this.shadow.style.top = (evt.pageY - Board.bounds.top - 18) + 'px';
this.shadow.style.left = (this.snapX(evt.pageX) + 2) + 'px';
this.shadow.style.top = (this.snapY(evt.pageY) + 2) + 'px';
};
Robot.prototype.onMouseUp = function(evt) {
console.log('mouseup')
this.shadow.style.display = 'none';
document.removeEventListener('mouseup', this.onMouseUp);
document.removeEventListener('mousemove', this.onDrag);
};
Robot.prototype.snapX = (x) => {
const relativeX = Math.floor((x - Board.bounds.left) / Board.squareSize) * Board.squareSize;
const maxX = Board.squareSize * (Board.squaresPerSide - 1);
return Math.min(Math.max(0, relativeX), maxX);
};
Robot.prototype.snapY = (y) => {
const relativeY = Math.floor((y - Board.bounds.top) / Board.squareSize) * Board.squareSize;
const maxY = Board.squareSize * (Board.squaresPerSide - 1);
return Math.min(Math.max(0, relativeY), maxY);
};
const Board = {
bounds: document.getElementById('board-squares').getBoundingClientRect(),
el: document.getElementById('board-squares'),
squaresPerSide: 20,
squareSize: 40,
placeSquares: () => {
Board.el.style.width = (Board.squaresPerSide * Board.squareSize + 1) + 'px';
Board.el.style.height = (Board.squaresPerSide * Board.squareSize + 1) + 'px';
while (Board.el.hasChildElements) {
Board.el.removeChild(board.firstChild);
}
for (let i = 0; i < Board.squaresPerSide; i++) {
for (let j = 0; j < Board.squaresPerSide; j++) {
const square = document.createElement('div');
square.className = 'board-square';
Board.el.appendChild(square);
}
}
},
placeRobots: (robots) => {
robots.forEach(r => new Robot(r))
},
placeWall: (id, className, x, y) => {
if (document.getElementById(id)) {
return;
}
const w = document.createElement('wall');
w.id = id;
w.style.top = x + 'px';
w.style.left = y + 'px';
w.className = className;
Board.el.appendChild(w);
},
placeWalls: (walls) => {
walls.forEach(wall => {
const [x, y, north, south, east, west] = wall;
const pxX = 40 * x;
const pxY = 40 * y;
if (north) {
Board.placeWall(`${x}-${y}-n`, "board-wall-y", pxX, pxY);
}
if (south) {
Board.placeWall(`${x}-${y}-s`, "board-wall-y", pxX, pxY + Board.squareSize);
}
if (east) {
Board.placeWall(`${x}-${y}-e`, "board-wall-x", pxX, pxY);
}
if (west) {
Board.placeWall(`${x}-${y}-e`, "board-wall-x", pxX + Board.squareSize, pxY);
}
})
},
removeWalls: () => {
const walls = document.querySelector('board-wall-x').concat(document.querySelectorAll('board-wall-y'))
}
}
/////////////////////
window.addEventListener('load', () => {
Controls.guessBuild();
Board.placeSquares();
})
var connection = new WebSocket('ws://localhost:8080/ricochet', ['soap', 'xmpp']);
connection.onopen = Controls.playerAdd;
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.playersUpdate(data.body)
break;
case 'robots':
Board.placeRobots(data.body);
break;
case 'walls':
Board.placeWalls(data.body);
break;
default:
console.warn("Unhandled message: ", msg)
}
};
</script>
</body>
</html>