ts-raycasting
Version:
Raycasting in typescript
108 lines (100 loc) • 3.5 kB
text/typescript
/// <reference path="../../dist/interfaces/IRay.d.ts"/>
declare const raycast: any;
// initialize canvas
const ctx = (<HTMLCanvasElement>document.getElementById('canvas')).getContext('2d');
const mctx = (<HTMLCanvasElement>document.getElementById('minimap')).getContext('2d');
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 256, 300);
mctx.fillStyle = "black";
mctx.fillRect(0, 0, 130, 130);
// initiliaze world and camera
const map: number[][] = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1],
[1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1],
[1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1],
[1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1],
[1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
];
let camX = 3.5;
let camY = 3.5;
let camRot = (Math.PI / 2);
const h = 80;
// test every ray's intersection
const testIntersection = (row: number, column: number, cell: number): boolean => {
if (cell === 1) {
return false;
}
return true;
}
// calculate new position
const forward = (): void => {
camX += Math.cos(camRot) * 0.5;
camY += Math.sin(camRot) * 0.5;
};
document.addEventListener("keyup", (e) => {
switch (e.keyCode) {
case 38:
forward();
break;
case 37:
camRot -= (Math.PI / 12);
break;
case 39:
camRot += (Math.PI / 12);
break;
default: {
console.log('unexpected key');
}
}
});
// main
setInterval(() => {
// 2.5d plot
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 256, 300); // clear canvas
ctx.fillStyle = "grey";
ctx.fillRect(0, 150, 256, 150); // draw floor
// minimap
mctx.fillStyle = "black";
mctx.fillRect(0, 0, 130, 130); // clear canvas
// render minimap
map.forEach((row: number[], r: number) =>
row.forEach((cell: number, c: number) => {
if (cell === 1) {
mctx.fillStyle = "white";
} else {
mctx.fillStyle = "black";
}
mctx.fillRect(c * 10, r * 10, c * 10 + 10, r * 10 + 10);
}));
// render 2.5d plot
mctx.strokeStyle = "green";
const rays: IRay[] = raycast.castRays(map, camX, camY, camRot, testIntersection);
rays.forEach((ray: IRay, index: number) => {
if (ray.side) {
ctx.fillStyle = "yellow";
} else {
ctx.fillStyle = "blue";
}
ctx.fillRect(index, 150 - (h / ray.dist), 1, 2 * (h / ray.dist));
// draw on miminap
mctx.beginPath();
mctx.moveTo(Math.floor(camX * 10), Math.floor(camY * 10));
mctx.lineTo(Math.floor(ray.x * 10), Math.floor(ray.y * 10));
mctx.stroke();
});
const dirRay: IRay = raycast.castRay(map, camX, camY, testIntersection, camRot);
mctx.strokeStyle = "red";
mctx.beginPath();
mctx.moveTo(Math.floor(camX * 10), Math.floor(camY * 10));
mctx.lineTo(Math.floor(dirRay.x * 10), Math.floor(dirRay.y * 10));
mctx.stroke();
}, 1000 / 30);