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.
126 lines
3.5 KiB
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)
|
|
|