代码之家  ›  专栏  ›  技术社区  ›  John Smith

为什么细胞之间有间隙?

  •  0
  • John Smith  · 技术社区  · 2 年前

    我正在用纯JavaScript创建一个光线投射引擎,我刚刚实现了用于优化的DDA算法。但是,渲染中存在一个问题,即每个长方体之间存在间隙: rendering issue

    DDA算法旨在自动跳到下一个点,在该点它将击中构成地图的一个方框。这是为每条光线实现以下功能的函数:

    function getDistances() {
        for (var i = 0; i < Game.rays.quantity; i++) {
          // get current angle of the ray
          var angle = Game.toRad((Game.player.angle - (Game.rays.fov / 2)) + ((Game.rays.fov / Game.rays.quantity) * i));
          var rayX = Game.player.x;
          var rayY = Game.player.y;
          // pre-calculate sin, cos, and tan for angle
          var sin = Math.sin(angle);
          var cos = Math.cos(angle);
          var tan = Math.tan(angle);
          var hitWall = false;
    
          for (var j = 0; j < Game.rays.renderDistance; j++) {
            // get the closest X and Y coordinate for the ray
            var stepX, stepY;
    
            if (sin < 0) {
              stepY = (Math.floor((rayY - 1) / Game.mapConfig.blockSize) * Game.mapConfig.blockSize) - rayY;
            } else {
              stepY = (Math.ceil((rayY + 1) / Game.mapConfig.blockSize) * Game.mapConfig.blockSize) - rayY;
            }
            if (cos < 0) {
              stepX = (Math.floor((rayX - 1) / Game.mapConfig.blockSize) * Game.mapConfig.blockSize) - rayX
            } else {
              stepX = (Math.ceil((rayX + 1) / Game.mapConfig.blockSize) * Game.mapConfig.blockSize) - rayX;
            }
          
    
            // closest coordinate pairs where ray intersects a box (rounded to X and Y)
            var nearX = [rayX + stepX, (stepX * tan) + rayY]; // blue
            var nearY = [(stepY / tan) + rayX, rayY + stepY]; // purple
    
            // take the X and Y coordinates and get the box it hit from Game.map.data
            // this is where the issues are
            var mapX, mapY;
    
            if (Game.distanceTo([rayX, rayY], nearX) < Game.distanceTo([rayX, rayY], nearY)) {
              // hits side of box
              rayX = nearX[0];
              rayY = nearX[1];
              
              if (cos < 0) { // facing left
                mapX = Math.floor(rayX / Game.mapConfig.blockSize) - 1;
                mapY = Math.floor(rayY / Game.mapConfig.blockSize);
              } else { // facing right
                mapX = Math.floor(rayX / Game.mapConfig.blockSize);
                mapY = Math.floor(rayY / Game.mapConfig.blockSize);
              }
            } else {
              // hits top/bottom of box
              rayX = nearY[0];
              rayY = nearY[1];
    
              if (sin < 0) { // facing down
                mapX = Math.floor(rayX / Game.mapConfig.blockSize);
                mapY = Math.floor(rayY / Game.mapConfig.blockSize) - 1;
              } else { // facing up
                mapX = Math.floor(rayX / Game.mapConfig.blockSize);
                mapY = Math.floor(rayY / Game.mapConfig.blockSize);
              }
            }
    
            // check if the box is solid; if so, stop the ray
            if (Game.checkSolid(mapY, mapX)) {
              hitWall = true;
              var distance = Math.sqrt(Math.pow(rayX - Game.player.x, 2) + Math.pow(rayY - Game.player.y, 2));
              Game.rays.distances[i] = [distance, Game.map.data[mapY][mapX]];
              break;
            }
          }
    
          if (!hitWall) {
            Game.rays.distances[i] = [Infinity, " "];
          }
        }
      }
    

    似乎每当光线遇到长方体的角时,它都会在检查长方体是否为实心时跳过它,因为它检查错了长方体。我想我在计算 mapX mapY 错误,但我不完全确定。

    映射是一组嵌套数组,因此要访问左上角的单元格,需要调用 Game.map.data[0][0]

    有人知道这里可能出了什么问题吗?

    对于感兴趣的人,可以在这里找到完整的代码: raycaster

    0 回复  |  直到 2 年前
        1
  •  1
  •   Cacci    2 年前

    将+1和-1的值减少到更小的值似乎可以解决问题。如果你还需要别的东西,请告诉我。

        if (sin < 0) {
          stepY = (Math.floor((rayY - 0.00000000001) / Game.mapConfig.blockSize) * Game.mapConfig.blockSize) - rayY;
        } else {
          stepY = (Math.ceil((rayY + 0.00000000001) / Game.mapConfig.blockSize) * Game.mapConfig.blockSize) - rayY;
        }
        if (cos < 0) {
          stepX = (Math.floor((rayX - 0.00000000001) / Game.mapConfig.blockSize) * Game.mapConfig.blockSize) - rayX
        } else {
          stepX = (Math.ceil((rayX + 0.00000000001) / Game.mapConfig.blockSize) * Game.mapConfig.blockSize) - rayX;
        }