parent
0681a9bc95
commit
97cf2dc632
11 changed files with 449 additions and 350 deletions
@ -0,0 +1,184 @@ |
|||||||
|
const Board = function({ parent, squares }) { |
||||||
|
this.parent = parent; |
||||||
|
this.squares = squares; |
||||||
|
|
||||||
|
this.blockers = {}; |
||||||
|
this.listeners = {}; |
||||||
|
|
||||||
|
this.drawSquares(); |
||||||
|
this.resetBlockers(); |
||||||
|
}; |
||||||
|
|
||||||
|
Board.prototype.resetBlockers = function() { |
||||||
|
this.blockers = { |
||||||
|
negativeI: null, |
||||||
|
negativeJ: null, |
||||||
|
positiveI: null, |
||||||
|
positiveJ: null |
||||||
|
}; |
||||||
|
}; |
||||||
|
|
||||||
|
Board.prototype.drawRobots = function(robots) { |
||||||
|
robots.forEach(({ color, i, j }) => { |
||||||
|
const { x, y } = this.squares.ijToXy({ i, j }); |
||||||
|
const s = this.squares.sideLength; |
||||||
|
const id = color.replace('#', '').toUpperCase(); |
||||||
|
|
||||||
|
const robot = document.createElement('div'); |
||||||
|
robot.className = 'content-robot'; |
||||||
|
robot.style.background = color; |
||||||
|
robot.style.borderRadius = (s / 2) + 'px'; |
||||||
|
robot.style.height = s + 'px'; |
||||||
|
robot.style.width = s + 'px'; |
||||||
|
robot.style.left = x + 'px'; |
||||||
|
robot.style.top = y + 'px'; |
||||||
|
robot.id = id |
||||||
|
|
||||||
|
// Find if a robot is on a square: document.querySelector('[data-robot=i-j]')
|
||||||
|
robot.dataset.robot = `${i}-${j}`; |
||||||
|
|
||||||
|
const shadow = document.createElement('div'); |
||||||
|
shadow.className = 'content-shadow'; |
||||||
|
shadow.style.background = color; |
||||||
|
shadow.style.borderRadius = (s / 2) + 'px'; |
||||||
|
shadow.style.height = s + 'px'; |
||||||
|
shadow.style.width = s + 'px'; |
||||||
|
shadow.style.left = x + 'px'; |
||||||
|
shadow.style.top = y + 'px'; |
||||||
|
shadow.dataset.parentRobot = id; |
||||||
|
|
||||||
|
this.parent.appendChild(robot); |
||||||
|
this.parent.appendChild(shadow); |
||||||
|
|
||||||
|
shadow.addEventListener('mousedown', this.onRobotDragStart.bind(this)); |
||||||
|
}); |
||||||
|
}; |
||||||
|
|
||||||
|
Board.prototype.drawSquares = function() { |
||||||
|
for (let i = 0; i < this.squares.perSide; i++) { |
||||||
|
for (let j = 0; j < this.squares.perSide; j++) { |
||||||
|
// All squares are absolutely positioned relative to the viewport.
|
||||||
|
const { x, y } = this.squares.ijToXy({ i, j }); |
||||||
|
|
||||||
|
const square = document.createElement('div'); |
||||||
|
square.className = 'content-square'; |
||||||
|
square.style.height = this.squares.sideLength + 'px'; |
||||||
|
square.style.width = this.squares.sideLength + 'px'; |
||||||
|
square.style.left = x + 'px'; |
||||||
|
square.style.top = y + 'px'; |
||||||
|
|
||||||
|
this.parent.appendChild(square); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
Board.prototype.drawWalls = function(edges) { |
||||||
|
edges.forEach(edge => { |
||||||
|
const id = `wall-${edge}`; |
||||||
|
|
||||||
|
if (document.getElementById(id)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const [i1, j1, i2, j2] = edge.split('-'); |
||||||
|
|
||||||
|
console.log(edge) |
||||||
|
|
||||||
|
const wall = document.createElement('div'); |
||||||
|
wall.id = id; |
||||||
|
wall.title = edge; |
||||||
|
|
||||||
|
const { x, y } = this.squares.ijToXy({ i: i1, j: j1 }); |
||||||
|
wall.style.left = x + 'px'; |
||||||
|
wall.style.top = y + 'px'; |
||||||
|
|
||||||
|
// Find if edge has a wall: document.querySelector('[data-wall=i1-j1-i2-j2]')
|
||||||
|
wall.dataset.wall = edge; |
||||||
|
|
||||||
|
if (i1 === i2) { |
||||||
|
wall.className = 'content-wall-y'; |
||||||
|
wall.style.height = this.squares.sideLength + 'px'; |
||||||
|
} else { |
||||||
|
wall.className = 'content-wall-x'; |
||||||
|
wall.style.width = this.squares.sideLength + 'px'; |
||||||
|
} |
||||||
|
|
||||||
|
this.parent.appendChild(wall) |
||||||
|
}) |
||||||
|
}; |
||||||
|
|
||||||
|
Board.prototype.getBlockers = function({ i1, j1, i2, j2 }) { |
||||||
|
// const upperEdge = `${i1}-${j1}-${i2}-${j2}`;
|
||||||
|
// const lowerEdge = `${i1}-${j1}-${i2}-${j2}`;
|
||||||
|
|
||||||
|
if (i1 === i2 && j1 < j2) { |
||||||
|
|
||||||
|
|
||||||
|
} else if (i1 === i2 && j1 > j2) { |
||||||
|
|
||||||
|
|
||||||
|
} else if (j1 === j2 && i1 <= i2) { |
||||||
|
this.blockers.positiveI && console.log(this.blockers.positiveI.i, i1) |
||||||
|
|
||||||
|
if (this.blockers.positiveI && this.blockers.positiveI.i <= i1) { |
||||||
|
return this.blockers.positiveI.blockage; |
||||||
|
} |
||||||
|
|
||||||
|
const rightEdge = `${i1 + 1}-${j1}-${i1 + 1}-${j1 + 1}`; |
||||||
|
|
||||||
|
const wall = document.querySelector(`[data-wall='${rightEdge}']`); |
||||||
|
|
||||||
|
if (wall) { |
||||||
|
this.blockers.positiveI = { i: i1 + 1, blockage: wall }; |
||||||
|
return wall; |
||||||
|
} |
||||||
|
} else { |
||||||
|
// const leftEdge = `${i1}-${j1}-${i2}-${j2}`;
|
||||||
|
// console.log("Left edge: ", leftEdge)
|
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
}; |
||||||
|
|
||||||
|
Board.prototype.onRobotDragStart = function(evt) { |
||||||
|
evt.stopPropagation(); |
||||||
|
evt.preventDefault(); |
||||||
|
|
||||||
|
this.listeners.onRobotDragStop = this.onRobotDragStop.bind(this); |
||||||
|
this.listeners.onRobotDrag = this.onRobotDrag.bind(this, evt.currentTarget); |
||||||
|
|
||||||
|
document.body.addEventListener('mouseup', this.listeners.onRobotDragStop); |
||||||
|
document.body.addEventListener('mousemove', this.listeners.onRobotDrag); |
||||||
|
|
||||||
|
const { x, y } = this.squares.ijToXy(this.squares.xyToIj(evt)); |
||||||
|
|
||||||
|
evt.currentTarget.style.left = x + 'px'; |
||||||
|
evt.currentTarget.style.top = y + 'px'; |
||||||
|
}; |
||||||
|
|
||||||
|
Board.prototype.onRobotDrag = function(dragTarget, evt) { |
||||||
|
const { i: i1, j: j1 } = this.squares.xyToIj({ x: evt.x - evt.movementX, y: evt.y - evt.movementY }); |
||||||
|
const { i: i2, j: j2 } = this.squares.xyToIj({ x: evt.x, y: evt.y }); |
||||||
|
|
||||||
|
const blockage = this.getBlockers({ i1, j1, i2, j2 }); |
||||||
|
// console.warn(blockers)
|
||||||
|
|
||||||
|
if (blockage) { |
||||||
|
console.log(blockage) |
||||||
|
console.log("NOPE") |
||||||
|
// this.onRobotDragStop(); works but i don't like it
|
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
const { x, y } = this.squares.ijToXy({ i: i2, j: j2 }); |
||||||
|
|
||||||
|
dragTarget.style.left = x + 'px'; |
||||||
|
dragTarget.style.top = y + 'px'; |
||||||
|
}; |
||||||
|
|
||||||
|
Board.prototype.onRobotDragStop = function(_) { |
||||||
|
this.resetBlockers(); |
||||||
|
|
||||||
|
document.body.removeEventListener('mouseup', this.listeners.onRobotDragStop); |
||||||
|
document.body.removeEventListener('mousemove', this.listeners.onRobotDrag); |
||||||
|
}; |
@ -0,0 +1,53 @@ |
|||||||
|
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);
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
}, |
||||||
|
}; |
@ -0,0 +1,16 @@ |
|||||||
|
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);
|
||||||
|
} |
||||||
|
}; |
@ -0,0 +1,3 @@ |
|||||||
|
const Settings = function() { |
||||||
|
this.squaresPerSide = 20; |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
// This layer acts to convert squares and their edges to pixel coords and back.
|
||||||
|
// i and j are notations for the grid of squares.
|
||||||
|
// x and y are notations for absolute pixels.
|
||||||
|
//
|
||||||
|
// Grid: XY pair. 0-i on x and 0-j on y.
|
||||||
|
// Absolute: XY pair. 0-width and 0-height, relative to viewport
|
||||||
|
// Edge: A string. i1-j1-i1-j2.
|
||||||
|
|
||||||
|
const Squares = function() { |
||||||
|
const controlBounds = document.getElementById('controls-container').getBoundingClientRect(); |
||||||
|
const contentBounds = document.getElementById('content-container').getBoundingClientRect(); |
||||||
|
|
||||||
|
const h = contentBounds.height - 40; |
||||||
|
const w = contentBounds.width - controlBounds.right - 40; |
||||||
|
const min = Math.min(h, w); |
||||||
|
|
||||||
|
// Centering
|
||||||
|
const offsetX = (min === h) ? ((w - min) / 2) : 0; |
||||||
|
const offsetY = (min === h) ? 0 : ((h - min) / 2); |
||||||
|
|
||||||
|
this.perSide = 20; |
||||||
|
this.sideLength = Math.floor(min / this.perSide); |
||||||
|
|
||||||
|
// Origin (top left)
|
||||||
|
this.x0 = controlBounds.left + controlBounds.width + 40 + offsetX; |
||||||
|
this.y0 = contentBounds.top + 40 + offsetY; |
||||||
|
} |
||||||
|
|
||||||
|
Squares.prototype.ijToXy = function({ i, j }) { |
||||||
|
if ((i !== 0 && !i) || (j !== 0 && !j)) { |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
x: this.x0 + i * this.sideLength, |
||||||
|
y: this.y0 + j * this.sideLength |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Squares.prototype.xyToIj = function({ x, y }) { |
||||||
|
const i = Math.floor((x - this.x0) / this.sideLength); |
||||||
|
const j = Math.floor((y - this.y0) / this.sideLength); |
||||||
|
|
||||||
|
const min = 0; |
||||||
|
const max = this.perSide - 1; |
||||||
|
|
||||||
|
// Coalesce outlying results to grid edges.
|
||||||
|
return { |
||||||
|
i: Math.min(Math.max(min, i), max), |
||||||
|
j: Math.min(Math.max(min, j), max), |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
<!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="index.css"> |
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Montserrat&display=swap" rel="stylesheet"> |
||||||
|
<script type='text/javascript' src='client/board.js'></script> |
||||||
|
<script type='text/javascript' src='client/controls.js'></script> |
||||||
|
<script type='text/javascript' src='client/cookie.js'></script> |
||||||
|
<script type='text/javascript' src='client/squares.js'></script> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div id="controls-container"> |
||||||
|
<div class='controls-title'>Puzzle Robots</div> |
||||||
|
|
||||||
|
<div class="controls-room"> |
||||||
|
<div class='controls-subtitle'>Room</div> |
||||||
|
<input type="text" id='game-id'> |
||||||
|
<button type='button'>></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 id="content-container"> |
||||||
|
</div> |
||||||
|
|
||||||
|
<script> |
||||||
|
window.addEventListener('load', () => { |
||||||
|
const squares = new Squares(); |
||||||
|
|
||||||
|
const board = new Board({ parent: document.getElementById('content-container'), squares }); |
||||||
|
|
||||||
|
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.drawRobots(data.body); |
||||||
|
break; |
||||||
|
|
||||||
|
case 'walls': |
||||||
|
board.drawWalls(data.body); |
||||||
|
break; |
||||||
|
|
||||||
|
default: |
||||||
|
console.warn("Unhandled message: ", msg) |
||||||
|
} |
||||||
|
}; |
||||||
|
}) |
||||||
|
</script> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,12 @@ |
|||||||
|
// 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 |
||||||
|
// TODO donate link |
@ -1,301 +0,0 @@ |
|||||||
<!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'>></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> |
|
Loading…
Reference in new issue