Last active
March 18, 2016 02:17
-
-
Save noonat/37f8b846542e80b7edce to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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