德尔福转换Lode的无纹理raycaster抛出零分割错误

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

所以我一直在编写一个delphi转换的this无纹理raycaster。但是,在检查错误时,我注意到如果您直接向前走,则会发生零分割错误。这是有道理的,因为当它确实发生时,摄像机位于墙内,因此摄像机与该墙之间的垂直距离为零。然而,对我来说没有意义的是,能够向前移动的检查应该阻止玩家进入墙壁。更令人困惑的是,错误只发生在前进而不是后退时(即使为每个步骤完成的测试基本相同)。从调试开始,我发现错误只发生在摄像机处于起始旋转状态时。我试图通过将绘制的线的高度设置为480(屏幕大小)来解决问题,并且在停止程序崩溃的同时,你会得到这个error,你可以穿过墙壁。 tldr,raycaster抛出零分错误,我不知道如何解决它,请帮忙。 Source code 编辑:这是源代码的必需部分:

procedure TForm1.ScreenRender();
var
 Count : Integer;

CameraX : Double;
rayPosX : Double;
rayPosY : Double;
rayDirX : Double;
rayDirY : Double;

mapX        : Integer;
mapY        : Integer;
sideDistX   : Double;
sideDistY   : Double;
deltaDistX  : Double;
deltaDistY  : Double;
perpWallDist: Double;
stepX       : Integer;
stepY       : Integer;
hit         : Integer;
side        : Integer;

lineHeight  : Integer;
drawStart   : Integer;
drawEnd     : Integer;
begin
  for Count := 0 to 639 do
  begin

CameraX := 2 * Count/639-1;
rayPosX := posX;
rayPosY := posY;                               
rayDirX := dirX + planeX * CameraX;
rayDirY := dirY + planeY * CameraX;

mapX := Trunc(rayPosX);
mapY := Trunc(rayPosY);
deltaDistX := sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX));
deltaDistY := sqrt(1 + (rayDirX * rayDirX) / (rayDirY * rayDirY));
hit := 0;

if(rayDirX < 0) then
begin
  stepX:=-1;
  sideDistX := (rayPosX - mapX) * deltaDistX;
end

else                                                                        
begin                                                              
  stepX := 1;
  sideDistX := (mapX + 1 - rayPosX) * deltaDistX;
end;

if(rayDirY < 0) then
begin
  stepY:=-1;
  sideDistY := (rayPosY - mapY) * deltaDistY ;
end

else
begin
  stepY:=1;
  sideDistY := (mapY + 1 - rayPosY) * deltaDistY;
end;

while(hit = 0) do
begin
  if(sideDistX < sideDistY) then
  begin
    sideDistX := sideDistX + deltaDistX;
    mapX := mapX + stepX;
    side := 0;
  end

  else
  begin
    sideDistY := sideDistY + deltaDistY;
    mapY := mapY + stepY;
    side:= 1;
  end;

  if(MapData[mapX,mapY] > 0) then
    hit := 1;
end;


if(side = 0) then
  perpWallDist := (mapX - rayPosX + (1 - stepX) / 2) / rayDirX
else
  perpWallDist := (mapY - rayPosY + (1 - stepY) / 2) / rayDirY;


    //the error is here
    //as the camera is in the wall and perpWallDist is 0, a zero division error is thrown
  //if(perpWallDist > 0) then
    lineHeight := Trunc(480 /perpWallDist);
  //else
  //  lineHeight := 480;
drawStart := round(-lineHeight / 2 + 480 / 2);
if(drawStart < 0) then
  drawStart := 0;                                                           
drawEnd := round(lineHeight / 2 + 480 / 2);
if(drawEnd >= 480) then
  drawEnd := 480;                                                                 

case MapData[mapX,mapY] of                                                                    
  1: image1.Canvas.Pen.Color := $ff0000;
  2: image1.Canvas.Pen.Color := $0000ff;
  3: image1.Canvas.Pen.Color := $00ff00;
  4: image1.Canvas.Pen.Color := $ffffff;
