Basic Raycasting With Python
3D Raycasting Engine
This project is a simple implementation of a 3D raycasting engine using Python and the Pygame library. Raycasting is a technique used to create 3D world simulations.
Introduction
Raycasting is a rendering technique used in computer graphics to create a 3D perspective in a 2D map. In this project, we simulate a 3D environment by casting rays from the player’s viewpoint and rendering the scene accordingly.
How It Works
The player navigates through the 3D environment using keyboard controls. Raycasting is used to calculate the distance from the player to the walls in the scene, which determines the height of the walls in the rendered view. The scene is then drawn on the screen using Pygame.
Features
- Simple 3D environment simulation
- Player movement and rotation
- Basic wall rendering using raycasting
Installation
Prerequisites
- Python 3.x
- Pygame library
Installation
- Install Python from Python’s Official Website.
- Install Pygame by running
pip install pygame
in your terminal.
Usage
- Clone the repository or download the source code.
- Navigate to the project directory using the terminal.
- Run the command
python raycasting.py
to start the project.
Controls
- Use the arrow keys to move forward, backward, and rotate left or right.
- Press the ESC key to exit the game.
Code
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
```python
import pygame
import sys
import math
WIDTH, HEIGHT = 800, 600
player_pos = [4.5, 4.5]
player_dir = [-1, 0]
player_plane = [0, 0.66]
world_map = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
]
def draw(screen):
screen.fill((0, 0, 0))
for x in range(WIDTH):
camera_x = 2 * x / WIDTH - 1
ray_dir_x = player_dir[0] + player_plane[0] * camera_x
ray_dir_y = player_dir[1] + player_plane[1] * camera_x
if ray_dir_y != 0:
delta_dist_y = abs(1 / ray_dir_y)
else:
delta_dist_y = float('inf')
map_x = int(player_pos[0])
map_y = int(player_pos[1])
if ray_dir_y != 0:
delta_dist_x = abs(1 / ray_dir_x)
else:
delta_dist_x = float('inf')
step_x = -1 if ray_dir_x < 0 else 1
step_y = -1 if ray_dir_y < 0 else 1
if ray_dir_x < 0:
side_dist_x = (player_pos[0] - map_x) * delta_dist_x
else:
side_dist_x = (map_x + 1.0 - player_pos[0]) * delta_dist_x
if ray_dir_y < 0:
side_dist_y = (player_pos[1] - map_y) * delta_dist_y
else:
side_dist_y = (map_y + 1.0 - player_pos[1]) * delta_dist_y
hit = 0
side = 0
while hit == 0:
if side_dist_x < side_dist_y:
side_dist_x += delta_dist_x
map_x += step_x
side = 0
else:
side_dist_y += delta_dist_y
map_y += step_y
side = 1
if world_map[map_x][map_y] > 0:
hit = 1
if ray_dir_y != 0:
if side == 0:
perp_wall_dist = (map_x - player_pos[0] + (1 - step_x) / 2) / ray_dir_x
else:
perp_wall_dist = (map_y - player_pos[1] + (1 - step_y) / 2) / ray_dir_y
else:
perp_wall_dist = float('inf')
line_height = HEIGHT / perp_wall_dist
draw_start = int(-line_height / 2 + HEIGHT / 2)
if draw_start < 0:
draw_start = 0
draw_end = int(line_height / 2 + HEIGHT / 2)
if draw_end >= HEIGHT:
draw_end = HEIGHT - 1
color = (255, 255, 255)
if side == 1:
color = (128, 128, 128)
pygame.draw.line(screen, color, (x, draw_start), (x, draw_end), 1)
pygame.display.flip()
def main():
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("3D Raycaster")
clock = pygame.time.Clock()
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_ESCAPE]:
running = False
# Oyuncu hareketi
move_speed = 0.05
rot_speed = 0.03
if keys[pygame.K_UP]:
new_x = player_pos[0] + player_dir[0] * move_speed
new_y = player_pos[1] + player_dir[1] * move_speed
if world_map[int(new_x)][int(player_pos[1])] == 0:
player_pos[0] = new_x
if world_map[int(player_pos[0])][int(new_y)] == 0:
player_pos[1] = new_y
if keys[pygame.K_DOWN]:
new_x = player_pos[0] - player_dir[0] * move_speed
new_y = player_pos[1] - player_dir[1] * move_speed
if world_map[int(new_x)][int(player_pos[1])] == 0:
player_pos[0] = new_x
if world_map[int(player_pos[0])][int(new_y)] == 0:
player_pos[1] = new_y
if keys[pygame.K_LEFT]:
old_dir_x = player_dir[0]
player_dir[0] = player_dir[0] * math.cos(rot_speed) - player_dir[1] * math.sin(rot_speed)
player_dir[1] = old_dir_x * math.sin(rot_speed) + player_dir[1] * math.cos(rot_speed)
old_plane_x = player_plane[0]
player_plane[0] = player_plane[0] * math.cos(rot_speed) - player_plane[1] * math.sin(rot_speed)
player_plane[1] = old_plane_x * math.sin(rot_speed) + player_plane[1] * math.cos(rot_speed)
if keys[pygame.K_RIGHT]:
old_dir_x = player_dir[0]
player_dir[0] = player_dir[0] * math.cos(-rot_speed) - player_dir[1] * math.sin(-rot_speed)
player_dir[1] = old_dir_x * math.sin(-rot_speed) + player_dir[1] * math.cos(-rot_speed)
old_plane_x = player_plane[0]
player_plane[0] = player_plane[0] * math.cos(-rot_speed) - player_plane[1] * math.sin(-rot_speed)
player_plane[1] = old_plane_x * math.sin(-rot_speed) + player_plane[1] * math.cos(-rot_speed)
draw(screen)
clock.tick(60)
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()
``` ## Contributing
Contributions are welcome! If you want to contribute to this project, feel free to open a pull request on GitHub. Fixes, improvements, and suggestions are always appreciated.