光线投射墙阿伦特同样宽

时间:2018-07-20 06:10:25

标签: javascript canvas raycasting

我正在研究光线投射器,并遵循了本教程:https://dev.opera.com/articles/3d-games-with-canvas-and-raycasting-part-1/

我的问题是关于一个Bug,该Bug会根据在画布上绘制的位置绘制/计算不同宽度的Walls(因此,射线角度对玩家的方向点(中心视图)有多大): 中间(1.)中绘制的墙较小,但屏幕左侧或右侧(2.)上的墙则绘制得较宽。当您查看图像时,它最容易理解。我想我只是对数学有误,可能是四舍五入到了我不应该发现的地方,但我还没有找到它,或者可以想到此错误的任何原因。它是使用JavaScript在HTML Canvas中制成的。

enter image description here

在我的第一个功能中,我为画布的每个x像素发出一束光线:

let resolution = Math.ceil(canvas.width / this.resolution); //canvas width = 1600, resolution = 1
let id = 0;

    for (let x = 0; x < resolution; x++) {
        let viewDist = (canvas.width / this.resolution) / Math.tan((this.fov / 2)); //fov 90 in rad
        let rayx = (-resolution / 2 + x) * this.resolution;
        let rayDist = Math.sqrt(rayx * rayx + viewDist * viewDist);
        let rayAngle = Math.asin(rayx / rayDist);

        let wall = this.castWall(this.pod * Math.PI / 180 + rayAngle);
        this.drawWall(x, wall);
    }

但是我不认为这里有什么问题。在第二个函数中,我向每条射线投射光并返回到碰撞墙的距离。我的积木/墙壁宽50。我的地图存储在2D数字Array-> this.map.grid中,this.map.width保持x方向上有多少块,this.map.height保持y方向上的计数。

castWall(angle) {
    const PI2 = Math.PI * 2;

    angle %= PI2;
    if (angle < 0) {
        angle += PI2;
    }

    let right = angle > PI2 * 0.75 || angle < PI2 * 0.25;
    let up = angle < 0 || angle > Math.PI;

    let sin = Math.sin(angle);
    let cos = Math.cos(angle);

    let dist = 0;
    let textureX;
    let texture;

    let slope = sin / cos;
    let dXVer = right ? 1 : -1;
    let dYVer = dXVer * slope;

    let px = this.x / 50;
    let py = this.y / 50;

    let x = right ? Math.ceil(px) : Math.floor(px);
    let y = py + (x - px) * slope;

    while (x >= 0 && x < this.map.width && y >= 0 && y < this.map.height) {
        let wallX = Math.floor(x + (right ? 0 : -1));
        let wallY = Math.floor(y);

        if (this.map.grid[wallY][wallX] > 0) {
            dist = Math.sqrt(Math.pow(x - px, 2) + Math.pow(y - py, 2));
            texture = this.map.grid[wallY][wallX];
            textureX = (y * 50) % 50;

            if (right) {
                textureX = 50 - textureX;
            }
            break;
        }
        x += dXVer;
        y += dYVer;
    }

    slope = cos / sin;

    let dYHor = up ? -1 : 1;
    let dXHor = dYHor * slope;

    y = up ? Math.floor(py) : Math.ceil(py);
    x = px + (y - py) * slope;

    while (x >= 0 && x < this.map.width && y >= 0 && y < this.map.height) {
        let wallY = Math.floor(y + (up ? -1 : 0));
        let wallX = Math.floor(x);

        if (this.map.grid[wallY][wallX] > 0) {
            let distHor = Math.sqrt(Math.pow(x - px, 2) + Math.pow(y - py, 2));

            if (dist === 0 || distHor < dist) {
                dist = distHor;
                texture = this.map.grid[wallY][wallX];
                textureX = (x * 50) % 50;

                if (up) {
                    textureX = 50 - textureX;
                }
            }
            break;
        }
        x += dXHor;
        y += dYHor;
    }

    return {
        distance: dist,
        texture: texture,
        textureX: textureX
    };`

我还尝试了使用其他算法(Bresenham和DDA)进行射线广播,但是我从未真正使它们起作用。这是唯一对我有用的。如果您对代码有任何疑问,请随时提问。

0 个答案:

没有答案