修复光线投射算法

问题描述 投票:0回答:1

我是一名新生程序员。最近,我对计算机图形学产生了浓厚的兴趣,并一直在尝试练习光线投射算法。这几天我一直在 YouTube 上播放教程。我编写的大部分代码基本上只是复制粘贴,因为我首先想要了解的是光线投射的实际工作原理。但是,我面临两个问题: 1.我的投射光线与玩家的视角不一致,并且错误地表示了投射光线的特征(例如:如果撞到墙上,它会变短) 2.有时我的程序得到因“错误 -1073741819”消息而崩溃。我仍在尝试理解算法(这对我来说非常具有挑战性)以修复代码。因此,如果你们能花一点时间看我的代码并指出发生了什么,我将不胜感激!

这是我遵循的教程: 文字

这是我的问题的一些图片:

Ray-cast problem Program crashed

这是我在 VSC 中使用 SDL 库和 C++ 的代码:

#include <iostream>
#include <math.h>
#include <SDL2/SDL.h>

#define PI 3.1415926535

using namespace std;

SDL_Event event;
SDL_Window* window;
SDL_Renderer* renderer;
SDL_Surface* surface;
float pdX, pdY, pA;
bool RunState;
int vel = 10;
int mapX = 8, mapY = 9, mapS = 64;
SDL_Rect tileRect = {0, 0, 64, 64};
int map[] = 
{
    1,1,1,1,1,1,1,1,
    1,0,0,0,1,0,0,1,
    1,0,1,1,0,0,0,1,
    1,0,1,0,0,0,0,1,
    1,0,0,0,0,1,0,1,
    1,0,0,0,1,1,0,1,
    1,0,0,0,0,0,0,1,
    1,1,1,1,1,1,1,1,
};

class Player{
    public:
        SDL_Rect dest = {100, 100, 10, 10};
};

Player player;

void DrawRay3d()
{
    int r, mx, my, mp, dof;
    float rx, ry, ra, xo, yo;
    ra = pA;
    for(r = 0; r > -1; r--)
    {
        dof = 0;
        float aTan = -1/tan(ra);
        if(ra>PI)
        {
            ry = (((int)pdY/64)*64)-0.0001;
            rx = (pdY-ry)*aTan+pdX;
            yo = -64;
            xo= -yo*aTan;
        }
        if(ra<PI)
        {
            ry = (((int)pdY/64)*64)+64;
            rx = (pdY-ry)*aTan+pdX;
            yo = 64;
            xo= -yo*aTan;
        }
        if(ra==0 || ra==PI)
        {
            rx = pdX;
            ry = pdY;
            dof = 8;
        }
        while(dof<8)
        {
            mx = (int)(rx)/64;
            my = (int)(ry)/64;
            mp = my*mapX+mx;
            if(mp<mapX*mapY && map[mp]==1)
            {
                dof = 8;
            }
            else{
                rx += xo;
                ry += yo;
                dof +=1;
            }
        }
        SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255);
        SDL_RenderDrawLine(renderer, player.dest.x+player.dest.w/2+pdX*5, player.dest.y+player.dest.h/2+pdY*5, rx, ry);
    }
}

void Drawmap()
{
    for(int y = 0; y < mapY; y++)
    {
        for(int x = 0; x < mapX; x++)
        {
            if(map[y*mapX+x]==1) 
            {
                SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
                tileRect.x = x*64;
                tileRect.y = y*64;
                SDL_RenderFillRect(renderer, &tileRect);

                SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
                SDL_RenderDrawLine(renderer, x*64, y*64, x*64 + 64, y*64);
                SDL_RenderDrawLine(renderer, x*64+64, y*64, x*64 + 64, y*64 + 64);
                SDL_RenderDrawLine(renderer, x*64 + 64, y*64 + 64, x*64, y*64 + 64);
                SDL_RenderDrawLine(renderer, x*64, y*64 + 64, x*64, y*64);
            }
            else if(map[y*mapX+x]==0) 
            {
                SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
                tileRect.x = x*64;
                tileRect.y = y*64;
                SDL_RenderFillRect(renderer, &tileRect);

                SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
                SDL_RenderDrawLine(renderer, x*64, y*64, x*64 + 64, y*64);
                SDL_RenderDrawLine(renderer, x*64+64, y*64, x*64 + 64, y*64 + 64);
                SDL_RenderDrawLine(renderer, x*64 + 64, y*64 + 64, x*64, y*64 + 64);
                SDL_RenderDrawLine(renderer, x*64, y*64 + 64, x*64, y*64);
            }
        }
    }
}

