import pygame import sys import math SCREEN_HEIGHT=480 SCREEN_WIDTH=SCREEN_HEIGHT * 2 MAP_SIZE=8 TILE_SIZE=int((SCREEN_WIDTH / 2) / MAP_SIZE) FOV=math.pi / 3 HALF_FOV = FOV / 2 CASTED_RAYS=30 STEP_ANGLE = FOV / CASTED_RAYS MAX_DEPTH = int(MAP_SIZE * TILE_SIZE) SCALE = (SCREEN_WIDTH / 2) / CASTED_RAYS player_x = (SCREEN_WIDTH/2)/2 player_y = (SCREEN_WIDTH/2)/2 player_angle = math.pi MAP = ('########' '# # #' '# # ###' '# #' '## #' '# ### #' '# # #' '########') pygame.init() win = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT)) pygame.display.set_caption("Ray-Casting") clock = pygame.time.Clock() def draw_map(): light_grey = (191, 191, 191) dark_grey = (65,65,65) for i in range(MAP_SIZE): for j in range(MAP_SIZE): square = i * MAP_SIZE + j pygame.draw.rect(win, light_grey if MAP[square] == '#' else dark_grey, (j * TILE_SIZE, i * TILE_SIZE, TILE_SIZE -1, TILE_SIZE - 1)) def ray_casting(): # left angle of FOV start_angle = player_angle - HALF_FOV for ray in range(CASTED_RAYS): for depth in range(1,MAX_DEPTH): target_x = player_x - math.sin(start_angle) * depth target_y = player_y + math.cos(start_angle) * depth col = int(target_x / TILE_SIZE) row = int(target_y / TILE_SIZE) square = row * MAP_SIZE + col if MAP[square] == '#': pygame.draw.rect(win, (195, 137, 38), (col * TILE_SIZE, row * TILE_SIZE, TILE_SIZE -1, TILE_SIZE-1)) pygame.draw.line(win, (233, 166, 49), (player_x, player_y), (target_x, target_y)) # wall shading color = 255 / (1 + depth * depth * 0.0001) # fix fish eye effect depth *= math.cos(player_angle - start_angle) # calculate wall height wall_height = 21000 / (depth) if wall_height > SCREEN_HEIGHT: wall_height = SCREEN_HEIGHT pygame.draw.rect(win, (color, color, color), (SCREEN_HEIGHT + ray * SCALE, (SCREEN_HEIGHT / 2) - wall_height/2, SCALE, wall_height)) break start_angle += STEP_ANGLE while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit(0) # update 2d background pygame.draw.rect(win, (0,0,0), (0, 0, SCREEN_HEIGHT, SCREEN_HEIGHT)) # update 3d background pygame.draw.rect(win, (100, 100, 100), (480, SCREEN_HEIGHT / 2, SCREEN_HEIGHT, SCREEN_HEIGHT)) pygame.draw.rect(win, (200, 200, 200), (480, -SCREEN_HEIGHT / 2, SCREEN_HEIGHT, SCREEN_HEIGHT)) draw_map() ray_casting() keys = pygame.key.get_pressed() if keys[pygame.K_LEFT]: # working with radians, not degrees player_angle -= 0.1 elif keys[pygame.K_RIGHT]: player_angle += 0.1 elif keys[pygame.K_UP]: forward = True player_x += -1 * math.sin(player_angle) * 5 player_y += math.cos(player_angle) * 5 elif keys[pygame.K_DOWN]: forward = False player_x -= -1 * math.sin(player_angle) * 5 player_y -= math.cos(player_angle) * 5 # update the display pygame.display.flip() clock.tick(30)