diff --git a/boom.py b/boom.py index c5e6e87..b682a47 100644 --- a/boom.py +++ b/boom.py @@ -1,10 +1,16 @@ import pygame import math +import functools wall_texture_path = 'wall.png' floor_texture_path = 'floor.png' sky_texture_path = 'sky.png' +# 3 functions to cache the calculated trig values +cached_sin = functools.cache(math.sin) +cached_cos = functools.cache(math.cos) +cached_tan = functools.cache(math.tan) + world = [ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], @@ -40,8 +46,8 @@ def lighting(screen, doomguy_pos, doomguy_vector): main_vector = doomguy_vector - (math.pi / 3) / 2 + 0.1 for ray in range(800): - sin_a = math.sin(main_vector) - cos_a = math.cos(main_vector) + sin_a = cached_sin(main_vector) + cos_a = cached_cos(main_vector) y_hor, dy = (y_map + 1, 1) if sin_a > 0 else (y_map - 1e-6, -1) @@ -80,9 +86,9 @@ def lighting(screen, doomguy_pos, doomguy_vector): else: depth = depth_hor - depth *= math.cos(doomguy_vector - main_vector) + depth *= cached_cos(doomguy_vector - main_vector) - proj_height = 800 / math.tan((math.pi / 3) / 2) / (depth + 0.0001) + proj_height = 800 / cached_tan((math.pi / 3) / 2) / (depth + 0.0001) color = [255 / (1 + depth ** 5 * 0.00002)] * 3 pygame.draw.rect(screen, color, (ray * scale, 540 - proj_height // 2, scale, proj_height)) @@ -108,8 +114,8 @@ def check_wall_collision(x, y): if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key == pygame.K_q): pygame.quit() - sin_a = math.sin(doomguy_vector) - cos_a = math.cos(doomguy_vector) + sin_a = cached_sin(doomguy_vector) + cos_a = cached_cos(doomguy_vector) dx, dy = 0, 0 speed = doomguy_speed * dt speed_sin = speed * sin_a diff --git a/boom_test_file.py b/boom_test_file.py new file mode 100644 index 0000000..70a7819 --- /dev/null +++ b/boom_test_file.py @@ -0,0 +1,158 @@ +import pygame +import math +import timeit + +wall_texture_path = 'wall.png' +floor_texture_path = 'floor.png' +sky_texture_path = 'sky.png' + +world = [ + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1], + [1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1], + [1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1], + [1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1], + [1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1], + [1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1], + [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], +] + +walls = {} + +for l, row in enumerate(world): + for n, value in enumerate(row): + if value: + walls[(n, l)] = value + + +doomguy_pos = 1.5, 5 +doomguy_vector = 0 +doomguy_speed = 2 +doomguy_sens = 2 +fov = math.pi / 3 +scale = 1600 // 600 + +code_without_cache = """ +def lighting(screen, doomguy_pos, doomguy_vector): + ox, oy = doomguy_pos + x_map, y_map = int(ox), int(oy) + + main_vector = doomguy_vector - (math.pi / 3) / 2 + 0.1 + for ray in range(800): + sin_a = math.sin(main_vector) + cos_a = math.cos(main_vector) + + y_hor, dy = (y_map + 1, 1) if sin_a > 0 else (y_map - 1e-6, -1) + + depth_hor = (y_hor - oy) / sin_a + x_hor = ox + depth_hor * cos_a + + delta_depth = dy / sin_a + dx = delta_depth * cos_a + + for i in range(20): + tile_hor = int(x_hor), int(y_hor) + if tile_hor in walls: + break + x_hor += dx + y_hor += dy + depth_hor += delta_depth + + x_vert, dx = (x_map + 1, 1) if cos_a > 0 else (x_map - 1e-6, -1) + + depth_vert = (x_vert - ox) / cos_a + y_vert = oy + depth_vert * sin_a + + delta_depth = dx / cos_a + dy = delta_depth * sin_a + + for i in range(20): + tile_vert = int(x_vert), int(y_vert) + if tile_vert in walls: + break + x_vert += dx + y_vert += dy + depth_vert += delta_depth + + if depth_vert < depth_hor: + depth = depth_vert + else: + depth = depth_hor + + depth *= math.cos(doomguy_vector - main_vector) + + proj_height = 800 / math.tan((math.pi / 3) / 2) / (depth + 0.0001) + + color = [255 / (1 + depth ** 5 * 0.00002)] * 3 + pygame.draw.rect(screen, color, (ray * scale, 540 - proj_height // 2, scale, proj_height)) + + main_vector += (math.pi / 3) / 800 +""" + +code_with_cache = """ +def lighting(screen, doomguy_pos, doomguy_vector): + ox, oy = doomguy_pos + x_map, y_map = int(ox), int(oy) + + main_vector = doomguy_vector - (math.pi / 3) / 2 + 0.1 + for ray in range(800): + sin_a = cached_sin(main_vector) + cos_a = cached_cos(main_vector) + + y_hor, dy = (y_map + 1, 1) if sin_a > 0 else (y_map - 1e-6, -1) + + depth_hor = (y_hor - oy) / sin_a + x_hor = ox + depth_hor * cos_a + + delta_depth = dy / sin_a + dx = delta_depth * cos_a + + for i in range(20): + tile_hor = int(x_hor), int(y_hor) + if tile_hor in walls: + break + x_hor += dx + y_hor += dy + depth_hor += delta_depth + + x_vert, dx = (x_map + 1, 1) if cos_a > 0 else (x_map - 1e-6, -1) + + depth_vert = (x_vert - ox) / cos_a + y_vert = oy + depth_vert * sin_a + + delta_depth = dx / cos_a + dy = delta_depth * sin_a + + for i in range(20): + tile_vert = int(x_vert), int(y_vert) + if tile_vert in walls: + break + x_vert += dx + y_vert += dy + depth_vert += delta_depth + + if depth_vert < depth_hor: + depth = depth_vert + else: + depth = depth_hor + + depth *= cached_cos(doomguy_vector - main_vector) + + proj_height = 800 / cached_tan((math.pi / 3) / 2) / (depth + 0.0001) + + color = [255 / (1 + depth ** 5 * 0.00002)] * 3 + pygame.draw.rect(screen, color, (ray * scale, 540 - proj_height // 2, scale, proj_height)) + + main_vector += (math.pi / 3) / 800 +""" + + +# performance before cache implementation +print("\nperformance before cache implementation:") +print(timeit.timeit(stmt=code_without_cache, number=1)) +# performance after cache implementation +print("\nperformance after cache implementation:") +print(timeit.timeit(stmt=code_with_cache, number=1)) \ No newline at end of file