修复射线投射算法

huangapple go评论63阅读模式
英文:

Fixing Ray-Casting algorithm

问题

I can help you translate the text you provided. Here it is:

"我一直在尝试练习射线投射算法。我面临两个问题:

  1. 我的投射射线与玩家的视点不对齐,错误地表示了投射射线的特征(例如,如果撞到墙壁,它会变短)。
  2. 有时我的程序会崩溃,显示错误消息'Error -1073741819'。

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

射线投射问题

程序崩溃

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

Please note that I've only translated the text and didn't include code translations. If you need any specific parts of the code translated, please let me know.

英文:

I've been trying to practice Ray-casting algorithm. I'm facing 2 problems:

  1. My casting ray does not align with the player's point of view and represent incorrectly the feature of a casting ray(ex: it will get short if hit a wall)
  2. Sometime my program get crashed with this 'Error -1073741819' message.

Here are some pictures for my problem:

Ray-cast problem

Program crashed

Here is my code using SDL library and C++ in VSC:

#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;
}

答案1

得分: 1

I see some serious problems with your code:

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

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

  3. 如果你的指针没有合适的初始化,可以用 nullptr 来初始化它们。尽量给变量取有意义的名字,使用 x、y、rx 等名字似乎不太合适,而且很难区分它们。

  4. 也尽量避免使用 namespace std,原因在于:避免使用 namespace std

  5. 我看到唯一的程序缺陷是一些语句导致的精度损失,也许这导致了错误?

    ry = (((int)pdY/64)*64)-0.0001; 例如,这个表达式使用整数除法,因此会损失精度。

    if(ra==0 || ra==PI) 这个表达式容易出错。尽量不要与浮点数进行比较,通常不起作用。你几乎总是希望引入一个数值范围,这样可以使用 epsilon 进行正确比较。如果想了解这是如何工作的,这里有一些初学者友好的介绍:

    LearnCPP.com

    Stackoverflow

英文:

I don't have an answer to your question really.
But I see some serious problems with your code.

  1. You should try to declare variables only in places where they are used.

  2. Then you should initialize all variables.

  3. If you don't have a proper initialization for you pointers, just initialize them with nullptr. Try to give your variables meaningful names. x, y, rx, ... just seems wrong and trying to distinguish between them is hard.

  4. Try also avoiding using namespace std. Here is why: Avoid using namespace std!

  5. The only programmatic flaw I see the loss of precision that is caused by some of your statements. Maybe that results in the error?

    ry = (((int)pdY/64)*64)-0.0001; This expression for example uses integer division and therefore omits precision.

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

This expression is error-prone. Try not to compare to floating point numbers. This generally does not work. You almost always want to introduce a number span, so they can be compared properly using an epsilon. If you want to know how this works. Here are some beginner-friendly introductions:

LearnCPP.com

Stackoverflow

huangapple
  • 本文由 发表于 2023年5月6日 17:11:10
  • 转载请务必保留本文链接:https://go.coder-hub.com/76188079.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定