end;

if(side = 1) then
  image1.Canvas.Pen.Color := round( image1.Canvas.Pen.Color / 1.5);

image1.Canvas.MoveTo(Count,drawStart);                                         
image1.Canvas.LineTo(Count,drawEnd);

end;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: 
TShiftState);
const
moveSpeed = 0.5;
rotSpeed = 0.25;
var                                                                               
oldDirX    : Double;
oldPlaneX  : Double;
begin                                                                                        
if(Key = $57) and (MovAllow = true) then
begin
if(MapData[trunc(posX + dirX * moveSpeed),trunc(posY)] = 0) then
  posX := posX + (dirX * moveSpeed);
if(MapData[trunc(posX),trunc(posY + dirY * moveSpeed)] = 0) then
  posY := posY + (dirY * moveSpeed);
end;                                                                                    

if(Key = $53) and (MovAllow = true) then
begin
if(MapData[trunc(posX - dirX * moveSpeed),trunc(posY)] = 0) then
  posX := posX - (dirX * moveSpeed);
if(MapData[trunc(posX),trunc(posY - dirY * moveSpeed)] = 0) then
  posY := posY - (dirY * moveSpeed);                                                    
end;


if(Key = $44) and (MovAllow = true) then
begin
oldDirX := dirX;
dirX := dirX * cos(-rotSpeed) - dirY * sin(-rotSpeed);
dirY := oldDirX * sin(-rotSpeed) + dirY * cos(-rotSpeed);
oldPlaneX := planeX;
planeX := planeX * cos(-rotSpeed) - planeY * sin(-rotSpeed);
planeY := oldPlaneX * sin(-rotSpeed) + planeY * cos(-rotSpeed);
end;

if(Key = $41) and (MovAllow = true) then
begin
oldDirX := dirX;
dirX := dirX * cos(rotSpeed) - dirY * sin(rotSpeed);
dirY := oldDirX * sin(rotSpeed) + dirY * cos(rotSpeed);
oldPlaneX := planeX;
planeX := planeX * cos(rotSpeed) - planeY * sin(rotSpeed);
planeY := oldPlaneX * sin(rotSpeed) + planeY * cos(rotSpeed);
end;


end;

编辑2:dirX和dirY仅在按下'A'或'D'时改变(键= $ 41是A,键= $ 44是D)。它们使用旋转矩阵进行更改。它们的代码改变就在代码底部的编辑之上。从调试开始,我发现如果你走直线就不会改变(这是预期的)。我还发现,如果你在一个方向稍微旋转相机,然后将其旋转回看起来像起始旋转,即使dirX和dirY值略有不同(而不是初始值,它们有dirX = -1和dirY = 1.98408997564847E-0017)它仍会导致同样的崩溃。我认为这是因为它们几乎是相同的值。

delphi delphi-7 raycasting divide-by-zero
1个回答
1
投票

只需在调试器中运行程序,Delphi就会告诉您错误发生在哪一行。

即使没有它,您也可以检查所有划分的地方是否安全。

看看这一行:

deltaDistX := sqrt(1 + (rayDirY * rayDirY) / (rayDirX * rayDirX));

当rayDir为0时会发生什么?

perpWallDist := (mapX - rayPosX + (1 - stepX) / 2) / rayDirX

当rayDir为0时会发生什么?

lineHeight := Trunc(480 /perpWallDist);

当perpWallDist为0时会发生什么?

更新为什么perpWallDist可以为0?好吧,在设置它的地方放置一个断点,并查看用于设置变量的值。

perpWallDist := (mapX - rayPosX + (1 - stepX) / 2) / rayDirX

其余的我无法帮助你。这只是一个简单的调试问题。如果你在某个地方遇到了这个过程,那就创建一个关于你遇到的问题的单独问题。

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