首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用光线投射实现DDA算法

用光线投射实现DDA算法
EN

Code Review用户
提问于 2021-02-12 03:16:14
回答 1查看 908关注 0票数 3

我正在制作一个简单的游戏,像沃尔芬斯坦3d在C上使用光线投射。为了计算射线的长度,我使用了DDA算法。我应用代码的一部分,计算射线的长度和墙壁的大小的垂直线,射线击中。如何优化和改进代码?

代码语言:javascript
复制
/*
**      Function:           void        calculate()
**
**      Arguments:          main struct and i
**
**      return:             void
**
**      Description:        The raycasting loop is a for loop that goes through every x,
** so there is a calculation for every  vertical stripe of the screen.
*/

void            calculate(t_cub3d *cub)
{
    int i;

    i = 0;
    while (i < cub->window.res_width)
    {
        calculate_cam(cub, &i);
// field_x and field_y represent the current square of the map the ray is in.
        cub->field.field_x = cub->player.x_pos;
        cub->field.field_y = cub->player.y_pos;
        calculate_ray_dir(cub);
        calculate_step(cub);
        calculate_wall(cub);
        calculate_height(cub);
        draw(cub, i);
        i++;
    }
    calculate_sprite(cub);
}


/*
**      Function:           void        calculate_cam()
**
**      Arguments:          main struct, variable counter(width)
**
**      return:             void
**
**      Description:        x_camera is the x-coordinate on the camera plane
** that the current x-coordinate of the screen represents, done this way
** so that the right side of the screen will get coordinate 1, the center
** of the screen gets coordinate 0, and the left side of the screen gets coordinate -1
*/

void            calculate_cam(t_cub3d *cub, int *i)
{
    cub->camera.x_camera = 2 * *i / (double)(cub->window.res_width) - 1;
    cub->ray.dir_ray_x = cub->player.x_dir + cub->camera.x_plane * \
            cub->camera.x_camera;
    cub->ray.dir_ray_y = cub->player.y_dir + cub->camera.y_plane * \
            cub->camera.x_camera;
}


/*
**      Function:           void        calculate_ray_dir()
**
**      Arguments:          main struct
**
**      return:             void
**
**      Description:        x_deltaDist and y_deltaDist are the distance the ray
** has to travel to go from 1 x-side to the next x-side, or from 1 y-side
** to the next y-side.
*/

void            calculate_ray_dir(t_cub3d *cub)
{
    if (cub->ray.dir_ray_y == 0)
        cub->ray.x_deltadist = 0;
    else
    {
        if (cub->ray.dir_ray_x == 0)
            cub->ray.x_deltadist = 1;
        else
            cub->ray.x_deltadist = fabs(1 / cub->ray.dir_ray_x);
    }
    if (cub->ray.dir_ray_x == 0)
        cub->ray.y_deltadist = 0;
    else
    {
        if (cub->ray.dir_ray_y == 0)
            cub->ray.y_deltadist = 1;
        else
            cub->ray.y_deltadist = fabs(1 / cub->ray.dir_ray_y);
    }
}


/*
**      Function:           void        calculate_step()
**
**      Arguments:          main struct
**
**      return:             void
**
**      Description:        x_sideDist and y_sideDist are initially the distance
** the ray has to travel from its start position to the first x-side and
** the first y-side.
*/

void            calculate_step(t_cub3d *cub)
{
    if (cub->ray.dir_ray_x < 0)
    {
        cub->ray.x_ray_step = -1;
        cub->ray.x_sidedist = (cub->player.x_pos - (double)(cub->field.field_x))
                * cub->ray.x_deltadist;
    }
    else
    {
        cub->ray.x_ray_step = 1;
        cub->ray.x_sidedist = (((double)(cub->field.field_x) + 1.0 - \
                cub->player.x_pos) * cub->ray.x_deltadist);
    }
    if (cub->ray.dir_ray_y < 0)
    {
        cub->ray.y_ray_step = -1;
        cub->ray.y_sidedist = (cub->player.y_pos - (double)(cub->field.field_y))
                * cub->ray.y_deltadist;
    }
    else
    {
        cub->ray.y_ray_step = 1;
        cub->ray.y_sidedist = ((double)(cub->field.field_y) + 1.0 - \
                cub->player.y_pos) * cub->ray.y_deltadist;
    }
}


/*
**      Function:           void        calculate_wall()
**
**      Arguments:          main struct
**
**      return:             void
**
**      Description:         DDA algorithm. It's a loop that increments the ray with 1 square
**      every time, until a wall is hit.
*/

