为什么我的光线投射一直穿过墙壁?

Why my raycasting keeps going through walls?

这是我的代码,忽略未使用的内容及其整体混乱

import sys, pygame, time, math

pygame.init()

size = width, height = 640, 640
black = 0, 0, 0
screen = pygame.display.set_mode(size)

ball = pygame.image.load("ball.png")
map = pygame.image.load("map.png")

ballrect = ball.get_rect()
ballrect.x = 262
ballrect.y = 582

direction = math.pi
FOV = math.pi / 3
HALF_FOV = FOV / 2
CASTED_ARRAYS = 640
STEP_ANGLE = FOV / CASTED_ARRAYS
MAX_DEPTH = 640

def cast_rays():
    start_angle = direction - HALF_FOV

    for ray in range(CASTED_ARRAYS):
        for depth in range(MAX_DEPTH):
            target_x = (ballrect.centerx) - math.sin(start_angle) * depth
            target_y = (ballrect.centery) + math.cos(start_angle) * depth
            if screen.get_at((int(target_x), int(target_y))) == (223, 113, 38):
                pygame.draw.line(screen, (0, 255, 255), (ballrect.centerx, ballrect.centery),
                                 (target_x, target_y))
                break
        start_angle += STEP_ANGLE


while 1:
    screen.blit(map, (0, 0))
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        direction -= 0.1
    if keys[pygame.K_RIGHT]:
        direction += 0.1
    if keys[pygame.K_UP]:
        ballrect.centerx += -math.sin(direction) * 5
        ballrect.centery += math.cos(direction) * 5
    if keys[pygame.K_DOWN]:
        ballrect.centerx -= -math.sin(direction) * 5
        ballrect.centery -= math.cos(direction) * 5
    time.sleep(0.01)
    screen.blit(ball, ballrect)
    cast_rays()
    pygame.display.flip()
    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            sys.exit()

到目前为止,它的行为是这样的:

有效,但无效。我修改了数字,有时它会更好地添加到 x 和 y,但它并不完全有效。如果你们想在您的计算机上尝试,这里是需要的文件:

(很小) 那么,这是怎么回事?

您需要阅读地图的颜色,而不是屏幕的颜色。你在屏幕上画线,每条线“切一小块墙:

if screen.get_at((int(target_x), int(target_y))) == (223, 113, 38):

if map.get_at((int(target_x), int(target_y))) == (223, 113, 38):

或者您可以在投射光线后绘制线条:

def cast_rays():
    targets = []
    for ray in range(CASTED_ARRAYS):
        angle = direction - HALF_FOV + ray * STEP_ANGLE
        s, c =  math.sin(angle), math.cos(angle)
        for depth in range(MAX_DEPTH):
            target = (round(ballrect.centerx - s * depth), round(ballrect.centery + c * depth))
            if screen.get_at(target) == (223, 113, 38):
                targets.append(target)
                break
    
    start = (ballrect.centerx, ballrect.centery)
    for target in targets:
        pygame.draw.line(screen, (0, 255, 255), start, target)