-
Notifications
You must be signed in to change notification settings - Fork 0
/
raycasting.py
122 lines (90 loc) · 4.37 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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
import pygame as pg
import math
from settings import *
class RayCasting:
def __init__(self,game):
self.game = game
self.ray_casting_result = []
self.object_to_render = []
self.textures = self.game.object_renderer.wall_texture
def get_object_to_render(self):
self.object_to_render = []
for ray, values in enumerate(self.ray_casting_result):
depth,proj_height,texture, offset = values
if proj_height < HEIGHT:
wall_column = self.textures[texture].subsurface(
offset * (TEXTURE_SIZE - SCALE),0,SCALE,TEXTURE_SIZE
)
wall_column = pg.transform.scale(wall_column,(SCALE,proj_height))
wall_pos = (ray * SCALE, HALF_HEIGHT - proj_height // 2)
else :
texture_height = TEXTURE_SIZE * HEIGHT / proj_height
wall_column = self.textures[texture].subsurface(
offset * (TEXTURE_SIZE - SCALE), HALF_TEXTURE_SIZE - texture_height //2 ,
SCALE , texture_height
)
wall_column = pg.transform.scale(wall_column,(SCALE,HEIGHT))
wall_pos = (ray * SCALE, 0)
self.object_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
ray_angle = self.game.player.angle - HALF_FOV + 0.0001
for ray in range(NUM_RAYS):
sin_a = math.sin(ray_angle)
cos_a = math.cos(ray_angle)
# Horizontals
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(MAX_DEPTH):
title_hor = int(x_hor) , int(y_hor)
if title_hor in self.game.map.world_map:
texture_hor = self.game.map.world_map[title_hor]
break
x_hor +=dx
y_hor +=dy
depth_hor += delta_depth
#verticals
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(MAX_DEPTH):
title_vert = int(x_vert) , int(y_vert)
if title_vert in self.game.map.world_map:
texture_vert = self.game.map.world_map[title_vert]
break
x_vert +=dx
y_vert +=dy
depth_vert += delta_depth
#depth , texture offsett
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
# draw for debug
# pg.draw.line(self.game.screen , 'yellow',(100 * ox, 100 * oy),
# (100 * ox + 100 * depth * cos_a, 100 * oy +100 * depth *sin_a),2)
# Removing Fish Bowl Effect
depth *= math.cos(self.game.player.angle - ray_angle)
# Projection
proj_height = SCREEN_DIST / (depth + 0.0001)
# # Draw WAlls:
# color = [255 / (1 + depth ** 5 * 0.00002)] * 3
# pg.draw.rect(self.game.screen,color,(ray * SCALE , HALF_HEIGHT - proj_height //2 , SCALE , proj_height))
# Ray Casting Result
self.ray_casting_result.append((depth,proj_height,texture,offset))
ray_angle += DELTA_ANGLE
def update(self):
self.ray_cast()
self.get_object_to_render()