int main(int argc, char* args[]){

    //Initialize window
    SDL_Init(SDL_INIT_EVERYTHING);
    window = SDL_CreateWindow("RayCastin'", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1024, 512, SDL_WINDOW_ALLOW_HIGHDPI);
    if(window)
    {
        renderer = SDL_CreateRenderer(window, -1, 0);
        if(renderer)
        {
            RunState = true;
            surface = SDL_GetWindowSurface(window);
        }
    }

    //Looping
    while(RunState)
    {
        //Handel event
        SDL_PollEvent(&event);
        if(event.type == SDL_QUIT)
        {
            RunState = false;
        }
        if(event.type == SDL_KEYDOWN)
        {
            switch (event.key.keysym.sym){
                case SDLK_UP:
                    player.dest.y+=pdY;
                    player.dest.x+=pdX;
                    break;
                case SDLK_DOWN:
                    player.dest.y-=pdY;
                    player.dest.x-=pdX;
                    break;
                case SDLK_LEFT:
                    pA-=0.1;
                    if(pA<0) pA+=2*PI;
                    pdX=cos(pA)*vel; pdY = sin(pA)*vel;
                    break;
                case SDLK_RIGHT:
                    pA+=0.1;
                    if(pA>2*PI) pA-=2*PI;
                    pdX=cos(pA)*vel; pdY = sin(pA)*vel;
                    break;
            }
        }

        //Render
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        SDL_RenderClear(renderer);
        
        Drawmap();
        DrawRay3d();

        SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
        SDL_RenderFillRect(renderer, &player.dest);
        SDL_RenderDrawLine(renderer, player.dest.x+player.dest.w/2, player.dest.y+player.dest.h/2,  player.dest.x+player.dest.w/2+pdX*5, player.dest.y+player.dest.h/2+pdY*5);
        SDL_RenderPresent(renderer);
    }

    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    window = NULL;
    renderer = NULL;

    return 0;
}

感谢您的宝贵时间!!!

我已经尝试修复崩溃错误,因为当程序试图读取或写入非法内存位置时会发生错误,但我真的不知道是哪个变量导致的。老实说,我还没有完全理解算法,因为我所做的只是复制,但我希望从一个地方到另一个地方学到更多。

c++ graphics sdl sdl-2 raycasting
1个回答
0
投票

我真的没有你的问题的答案。 但是我发现您的代码存在一些严重的问题。

  1. 你应该尽量只在使用变量的地方声明变量。

  2. 然后你应该初始化所有变量。

  3. 如果你没有为你的指针进行适当的初始化,只需使用 nullptr 初始化它们。试着给你的变量起有意义的名字。 x, y, rx, ... 似乎是错误的,很难区分它们。

  4. 也尽量避免使用命名空间标准。原因如下:Avoid using namespace std!

  5. 我看到唯一的程序缺陷是由您的某些语句引起的精度损失。也许这会导致错误?

    ry = (((int)pdY/64)*64)-0.0001;例如,此表达式使用整数除法,因此省略了精度。

         if(ra==0 || ra==PI)
    

这个表达式容易出错。尽量不要与浮点数进行比较。这通常不起作用。您几乎总是想引入数字跨度,以便可以使用 epsilon 正确比较它们。如果您想知道这是如何工作的。这里有一些适合初学者的介绍:

LearnCPP.com

计算器

© www.soinside.com 2019 - 2024. All rights reserved.