JSFiddle - React, Tailwind, and code Playground
JavaScript
var map = window.map = [
'xxxxxxxxxxxxxxx',
'x x x x',
'x xx xxx x x',
'x x x',
'xxxxxxxxxxxxxxx',
].join('').split('').map(function (s) {
// spaces are open, xes are a random texture
if (s === ' ') return 0;
return 1;
});
// map
var width = 15;
var height = 5;
// position
var x = 1.5
var y = 1.5
var heading = 30 / 180 * Math.PI;
var c = cast(x, y, heading);
document.querySelector('#d').innerHTML = [c.x, c.y, c.ex, c.ey].join(' ');
function cast(px, py, angle) {
if (px < 0 || px > width || py < 0 || py > height || map[Math.floor(px) + Math.floor(py) * width]) {
return {x: Math.floor(px), y: Math.floor(py), ex: px, ey:py};
}
// delta of moving one unit forward on a line at angle
var dx = Math.cos(angle);
var dy = Math.sin(angle);
if (Math.abs(dx) < 0.0000001) dx = 0;
if (Math.abs(dy) < 0.0000001) dy = 0;
for (var i = 0; i < 18; ++i) {
var restx = px % 1;
if (dx > 0) restx = 1 - restx;
if (restx === 0) restx = 1;
var ustepsx = Math.abs(restx / dx);
var resty = py % 1;
if (dy > 0) resty = 1 - resty;
if (resty === 0) resty = 1;
var ustepsy = Math.abs(resty / dy);
var dir = ustepsx < ustepsy;
// rounding ensures we dont get screwed too hard by floating point errors
if (dir) {
if (dx) px = Math.round(px + ustepsx * dx);
if (dy) py += ustepsx * dy;
} else {
if (dx) px += ustepsy * dx;
if (dy) py = Math.round(py + ustepsy * dy);
}
var x = Math.floor(px);
var y = Math.floor(py);
var bx = x + (dir && dx < 0 ? -1 : 0);
var by = y + (!dir && dy < 0 ? -1 : 0);
if (map[bx + by * width]) return {x: bx, y: by, ex: px, ey:py};
// corner case, repeat check
if (px === x && py === y) {
var cx = x + (!dir && dx < 0 ? -1 : 0);
var cy = y + (dir && dy < 0 ? -1 : 0);
if (map[cx + cy * width]) return {x: cx, y: cy, ex: px, ey:py};
}
// oob
if...