Post

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

  1. Install Python from Python’s Official Website.
  2. Install Pygame by running pip install pygame in your terminal.

Usage

  1. Clone the repository or download the source code.
  2. Navigate to the project directory using the terminal.
  3. 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
    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.

This post is licensed under CC BY 4.0 by the author.

Trending Tags