Last active
May 30, 2020 21:23
-
-
Save salt-die/c7db1ea3ce4ecc77dee0e71d85e1aa14 to your computer and use it in GitHub Desktop.
2d raycaster that runs in your terminal!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import defaultdict | |
import os | |
import time | |
import numpy as np | |
from pynput import keyboard | |
from pynput.keyboard import Key | |
TERMX, TERMY = os.get_terminal_size() | |
def center(*lines): | |
for line in lines: | |
yield line.center(TERMX) | |
class RayCaster: | |
keys = defaultdict(bool) | |
directions = ((Key.up, (-1, 0)), | |
(Key.right, (0, 1)), | |
(Key.down, (1, 0)), | |
(Key.left, (0, -1))) | |
running = True | |
def __init__(self, DIM, pos=(10,10)): | |
self.DIM = DIM | |
self.grid = np.pad(np.full(DIM, 1, dtype=int), pad_width=1, | |
mode='constant', constant_values=2) | |
for _ in range(40): | |
self.grid[np.random.randint(DIM[1]), np.random.randint(DIM[0])] = 2 | |
self.pos = np.array(pos) | |
self.listener = keyboard.Listener(on_press=self.pressed) | |
self.listener.start() | |
def pressed(self, key): | |
self.keys[key] = True | |
def grid_rays(self, angle): | |
angle = np.array([np.cos(angle), np.sin(angle)]) | |
with np.errstate(divide="ignore"): | |
delta = abs(1/angle) | |
step = 2 * np.heaviside(angle, 1) - 1 | |
side_dis = ((step + 1) / 2) * delta | |
map_pos = self.pos.copy() | |
while True: | |
side = 0 if side_dis[0] < side_dis[1] else 1 | |
side_dis[side] += delta[side] | |
map_pos[side] += step[side] | |
self.revealed[tuple(map_pos)] = self.grid[tuple(map_pos)] | |
if self.grid[tuple(map_pos)] == 2: | |
break | |
def print_revealed(self): | |
print(*center(*(" ".join(" .W@"[value] for value in row) | |
for row in self.revealed)), sep="\n") | |
def start(self): | |
while self.running: | |
self.revealed = np.zeros_like(self.grid) | |
# Cast rays | |
for theta in np.linspace(0, 2*np.pi, 100, endpoint=False): | |
self.grid_rays(theta) | |
self.revealed[tuple(self.pos)] = 3 | |
os.system("clear") | |
self.print_revealed() | |
time.sleep(.2) | |
# Input handling | |
for key, direction in self.directions: | |
if (self.keys[key] and | |
all(1 <= pos + dir_ <= dim for pos, dir_, dim in zip(self.pos, direction, self.DIM))): | |
self.pos += direction | |
self.keys[key] = False | |
if self.keys[Key.esc]: | |
self.running = False | |
self.listener.stop() | |
if __name__=="__main__": | |
RayCaster((40, 40)).start() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment