Skip to content

Instantly share code, notes, and snippets.

@vesche
Created November 14, 2017 00:39
Show Gist options
  • Save vesche/2851df4a8e3758d4bb5770bfed487fd2 to your computer and use it in GitHub Desktop.
Save vesche/2851df4a8e3758d4bb5770bfed487fd2 to your computer and use it in GitHub Desktop.
pygame raycaster
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# pygame raycaster proto
#
import math
import time
import pygame
from pygame.locals import *
LEVEL = [ [1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
[2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 3, 2, 3, 0, 0, 2],
[2, 0, 3, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
[2, 3, 1, 0, 0, 2, 0, 0, 0, 2, 3, 2, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 2, 0, 0, 0, 2],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, 2, 1, 0, 0, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 0, 0, 0, 0, 0, 0, 0, 2],
[2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 2, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2],
[2, 0, 3, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 3, 2, 1, 2, 0, 1],
[1, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 2],
[2, 3, 1, 0, 0, 2, 0, 0, 2, 1, 3, 2, 0, 2, 0, 0, 3, 0, 3, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 2, 0, 0, 2],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 2, 3, 0, 1, 2, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 3, 0, 2],
[2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 1],
[2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1]]
# constants
WIDTH = 1024
HEIGHT = 768
ROTSPEED = 0.02
MOVPSEED = 0.03
# trig constants
TGM = (math.cos(ROTSPEED), math.sin(ROTSPEED))
ITGM = (math.cos(-ROTSPEED), math.sin(-ROTSPEED))
COS, SIN = 0, 1
# init vars
position_x = 3.0
position_y = 7.0
direction_x = 1.0
direction_y = 0.0
plane_x = 0.0
plane_y = 0.5
# init pygame
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
key_state = [False] * 324 # pygame key states
while True:
for event in pygame.event.get():
if event.type == KEYDOWN:
key_state[event.key] = True
elif event.type == KEYUP:
key_state[event.key] = False
if key_state[K_ESCAPE]:
pygame.display.quit()
pygame.quit()
if key_state[K_LEFT]:
tmp_direction_x = direction_x
direction_x = direction_x * ITGM[COS] - direction_y * ITGM[SIN]
direction_y = tmp_direction_x * ITGM[SIN] + direction_y * ITGM[COS]
old_plane_x = plane_x
plane_x = plane_x * ITGM[COS] - plane_y * ITGM[SIN]
plane_y = old_plane_x * ITGM[SIN] + plane_y * ITGM[COS]
if key_state[K_RIGHT]:
tmp_direction_x = direction_x
direction_x = direction_x * TGM[COS] - direction_y * TGM[SIN]
direction_y = tmp_direction_x * TGM[SIN] + direction_y * TGM[COS]
old_plane_x = plane_x
plane_x = plane_x * TGM[COS] - plane_y * TGM[SIN]
plane_y = old_plane_x * TGM[SIN] + plane_y * TGM[COS]
if key_state[K_UP]:
if not LEVEL[int(position_x + direction_x * MOVPSEED)][int(position_y)]:
position_x += direction_x * MOVPSEED
if not LEVEL[int(position_x)][int(position_y + direction_y * MOVPSEED)]:
position_y += direction_y * MOVPSEED
if key_state[K_DOWN]:
if not LEVEL[int(position_x - direction_x * MOVPSEED)][int(position_y)]:
position_x -= direction_x * MOVPSEED
if not LEVEL[int(position_x)][int(position_y - direction_y * MOVPSEED)]:
position_y -= direction_y * MOVPSEED
# draw roof and floor
screen.fill((25,25,25))
pygame.draw.rect(screen, (50,50,50), (0, HEIGHT/2, WIDTH, HEIGHT/2))
column = 0
while column < WIDTH:
map_x = int(position_x)
map_y = int(position_y)
camera_x = 2.0 * column / WIDTH - 1.0
ray_direction_x = direction_x + plane_x * camera_x
ray_direction_y = direction_y + plane_y * camera_x + .0000001 # ZDE
delta_distance_x = math.sqrt(1.0 + (ray_direction_y * ray_direction_y) / (ray_direction_x * ray_direction_x))
delta_distance_y = math.sqrt(1.0 + (ray_direction_x * ray_direction_x) / (ray_direction_y * ray_direction_y))
if ray_direction_x < 0:
step_x = -1
side_distance_x = (position_x - map_x) * delta_distance_x
else:
step_x = 1
side_distance_x = (map_x + 1.0 - position_x) * delta_distance_x
if ray_direction_y < 0:
step_y = -1
side_distance_y = (position_y - map_y) * delta_distance_y
else:
step_y = 1
side_distance_y = (map_y + 1.0 - position_y) * delta_distance_y
# Finding distance to a wall
hit = False
while not hit:
if side_distance_x < side_distance_y:
side_distance_x += delta_distance_x
map_x += step_x
side = False
else:
side_distance_y += delta_distance_y
map_y += step_y
side = True
if LEVEL[map_x][map_y] > 0:
hit = True
# correction against fish eye effect
if not side:
perp_wall_distance = abs((map_x - position_x + ( 1.0 - step_x ) / 2.0) / ray_direction_x)
else:
perp_wall_distance = abs((map_y - position_y + ( 1.0 - step_y ) / 2.0) / ray_direction_y)
# calc line height
line_height = abs(int(HEIGHT / (perp_wall_distance + .0000001)))
draw_start = -line_height / 2.0 + HEIGHT / 2.0
# ensure doesn't draw outside screen
if draw_start < 0:
draw_start = 0
draw_end = line_height / 2.0 + HEIGHT / 2.0
if draw_end >= HEIGHT:
draw_end = HEIGHT - 1
# colors
wall_colors = [ [], [150,0,0], [0,150,0], [0,0,150] ]
color = wall_colors[ LEVEL[map_x][map_y] ]
if side:
for i,v in enumerate(color):
color[i] = int(v / 1.2)
# draw line
pygame.draw.line(screen, color, (column, draw_start), (column, draw_end), 2)
column += 2
# update screen
pygame.event.pump()
pygame.display.flip()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment