Arrow-based bounded movement complete.

master
Ben Burlingham 5 years ago
parent 212ff7b227
commit 818d4dcfc8
  1. 336
      client/board.js
  2. 6
      index.css
  3. 16
      server/game.js

@ -13,14 +13,14 @@ Board.prototype.drawRobots = function(robots) {
this.robots = {};
robots.forEach(({ color, i, j }) => {
this.robots[`${i}-${j}`] = true;
const { x, y } = this.squares.ijToXy({ i, j });
const s = this.squares.sideLength;
const id = color.replace('#', '').toUpperCase();
const ij = `${i}-${j}`;
this.robots[ij] = id;
// Get robot from ij: document.querySelector('[data-robot=i-j]')
const robot = document.createElement('div');
robot.id = `robot-${id}`;
robot.className = 'content-robot';
robot.style.background = `radial-gradient(circle at ${s/3}px ${s/3}px, ${color} 10%, #000)`;
robot.style.borderRadius = (s / 2) + 'px';
@ -28,87 +28,64 @@ Board.prototype.drawRobots = function(robots) {
robot.style.width = s + 'px';
robot.style.left = x + 'px';
robot.style.top = y + 'px';
robot.id = id;
robot.dataset.robot = `${i}-${j}`;
const shadow = document.createElement('div');
shadow.className = 'content-shadow';
shadow.style.background = `radial-gradient(circle at ${s/3}px ${s/3}px, ${color} 10%, #000)`;
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.id = `shadow-${id}`;
shadow.dataset.parentRobot = id;
shadow.dataset.currentIJ = `${i}-${j}`;
const up = document.createElement('div');
up.className = 'content-arrow';
up.innerHTML = "▲"
up.style.left = x + 'px';
up.style.top = (y - s) + 'px';
up.style.lineHeight = s + 'px';
up.style.height = s + 'px';
up.style.width = s + 'px';
up.dataset.i = i;
up.dataset.j = j;
up.dataset.direction = 'up';
up.dataset.parentRobot = id;
up.addEventListener('click', this.moveRobot.bind(this));
const down = document.createElement('div');
down.className = 'content-arrow';
down.innerHTML = "▼"
down.style.left = x + 'px';
down.style.top = (y + s) + 'px';
down.style.lineHeight = s + 'px';
down.style.height = s + 'px';
down.style.width = s + 'px';
down.dataset.i = i;
down.dataset.j = j;
down.dataset.direction = 'down';
down.dataset.parentRobot = id;
down.addEventListener('click', this.moveRobot.bind(this));
const left = document.createElement('div');
left.className = 'content-arrow';
left.innerHTML = "◀"
left.style.left = (x - s) + 'px';
left.style.top = y + 'px';
left.style.lineHeight = s + 'px';
left.style.height = s + 'px';
left.style.width = s + 'px';
left.dataset.i = i;
left.dataset.j = j;
left.dataset.direction = 'left';
left.dataset.parentRobot = id;
left.addEventListener('click', this.moveRobot.bind(this));
const right = document.createElement('div');
right.className = 'content-arrow';
right.innerHTML = "▶"
right.style.left = (x + s) + 'px';
right.style.top = y + 'px';
right.style.lineHeight = s + 'px';
right.style.height = s + 'px';
right.style.width = s + 'px';
right.dataset.i = i;
right.dataset.j = j;
right.dataset.direction = 'right';
right.dataset.parentRobot = id;
right.addEventListener('click', this.moveRobot.bind(this));
// this.parent.appendChild(robot);
this.parent.appendChild(shadow);
this.parent.appendChild(up);
this.parent.appendChild(down);
this.parent.appendChild(left);
this.parent.appendChild(right);
// shadow.addEventListener('mousedown', this.onRobotDragStart.bind(this));
robot.dataset.i = i;
robot.dataset.j = j;
// Get robot from ij: document.querySelector('[data-robot=i-j]')
// robot.dataset.robot = ij;
const arrows = document.createElement('div');
arrows.className = 'content-arrows';
arrows.id = `arrows-${id}`;
arrows.style.position = 'absolute';
arrows.style.left = (x - s) + 'px';
arrows.style.top = (y - s) + 'px';
const up = this.drawArrow({
direction: 'up', label: '▲', i, j, left: s, top: 0, parentId: id
});
const down = this.drawArrow({
direction: 'down', label: '▼', i, j, left: s, top: (2 * s), parentId: id
});
const left = this.drawArrow({
direction: 'left', label: '◀', i, j, left: 0, top: s, parentId: id
});
const right = this.drawArrow({
direction: 'right', label: '▶', i, j, left: (2 * s), top: s, parentId: id
});
arrows.appendChild(up);
arrows.appendChild(down);
arrows.appendChild(left);
arrows.appendChild(right);
this.parent.appendChild(robot);
this.parent.appendChild(arrows);
});
this.updateArrowVisibilities();
};
Board.prototype.drawArrow = function({ direction, label, i, j, left, top, parentId }) {
const s = this.squares.sideLength;
const arrow = document.createElement('div');
arrow.className = 'content-arrow';
arrow.innerHTML = label;
arrow.style.left = left + 'px';
arrow.style.top = top + 'px';
arrow.style.lineHeight = s + 'px';
arrow.style.height = s + 'px';
arrow.style.width = s + 'px';
arrow.dataset.direction = direction;
arrow.dataset.parent = parentId;
arrow.addEventListener('click', this.onArrowClick.bind(this));
return arrow;
};
Board.prototype.drawSquares = function() {
@ -163,21 +140,71 @@ Board.prototype.drawWalls = function(edges) {
}
this.parent.appendChild(wall)
})
});
this.updateArrowVisibilities();
};
Board.prototype.moveRobot = function(evt) {
const i = evt.currentTarget.dataset.i * 1;
const j = evt.currentTarget.dataset.j * 1;
Board.prototype.moveRobot = function({ id, i, j }) {
const robot = document.getElementById(`robot-${id}`);
const arrows = document.getElementById(`arrows-${id}`);
const { x, y } = this.squares.ijToXy({ i, j });
const s = this.squares.sideLength;
robot.style.left = x + 'px';
robot.style.top = y + 'px';
robot.dataset.i = i;
robot.dataset.j = j;
this.robots[`${i}-${j}`] = id;
arrows.style.left = (x - s) + 'px';
arrows.style.top = (y - s) + 'px';
this.updateArrowVisibilities();
}
Board.prototype.updateArrowVisibilities = function() {
const keys = Object.keys(this.robots);
keys.forEach(key => {
const id = this.robots[key];
const i = key.split('-')[0] * 1;
const j = key.split('-')[1] * 1;
const arrows = document.getElementById(`arrows-${id}`);
const ijR = `${i + 1}-${j}`;
const ijL = `${i - 1}-${j}`;
const ijU = `${i}-${j - 1}`;
const ijD = `${i}-${j + 1}`;
const edgeR = `${i + 1}-${j}-${i + 1}-${j + 1}`;
const edgeL = `${i}-${j}-${i}-${j + 1}`;
const edgeU = `${i}-${j}-${i + 1}-${j}`;
const edgeD = `${i}-${j + 1}-${i + 1}-${j + 1}`;
arrows.querySelector("[data-direction='right']").style.display = (this.robots[ijR] || this.walls[edgeR] || i === (this.squares.perSide - 1)) ? 'none' : 'block';
arrows.querySelector("[data-direction='left']").style.display = (this.robots[ijL] || this.walls[edgeL] || i === 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';
});
}
Board.prototype.onArrowClick = function(evt) {
const direction = evt.currentTarget.dataset.direction;
const id = evt.currentTarget.dataset.parentRobot;
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 });
const {x, y} = this.squares.ijToXy({ i: i2, j: j2 });
const robot = document.getElementById(`shadow-${id}`);
robot.style.left = x + 'px'
robot.style.top = y + 'px'
this.moveRobot({ id, i: i2, j: j2 })
};
Board.prototype.findNextObstacle = function({ direction, i, j }) {
@ -185,9 +212,9 @@ Board.prototype.findNextObstacle = function({ direction, i, j }) {
case 'right':
for (let ii = i + 1; ii < this.squares.perSide; ii++) {
const edge = `${ii + 1}-${j}-${ii + 1}-${j + 1}`;
const ij = `${ii}-${j}`;
const ij = `${ii + 1}-${j}`;
if (this.robots[ij] || this.walls[edge]) {
if (this.robots[ij] || this.walls[edge] || ii === (this.squares.perSide - 1)) {
return { i: ii, j };
}
}
@ -195,9 +222,9 @@ Board.prototype.findNextObstacle = function({ direction, i, j }) {
case 'left':
for (let ii = i - 1; ii >= 0; ii--) {
const edge = `${ii}-${j}-${ii}-${j + 1}`;
const ij = `${ii}-${j}`;
const ij = `${ii - 1}-${j}`;
if (this.robots[ij] || this.walls[edge]) {
if (this.robots[ij] || this.walls[edge] || ii === 0) {
return { i: ii, j };
}
}
@ -206,9 +233,9 @@ Board.prototype.findNextObstacle = function({ direction, i, j }) {
case 'up':
for (let jj = j - 1; jj >= 0; jj--) {
const edge = `${i}-${jj}-${i + 1}-${jj}`;
const ij = `${i}-${jj}`;
const ij = `${i}-${jj - 1}`;
if (this.robots[ij] || this.walls[edge]) {
if (this.robots[ij] || this.walls[edge] || jj === 0) {
return { i, j: jj };
}
}
@ -217,9 +244,9 @@ Board.prototype.findNextObstacle = function({ direction, i, j }) {
case 'down':
for (let jj = j + 1; jj < this.squares.perSide; jj++) {
const edge = `${i}-${jj + 1}-${i + 1}-${jj + 1}`;
const ij = `${i}-${jj}`;
const ij = `${i}-${jj + 1}`;
if (this.robots[ij] || this.walls[edge]) {
if (this.robots[ij] || this.walls[edge] || jj === (this.squares.perSide - 1)) {
return { i, j: jj };
}
}
@ -228,112 +255,3 @@ Board.prototype.findNextObstacle = function({ direction, i, j }) {
throw Error("Could not find next obstacle, no direction found. ", direction, i, j);
}
// i1 and j1 are the original position.
// i2 and j2 are the requested position.
// Check all the edges crossed between the two to find if it's a valid move.
// Board.prototype.getBlockers = function({ i1, j1, i2, j2 }) {
// if (i1 !== i2 && j1 !== j2) {
// return "diagonal move";
// }
// if (i1 === i2 && j1 == j2) {
// return;
// } else if (i1 === i2 && j1 > j2) {
// // Moving up.
// for (let j = j2; j < j1; j++) {
// const edge = `${i1}-${j + 1}-${i1 + 1}-${j + 1}`;
// const ij = `${i1}-${j}`;
// if (this.robots[ij]) {
// return document.querySelector(`[data-robot='${ij}']`);
// }
// if (this.walls[edge]) {
// return document.querySelector(`[data-wall='${edge}']`);
// }
// }
// } else if (i1 === i2 && j1 < j2) {
// // Moving down.
// for (let j = j1; j < j2; j++) {
// const edge = `${i1}-${j + 1}-${i1 + 1}-${j + 1}`;
// const ij = `${i1}-${j + 1}`;
// if (this.robots[ij]) {
// return document.querySelector(`[data-robot='${ij}']`);
// }
// if (this.walls[edge]) {
// return document.querySelector(`[data-wall='${edge}']`);
// }
// }
// } else if (j1 === j2 && i1 < i2) {
// // Moving right.
// for (let i = i1; i < i2; i++) {
// const edge = `${i + 1}-${j1}-${i + 1}-${j1 + 1}`;
// const ij = `${i + 1}-${j1}`;
// if (this.robots[ij]) {
// return document.querySelector(`[data-robot='${ij}']`);
// }
// if (this.walls[edge]) {
// return document.querySelector(`[data-wall='${edge}']`);
// }
// }
// } else {
// // Moving left.
// for (let i = i2; i < i1; i++) {
// const edge = `${i + 1}-${j1}-${i + 1}-${j1 + 1}`;
// const ij = `${i}-${j1}`;
// if (this.robots[ij]) {
// return document.querySelector(`[data-robot='${ij}']`);
// }
// if (this.walls[edge]) {
// return document.querySelector(`[data-wall='${edge}']`);
// }
// }
// }
// };
// 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 [ i1, j1 ] = dragTarget.dataset.currentIJ.split('-').map(v => v * 1);
// // cost { 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 });
// if (blockage) {
// // console.log(blockage)
// 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(_) {
// document.body.removeEventListener('mouseup', this.listeners.onRobotDragStop);
// document.body.removeEventListener('mousemove', this.listeners.onRobotDrag);
// };

@ -121,12 +121,11 @@ body {
}
.content-robot {
opacity: 0.25;
position: absolute;
transition: left 0.4s cubic-bezier(0,1,.5,1), top 0.4s cubic-bezier(0,1,.5,1);
}
.content-shadow {
position: absolute;
.content-arrows {
transition: left 0.4s cubic-bezier(0,1,.5,1), top 0.4s cubic-bezier(0,1,.5,1);
}
@ -135,6 +134,7 @@ body {
cursor: pointer;
position: absolute;
text-align: center;
user-select: none;
}
.content-arrow:hover {

@ -23,19 +23,21 @@ Game.prototype.getPlayers = function() {
Game.prototype.getRobots = function() {
return [
{i: 4, j: 3, color: '#E00000' },
{i: 4, j: 7, color: '#00C000' },
{i: 1, j: 19, color: '#0000FF' }
{i: 9, j: 9, color: '#E00000' },
{i: 18, j: 9, color: '#00C000' },
{i: 1, j: 9, color: '#0000FF' },
{i: 9, j: 18, color: '#00C0C0' },
{i: 9, j: 1, color: '#F000F0' },
];
}
Game.prototype.getWalls = function() {
// Edge IDs are of the form [i1-j1-i2-j2]. Top left is 0, 0.
return [
"1-3-1-4",
"4-1-5-1",
"4-8-5-8",
"8-3-8-4"
"1-9-1-10",
"9-1-10-1",
"9-19-10-19",
"19-9-19-10"
];
};

Loading…
Cancel
Save