Exploring raycasters and possibly make a little "doom like" game based on it.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
raycaster/pycaster.py

126 lines
3.5 KiB

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)