-
Notifications
You must be signed in to change notification settings - Fork 0
/
raycasting.py
97 lines (80 loc) · 3.67 KB
/
raycasting.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import pygame as pg
import math
import settings
class RayCasting:
def __init__(self, game) -> None:
self.game = game
def get_objects_to_render(self):
self.objects_to_render = []
for ray, values in enumerate(self.ray_casting_result):
depth, proj_height, texture, offset = values
if proj_height < settings.HEIGHT:
wall_column = self.textures[texture].subsurface(
offset * (settings.TEXTURE_SIZE - settings.SCALE), 0, settings.SCALE, settings.TEXTURE_SIZE
)
wall_column = pg.transform.scale(wall_column, (settings.SCALE, proj_height))
wall_pos = (ray * settings.SCALE, settings.HALF_HEIGHT - proj_height // 2)
else:
texture_height = settings.TEXTURE_SIZE * settings.HEIGHT / proj_height
wall_column = self.textures[texture].subsurface(
offset * (settings.TEXTURE_SIZE - settings.SCALE), settings.HALF_TEXTURE_SIZE - texture_height // 2,
settings.SCALE, texture_height
)
wall_column = pg.transform.scale(wall_column, (settings.SCALE, settings.HEIGHT))
wall_pos = (ray * settings.SCALE, 0)
self.objects_to_render.append((depth, wall_column, wall_pos))
def ray_cast(self):
self.ray_casting_result = []
ox, oy = self.game.player.pos
x_map, y_map = self.game.player.map_pos
texture_vert, texture_hor = 1, 1
self.objects_to_render = []
self.textures = self.game.object_renderer.textures
ray_angle = self.game.player.angle - settings.HALF_FOV + 0.0001
for ray in range(settings.NUM_RAYS):
sin_a = math.sin(ray_angle)
cos_a = math.cos(ray_angle)
# horiz
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(settings.MAX_DEPTH):
tile_hor = int(x_hor), int(y_hor)
if tile_hor in self.game.map.world_map:
texture_hor = self.game.map.world_map[tile_hor]
break
x_hor += dx
y_hor += dy
depth_hor += delta_depth
# verts
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(settings.MAX_DEPTH):
tile_vert = int(x_vert), int(y_vert)
if tile_vert in self.game.map.world_map:
texture_vert = self.game.map.world_map[tile_vert]
break
x_vert += dx
y_vert += dy
depth_vert += delta_depth
# depth
if depth_vert < depth_hor:
depth, texture = depth_vert, texture_vert
y_vert %= 1
offset = y_vert if cos_a > 0 else (1 - y_vert)
else:
depth, texture = depth_hor, texture_hor
x_hor %= 1
offset = (1 - x_hor) if sin_a > 0 else x_hor
depth *= math.cos(self.game.player.angle - ray_angle)
proj_height = settings.SCREEN_DIST / (depth + 0.0001)
self.ray_casting_result.append((depth, proj_height, texture, offset))
ray_angle += settings.DELTA_ANGLE
def update(self):
self.ray_cast()
self.get_objects_to_render()