2

here's my code, ignore unused stuff and its overal messiness

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()

so far, it's behaving this way:

faulty raycasting

it works, but it doesn't. i've tinkered the numbers, sometimes it gets better adding to the x, to the y, but it doesn't work completely. If you guys wanna try on your computer, here are the files needed for: map

ball

(it's tiny) so, what's going on?

felipebubu
  • 131
  • 7
  • It looks to me like the depth is causing the ray to step over the wall, have you tested with a thicker wall or shorter depth increments than 1? – Alex V Nov 16 '21 at 03:30
  • I tried messing with the depth, but it didn't work either. Now, what worked: apparently, I forgot of my own character and some of the rays was bugging because of it, no idea how yet phew.. but now the performance is atrocious when more than four characters are in the map, not sure what to do, not sure if it's because it's python – felipebubu Nov 16 '21 at 04:20
  • @felipebubu It seems the color of the walls is not exactly (223, 113, 38) in this area. – Rabbid76 Nov 16 '21 at 06:01
  • @felipebubu An easy optimization is to calculate ray direction per ray, not for every increment along the depth. Another is to only draw the rays once it reaches its target, i.e. after `break` is triggered. –  Nov 16 '21 at 18:32

1 Answers1

1

You need to read the color of the map instead of the color of the screen. You draw the lines on the screen, each line "cuts a small piece of the wall:

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):

Alternatively you can draw the lines after casting the rays:

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)

Rabbid76
  • 202,892
  • 27
  • 131
  • 174