# Raytracing on Tile maps, basic concepts

## Example source code

``````
<!DOCTYPE html>
<html>

<script type="text/javascript">
var ctx = null;
var tileW = 10, tileH = 10;
var gridW = 60, gridH = 40;
var circleX = 30, circleY = 20, radius = 15;
var mapData = new Array();
var rayData = {};

window.onload = function() {
ctx = document.getElementById('game').getContext('2d');
ctx.font = "bold 10pt sans-serif";

// Create our "map" and set random 10 tiles as impassable (0)
for(var i = 0; i < (gridW*gridH); i++) { mapData.push(1); }
for(var i = 0; i < 10; i++)
{
// Choose a random point on the map
var randPos = (Math.floor(Math.random()*20000)%(gridW*gridH));

// Check it's not the centre of the circle
if(randPos==((circleY*gridW)+circleX)) { continue; }

// Set the value of this position to 0
mapData[randPos] = 0;
}

rayData = updateRayData(circleX, circleY, radius);

// Get the position of the mouse click on the page
var mouseX = e.pageX;
var mouseY = e.pageY;

// Find the offset of the Canvas relative to the document top, left,
// and modify the mouse position to account for this
var p = game;
do
{
mouseX-= p.offsetLeft;
mouseY-= p.offsetTop;

p = p.offsetParent;
} while(p!=null);

// fit the real mouse position to our grid
mouseX = Math.floor(mouseX / tileW);
mouseY = Math.floor(mouseY / tileH);

// Set this blocking point to on or off, UNLESS this is the central point...
if(mouseX!=circleX || mouseY!=circleY)
{
mapData[((mouseY*gridW)+mouseX)] = (mapData[((mouseY*gridW)+mouseX)]==0 ? 1 : 0);
}

rayData = updateRayData(circleX, circleY, radius);
});

requestAnimationFrame(drawGame);
};

function updateRayData(cx, cy, cr)
{
var edges = pointsOnCircumference(cx, cy, cr);
var points = {};

for(x in edges)
{
var line = pointsOnLine(cx, cy, edges[x][0], edges[x][1]);

for(l in line)
{
points[((line[l][1]*gridW)+line[l][0])] = [line[l][0], line[l][1]];
if(mapData[((line[l][1]*gridW)+line[l][0])]==0) { break; }
}
}

return points;
}

function pointsOnLine(x1, y1, x2, y2)
{
line = new Array();

var dx = Math.abs(x2 - x1);
var dy = Math.abs(y2 - y1);
var x = x1;
var y = y1;
var n = 1 + dx + dy;
var xInc = (x1 < x2 ? 1 : -1);
var yInc = (y1 < y2 ? 1 : -1);
var error = dx - dy;

dx *= 2;
dy *= 2;

while(n>0)
{
line.push([x, y]);

if(error>0)
{
x+= xInc;
error-= dy;
}
else
{
y+= yInc;
error+= dx;
}

n-= 1;
}

return line;
}

function pointsOnCircumference(cx, cy, cr)
{
var list = new Array();

var x = cr;
var y = 0;
var o2 = Math.floor(1 - x);

while(y <= x)
{
list.push([ x + cx,  y + cy]);
list.push([ y + cx,  x + cy]);
list.push([-x + cx,  y + cy]);
list.push([-y + cx,  x + cy]);
list.push([-x + cx, -y + cy]);
list.push([-y + cx, -x + cy]);
list.push([ x + cx, -y + cy]);
list.push([ y + cx, -x + cy]);

y+= 1;

if(o2 <= 0) { o2+= (2 * y) + 1; }
else
{
x-= 1;
o2+= (2 * (y - x)) + 1;
}
}

return list;
}

function drawGame()
{
if(ctx==null) { return; }

// Clear the Canvas
ctx.fillStyle = "#ffffff";
ctx.fillRect(0, 0, 600, 400);

// Draw rays
ctx.fillStyle = "#dddd00";
for(r in rayData)
{
ctx.fillRect(rayData[r][0]*tileW, rayData[r][1]*tileH, tileW, tileH);
}

// Draw the grid
ctx.fillStyle = "#000000";
ctx.strokeStyle = "#999999";
ctx.beginPath();
for(y = 0; y < gridH; ++y)
{
for(x = 0; x < gridW; ++x)
{
// Draw a blocking point here?
if(mapData[((y*gridW)+x)]==0) { ctx.fillRect((x*tileW), (y*tileH), tileW, tileH); }

// Draw the grid lines
ctx.rect((x*tileW), (y*tileH), tileW, tileH);
}
}
ctx.closePath();
ctx.stroke();

// Draw circle centre
ctx.fillStyle = "#ff0000";
ctx.fillRect(circleX*tileW, circleY*tileH, tileW, tileH);

// Ask for the next animation frame
requestAnimationFrame(drawGame);
}
</script>