Walls in 3-D game (similar to Doom) are very flat

13 hours ago 1
ARTICLE AD BOX

I'm following a tutorial building a Wolfenstein-style raycaster in Python/pygame. The 3D projection is working like I can move around but the walls look very flat almost like it's 2D.

actual result with "flat" walls

Below is how I want the walls to look like.

desired walls

python:

import pygame as pg import sys from settings import * from map import * from player import * from raycasting import * class Game: def __init__(self): pg.init() self.screen = pg.display.set_mode(res) self.clock = pg.time.Clock() self.delta_time = 1 self.new_game() def new_game(self): self.map = Map(self) self.player = Player(self) self.raycasting = RayCasting(self) def update(self): self.player.update() self.raycasting.update() pg.display.flip() self.delta_time = self.clock.tick(fps) pg.display.set_caption(f'{self.clock.get_fps():.1f}') def draw(self): self.screen.fill('black') def check_events(self): for event in pg.event.get(): if event.type == pg.QUIT or (event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE): pg.quit() sys.exit() def run(self): while True: self.check_events() self.update() self.draw() if __name__ == '__main__': game = Game() game.run()

settings.py:

import math res = width, height = 1600, 900 half_width = width // 2 half_height = height // 2 fps = 0 player_pos = 1.5, 5 player_angle = 0 player_speed = 0.004 player_rot_speed = 0.002 fov = math.pi / 3 half_fov = fov / 2 num_rays = width // 2 half_num_rays = num_rays // 2 delta_angle = fov / num_rays max_depth = 20 screen_dist = half_width / math.tan(half_fov) scale = width // num_rays

raycasting.py:

import pygame as pg import math from settings import * class RayCasting: def __init__(self, game): self.game = game def ray_cast(self): ox, oy = self.game.player.pos x_map, y_map = self.game.player.map_pos 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) # horizontal 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): tile_hor = int(x_hor), int(y_hor) if tile_hor in self.game.map.world_map: break x_hor += dx y_hor += dy depth_hor += delta_depth # vertical 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): tile_vert = int(x_vert), int(y_vert) if tile_vert in self.game.map.world_map: break x_vert += dx y_vert += dy depth_vert += delta_depth # depth if depth_vert < depth_hor: depth = depth_vert else: depth = depth_hor # projection proj_height = screen_dist / (depth + 0.0001) pg.draw.rect(self.game.screen, "white", (ray * scale, half_height - proj_height // 2, scale, proj_height)) ray_angle += delta_angle def update(self): self.ray_cast()

Sonnet 4.6

Read Entire Article