void            calculate_wall(t_cub3d *cub)
{
    int     is_wall;

    is_wall = 0;
    cub->window.side = 0;
    while (is_wall == 0)
    {
        if (cub->ray.x_sidedist < cub->ray.y_sidedist)
        {
            cub->ray.x_sidedist += cub->ray.x_deltadist;
            cub->field.field_x += cub->ray.x_ray_step;
            cub->window.side = 0;
        }
        else
        {
            cub->ray.y_sidedist += cub->ray.y_deltadist;
            cub->field.field_y += cub->ray.y_ray_step;
            cub->window.side = 1;
        }
        if (cub->field.map[cub->field.field_y][cub->field.field_x] == '1')
            is_wall = 1;
    }
    calculate_distto_wall(cub);
}


/*
**      Function:           void        calculate_distto_wall()
**
**      Arguments:          main struct
**
**      return:             void
**
**      Description:        calculate the distance of the ray to the wall
*/

void            calculate_distto_wall(t_cub3d *cub)
{
    if (cub->window.side == 0)
    {
        cub->ray.wall_dist = ((double)(cub->field.field_x) - cub->player.x_pos \
                + (1 - cub->ray.x_ray_step) / 2) / cub->ray.dir_ray_x;
    }
    else
    {
        cub->ray.wall_dist = ((double)(cub->field.field_y) - cub->player.y_pos \
                + (1 - cub->ray.y_ray_step) / 2) / cub->ray.dir_ray_y;
    }
}


/*
**      Function:           void        calculate_height()
**
**      Arguments:          main struct
**
**      return:             void
**
**      Description:        calculate the height of the line that has to be
**      drawn on screen
*/

void            calculate_height(t_cub3d *cub)
{
    cub->window.height_ln = (int)(cub->window.res_height / cub->ray.wall_dist);
    cub->window.top_wall = (cub->window.height_ln * -1) / 2 + \
            cub->window.res_height / 2;
    if (cub->window.top_wall < 0)
        cub->window.top_wall = 0;
    cub->window.bottom_wall = cub->window.height_ln / 2 + \
            cub->window.res_height / 2;
    if (cub->window.bottom_wall >= cub->window.res_height)
        cub->window.bottom_wall = cub->window.res_height - 1;
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2021-02-12 22:04:33

使用your语言记录您的函数

看起来你用一些特别的方式来记录你的函数。添加这些文档是非常好的,但是有一些工具使得它更有用,比如含氧。一旦您重新格式化您的评论遵循DO2语法,那么您就可以使用D氧气工具生成PDF、HTML和其他各种格式的文档。它还可以检查文档是否正确,例如,是否记录了所有参数。它已经在第一个函数中找到了一个错误:在函数参数的描述中使用mentino i,但是没有这样的东西。

通过值

传递整数

为什么要引用i传递calculate_sam()?您应该按值传递它,否则您将支付不必要的指针取消引用的费用。

命名事物

您应该尝试为函数提供更多的描述性名称。命名所有的calculate_something()并不是很有用,因为计算基本上是计算机一直在做的事情。看起来,calculate()实际上导致了绘制所有东西,因为它调用了draw()。所以也许应该用类似于draw_scene()的名字来代替?draw()应该是draw_column()吗?

为什么有x_posx_plane,但是field_x呢?有一个一致的顺序词,使它更容易阅读你的代码。但是,field.field_x中也有冗余,也许可以重命名它,这样您就可以编写field.x了?

cub是什么?它代表一个立方体吗?如果是这样的话,不要随意地从一个单词中删除一个字母,稍后您可能会后悔

此外,如果有一个包含坐标的变量,则使用xy而不是i

具有函数返回值

您的函数不返回任何内容,而是修改指向的对象。尽管您可能认为这会将事情保持在一起,但这实际上会使它们更难使用,并且可能会导致大量临时变量被放入t_cub3d中,这将浪费内存。尝试让函数return它们的结果,并且只将这些变量传递给它们需要使用的变量。

例如,calculate_cam()似乎只将x_camera计算为一个临时值,而其他代码(据我所见)所使用的唯一东西是射线的方向。因此,假设cub->rayr_ray类型,我会写:

代码语言:javascript
复制
t_ray calculate_cam(const t_cub3d *cub, int x)
{
    int x_camera = 2.0 * x / cub->window.res_width - 1;
    t_ray ray;
    ray.dir_ray_x = cub->player.x_dir + cub->camera.x_plane * x_camera;
    ray.dir_ray_y = cub->player.y_dir + cub->camera.y_plane * x_camera;
    return ray;
}

在适当的情况下使用bool

当您有一个包含一个值的变量,该值应该表示"true“或"false",请使用bool from <stdbool.h>。例如,is_wall是一个很好的候选者。

更喜欢for而不是while (如果合适的话)

for-statement的优点是可以明确地将初始值、结束条件和增量放在循环的顶部。所以在calculate()中,我会写:

代码语言:javascript
复制
for (int i = 0; i < cub->window.res_width; i++)
{
    ...
}
票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/255913

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档