Ray-Casting算法实现求助:射线对齐异常与程序崩溃问题
Ray-Casting算法实现问题求助
我正在练习实现Ray-Casting算法,目前遇到两个问题:
- 投射的射线与玩家视角不对齐,且无法正确表现射线特性(例如碰到墙时不会变短);
- 程序偶尔崩溃,报错信息为
Error -1073741819。
以下是我用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; float pX = player.dest.x + player.dest.w/2; float pY = player.dest.y + player.dest.h/2; // 64条射线,覆盖60度视野(从视角左30度到右30度) for(r = 0; r < 64; r++) { ra = pA - PI/6 + (PI/3)*r/64; // 计算当前射线角度 dof = 0; float aTan = -1/tan(ra); if(ra > PI) { ry = (((int)pY/64)*64) - 0.0001; rx = (pY - ry)*aTan + pX; yo = -64; xo = -yo*aTan; } if(ra < PI) { ry = (((int)pY/64)*64) + 64; rx = (pY - ry)*aTan + pX; yo = 64; xo = -yo*aTan; } if(ra == 0 || ra == PI) { rx = pX; ry = pY; dof = 8; } while(dof < 8) { mx = (int)(rx)/64; my = (int)(ry)/64; mp = my*mapX + mx; // 防止数组越界 if(mp >= 0 && 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, pX, pY, 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); // 初始化玩家方向:朝向上方(PI/2对应90度) pA = PI/2; pdX = cos(pA)*vel; pdY = sin(pA)*vel; } } //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: // SDL y轴向下,向上移动需减去pdY 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; }
问题解决说明
- 修复程序崩溃:将
DrawRay3d中的无限循环改为固定数量的射线遍历(64条),同时计算每条射线对应的视野角度,避免程序卡死。 - 射线对齐与碰撞检测修复:
- 改用玩家中心坐标
pX/pY计算射线起点和网格交点,替换之前错误使用的速度分量pdX/pdY; - 修正射线绘制的起点为玩家中心,确保射线从玩家位置出发;
- 添加方向变量初始化,避免初始方向随机;
- 修正移动逻辑,适配SDL的y轴方向,确保移动方向与视角一致;
- 碰撞检测时增加数组越界判断,防止访问非法内存。
- 改用玩家中心坐标
内容的提问来源于stack exchange,提问作者Gia Khánh
相关产品推荐
相关产品推荐

