You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Raycaster远离(0,0)点时墙体检测异常问题求助

射线投射器大地图穿墙问题排查与修复

问题现象

  • 16×16瓦片、64×64尺寸的地图下,射线投射器运行正常;切换为60×60尺寸地图后,部分墙体无法被射线检测到。
  • 玩家位于坐标(2013.69,2043.34)时,射线可正常检测墙体;移动至(2124.59,2215.76)后,射线出现穿墙现象。
  • 尝试通过让玩家静止、滚动地图的方式缓解,但画面流畅度差。

核心原因

问题源于浮点数大数计算精度丢失:

  1. float类型仅支持6-7位十进制有效精度,当玩家坐标达到2000+时,小数部分精度被稀释,导致射线坐标、瓦片索引计算出现偏差。
  2. 射线步进的浮点累加误差随距离增大而放大,射线位置偏离实际应检测的墙体瓦片。
  3. 原代码中瓦片索引的边界判断存在漏洞,可能跳过合法瓦片检测或访问越界内存。

代码问题分析

核心代码片段及问题点:

void castRay(Map* &mp)
{
    int map_x, map_y, map_point, dof;
    // 问题1:float精度不足,无法准确表示大数坐标
    float ray_x, ray_y, ray_angle, ray_offset_x, ray_offset_y;
    float v_distance = 1e9, h_distance = 1e9, wall_distance;
    float vx, vy, hx, hy;

    int tile_size = mp->tileSize;
    ray_angle = player_angle-30*D;
    if(ray_angle > 2*PI)
            ray_angle -= 2*PI;
    else if(ray_angle < 0)
            ray_angle += 2*PI;

    for(int r = 0; r < 60; r++)
    {
        // Checking horizontal line
        float aTan = -1/tan(ray_angle);
        dof = 0;
        if(ray_angle > PI)
        {
            // 问题2:大数下的整数转换会丢失精度,导致初始射线位置错误
            ray_y = (((int)center_y/mp->tileSize)*mp->tileSize)-0.0001;
            ray_x = center_x + (center_y-ray_y)*aTan;
            ray_offset_y = -mp->tileSize;
            ray_offset_x = -ray_offset_y*aTan;
        }
        // ... 其余射线初始化代码

        while(dof < max(mp->Map_Width,mp->Map_Height))
        {
            map_x = (int)ray_x/mp->tileSize;
            map_y = (int)ray_y/mp->tileSize;
            map_point = map_y*mp->Map_Width+map_x;
            hx = ray_x;
            hy = ray_y;
            h_distance = sqrt((ray_x-center_x)*(ray_x-center_x)+(ray_y-center_y)*(ray_y-center_y));
            // 问题3:边界判断不严谨,未检查map_x/map_y是否在地图合法范围内
            if(map_point > 0 && map_point < mp->Map_Size && mp->Map_Tilemap[map_point] == 2)
            {
                break;
            }
            else
            {
                ray_x += ray_offset_x;
                ray_y += ray_offset_y;
                dof++;
            }
        }

        // ... 垂直射线检测代码(存在同样的精度和边界问题)

        // ... 3D渲染代码
    }
}

修复方案

1. 提升计算精度

将所有存储坐标、角度的float替换为double,利用其15-17位的十进制有效精度,缓解大数下的精度丢失:

// 替换所有float为double
double ray_x, ray_y, ray_angle, ray_offset_x, ray_offset_y;
double v_distance = 1e9, h_distance = 1e9, wall_distance;
double vx, vy, hx, hy;

2. 修正边界判断逻辑

直接检查map_x和map_y的合法性,避免越界和错误检测:

// 替换原if判断
if(map_x >= 0 && map_x < mp->Map_Width && map_y >= 0 && map_y < mp->Map_Height 
   && mp->Map_Tilemap[map_point] == 2)
{
    break;
}

3. 优化地图坐标体系(根治方案)

放弃玩家坐标无限增大的设计,改为玩家静止、地图滚动模式:

  • 玩家始终保持在屏幕中心对应的局部坐标(比如(tile_size*32, tile_size*32))。
  • 维护地图偏移量map_offset_x、map_offset_y,根据玩家移动方向更新。
  • 计算射线时,用局部坐标加偏移量获取全局瓦片索引,确保所有计算坐标处于小数值范围,彻底避免大数精度问题。

4. 优化射线步进计算

提前缓存三角函数值,减少重复计算;用整数运算辅助瓦片定位,降低浮点累加误差。

内容的提问来源于stack exchange,提问作者Duong Tran

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 12:05:06