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

在Rust+Raylib中实现DDA光线投射算法的问题排查

Rust+Raylib下DDA光线投射算法问题排查

背景

我在Rust结合Raylib框架中,为8×8的布尔值网格世界(每个网格单元为64×64像素)实现基于Digital Differential Analyzer(DDA)算法的单条光线投射功能。已有可正常运行的暴力实现版本,因此编写了函数签名完全一致的DDA版本,期望直接替代暴力版本。

函数签名

fn ray_cast_brute_force(&self, player: &Player, d: &mut RaylibDrawHandle) 

fn ray_cast_dda(&self, player: &Player, d: &mut RaylibDrawHandle)

Player结构体定义

pub struct Player {
    x: f32,
    y: f32,
    angle: f32, // 弧度制
    direction: Vector2,
}

其中direction为包含两个浮点数的Vector2类型。

正常运行的暴力实现版本

暴力实现可100%正常运行,代码如下:

pub fn ray_cast_brute_force(&self, player: &Player, d: &mut RaylibDrawHandle) {
    // 初始参数
    let ray_start = Vector2::new(player.x + 32.0, player.y + 32.0);
    let mut ray_end = ray_start;
    let step_size: f32 = 2.0;

    // 检查射线当前位置是否在墙体上(1为墙体,0为空)
    // 若未命中墙体,则延长射线长度
    // self.data 是8×8的布尔值网格数组
    while self.data[ray_end.x as usize / 64][ray_end.y as usize / 64] == 0 {
        ray_end.x += player.direction.x * step_size;
        ray_end.y += player.direction.y * step_size;
    }

    d.draw_line_ex(ray_start, ray_end, 5.0, Color::RED);
}

DDA版本问题

DDA版本无法正常工作:射线方向正确,且不会超出512×512像素的地图范围,但通常无法正确终止在墙体上。

DDA实现代码

fn ray_cast_dda(&self, player: &Player, d: &mut RaylibDrawHandle) {
    // 不可变初始参数
    let ray_start = Vector2::new(player.x + 32.0, player.y + 32.0); // 射线起点
    let direction_x = player.angle.cos(); // 射线X方向分量
    let direction_y = player.angle.sin(); // 射线Y方向分量
    let step_x = if direction_x < 0.0 { -1 } else { 1 }; // X方向步进方向
    let step_y = if direction_y < 0.0 { -1 } else { 1 }; // Y方向步进方向
    let t_delta_x = (64.0 / direction_x.abs()).abs(); // 穿越X方向网格边界所需的t增量
    let t_delta_y = (64.0 / direction_y.abs()).abs(); // 穿越Y方向网格边界所需的t增量

    // 可变初始参数
    let mut map_x = (ray_start.x / 64.0) as isize; // 当前射线所在的网格X坐标
    let mut map_y = (ray_start.y / 64.0) as isize; // 当前射线所在的网格Y坐标
    let mut t_max_x = {
        let boundary_x = if direction_x > 0.0 {
            (map_x + 1) as f32 * 64.0
        } else {
            map_x as f32 * 64.0
        };
        (boundary_x - ray_start.x) / direction_x
    };
    let mut t_max_y = {
        let boundary_y = if direction_y > 0.0 {
            (map_y + 1) as f32 * 64.0
        } else {
            map_y as f32 * 64.0
        };
        (boundary_y - ray_start.y) / direction_y
    };

    let mut hit = false;

    // DDA算法循环
    while !hit {
        if t_max_x < t_max_y {
            map_x += step_x; // 更新当前网格X坐标
            t_max_x += t_delta_x; // 更新下一次X边界的t值
        } else {
            map_y += step_y; // 更新当前网格Y坐标
            t_max_y += t_delta_y; // 更新下一次Y边界的t值
        }

        // 检查是否命中墙体
        if self.data[map_x as usize][map_y as usize] != 0 {
            hit = true;
        }
    }

    // 计算命中点的t值
    let t_hit = t_max_x.min(t_max_y);

    // 计算射线终点
    let ray_end = Vector2::new(
        ray_start.x + t_hit * direction_x,
        ray_start.y + t_hit * direction_y,
    );

    // 绘制射线
    d.draw_line_ex(ray_start, ray_end, 5.0, Color::RED);
}

求助

我认为DDA实现存在问题,但无法定位具体错误,若需要可提供更多源码。


内容的提问来源于stack exchange,提问作者Cade Thornton

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 23:49:59