Skip to content

Instantly share code, notes, and snippets.

@noonat
Last active March 18, 2016 02:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save noonat/37f8b846542e80b7edce to your computer and use it in GitHub Desktop.
Save noonat/37f8b846542e80b7edce to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<style type="text/css">
body {
margin: 0;
padding: 0;
}
canvas {
width: 640px;
height: 640px;
position: absolute;
top: 0;
left: 0;
}
</style>
</head>
<body>
<canvas></canvas>
<script>
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
canvas.setAttribute('width', 640);
canvas.setAttribute('height', 640);
var context = canvas.getContext('2d');
var map = [
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,
1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,
1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
];
var mapBlocks = [];
var mapBlockWidth = 32;
var mapBlockHeight = 32;
var mapCols = 18;
var mapRows = 18;
var mapX = mapBlockWidth;
var mapY = mapBlockHeight;
var width = +canvas.getAttribute('width');
var height = +canvas.getAttribute('height');
function State(startX, startY, endX, endY) {
this.startX = startX;
this.startY = startY;
this.endX = endX;
this.endY = endY;
this.deltaX = this.endX - this.startX;
this.deltaY = this.endY - this.startY;
this.stepCol = this.deltaX < 0 ? -1 : 1;
this.stepRow = this.deltaY < 0 ? -1 : 1;
// Figure out which column and row the line starts in.
this.col = Math.floor((this.startX - mapX) / mapBlockWidth);
this.row = Math.floor((this.startY - mapY) / mapBlockHeight);
// Figure out how much we need to step (in terms of time, or percentage
// along the line from start to end) to move from one column/row to the next.
this.timeStepCol = (mapBlockWidth * this.stepCol) / this.deltaX;
this.timeStepRow = (mapBlockHeight * this.stepRow) / this.deltaY;
// Figure out how far along the line (in time) we can move before we need to
// move into the next column and row.
if (this.deltaX === 0) {
this.nextColTime = 1;
} else {
var colEdge = mapX + (this.col * mapBlockWidth);
if (this.stepCol > 0) {
// Moving left to right, so put the edge on the right of the cell
colEdge += mapBlockWidth;
}
this.nextColTime = (colEdge - this.startX) / this.deltaX;
}
if (this.deltaY === 0) {
this.nextRowTime = 1;
} else {
var rowEdge = mapY + (this.row * mapBlockHeight);
if (this.stepRow > 0) {
// Moving top to bottom, so put the edge on the bottom of the cell
rowEdge += mapBlockHeight;
}
this.nextRowTime = (rowEdge - this.startY) / this.deltaY;
}
this.stack = [];
this.stackKeys = ['col', 'row', 'nextColTime', 'nextRowTime']
}
// Restore a saved state.
State.prototype.popState = function() {
var state = this.stack.pop();
if (state) {
this.stackKeys.forEach(function(key) {
this[key] = state[key];
}.bind(this));
}
draw();
};
// Save the current state so we can rewind the algorithm later, if we want to.
State.prototype.pushState = function() {
var state = {};
this.stackKeys.forEach(function(key) {
state[key] = this[key];
}.bind(this));
this.stack.push(state);
};
State.prototype.stepBackward = function() {
this.popState();
draw();
};
State.prototype.stepForward = function() {
this.pushState();
if (this.nextColTime < 1 || this.nextRowTime < 1) {
if (this.nextColTime < this.nextRowTime) {
this.col += this.stepCol;
this.nextColTime += this.timeStepCol;
} else {
this.row += this.stepRow;
this.nextRowTime += this.timeStepRow;
}
}
};
var state = new State(188, 162, 464, 262);
function init() {
for (var row = 0; row < mapRows; row++) {
var y = mapY + row * mapBlockHeight;
for (var col = 0; col < mapCols; col++) {
var x = mapX + col * mapBlockWidth;
var i = row * mapCols + col;
mapBlocks.push({
x: x,
y: y,
width: mapBlockWidth,
height: mapBlockHeight,
solid: Boolean(map[i])
});
}
}
}
function draw() {
context.fillStyle = '#000';
context.fillRect(0, 0, width, height);
context.fillStyle = '#666';
context.lineWidth = 0.5;
context.strokeStyle = '#999';
mapBlocks.forEach(function(block) {
context.beginPath();
context.rect(block.x, block.y, block.width, block.height);
context.closePath();
if (block.solid) {
context.fill();
}
context.stroke();
});
context.beginPath();
context.moveTo(state.startX, state.startY);
context.lineTo(state.endX, state.endY);
context.closePath();
context.lineWidth = 1;
context.strokeStyle = '#ff0';
context.stroke();
var currentBlockIndex = state.row * mapCols + state.col;
var currentBlock = mapBlocks[currentBlockIndex];
context.beginPath();
context.rect(currentBlock.x, currentBlock.y, currentBlock.width,
currentBlock.height);
context.closePath();
context.fillStyle = 'rgba(0, 255, 0, 0.2)';
context.fill();
var multiplier, edge;
multiplier = state.stepCol < 0 ? 0 : 1;
edge = currentBlock.x + currentBlock.width * multiplier;
context.beginPath();
context.moveTo(edge, 0);
context.lineTo(edge, height);
context.closePath();
context.lineWidth = 0.5;
context.strokeStyle = state.nextColTime < state.nextRowTime ? '#0f0' : '#f00';
context.stroke();
multiplier = state.stepRow < 0 ? 0 : 1;
edge = currentBlock.y + currentBlock.height * multiplier;
context.beginPath();
context.moveTo(0, edge);
context.lineTo(width, edge);
context.closePath();
context.lineWidth = 0.5;
context.strokeStyle = state.nextRowTime < state.nextColTime ? '#0f0' : '#f00';
context.stroke();
}
window.addEventListener('keyup', function(event) {
switch (event.keyCode) {
case 49: // 1
state = new State(mouseX, mouseY, state.endX, state.endY);
break;
case 50: // 2
state = new State(state.startX, state.startY, mouseX, mouseY);
break;
case 37: // left arrow
state.stepBackward();
break;
case 39: // right arrow
state.stepForward();
break;
default:
return;
}
event.preventDefault(true);
draw();
});
window.addEventListener('mousemove', function(event) {
mouseX = event.pageX;
mouseY = event.pageY;
});
init();
draw();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment