An open API service indexing awesome lists of open source software.

https://github.com/izabera/pseudo3d

a raycaster in bash
https://github.com/izabera/pseudo3d

3d bash gamedev raycasting terminal terminal-based terminal-game tui

Last synced: 5 months ago
JSON representation

a raycaster in bash

Awesome Lists containing this project

README

          

# a raycaster in bash

https://github.com/user-attachments/assets/59851903-cf4c-4dfc-afae-3c533f6241f7

more screenshots/vidoes at https://imgur.com/a/izas-wolfenstein-bash-journey-bAy5zhp

largely a port of https://lodev.org/cgtutor/raycasting.html

use the arrow keys to rotate and move around, and q to quit

### why this was a bit hard

- bash is slow. this is by far the biggest issue. it's so slow that you
cannot possibly achieve an acceptable frame rate if you have to execute even
a single command per pixel. this implies that you also cannot keep the state
of the screen in memory, neither as an array of colours (did you know that
accessing a random element in an array takes linear time?) nor as a single
long string (did you know that accessing the nth character in a string takes
linear time even in LANG=C?), because literally just reading this
representation to dump it to the screen will take longer than a frame

- bash has no floating point support nor access to a library of maths
functions. all the maths is done on integers, scaled up by 64k

- terminals are ugly if you use a full character to represent each pixel, so
this uses unicode half blocks with different foreground and background
colours, which effectively doubles the vertical resolution. there is
unfortunately no way to update only one of the two colours in a cell, nor any
way to query the current colours of a cell (besides, it would be too slow for
bash), so every time we write a pixel we need to know the colour of an
adjacent pixel. it would be really convenient if bash could store the state
somehow but alas it cannot

- various misc annoyances:
- making sure all the terminal is updated at once is not trivial with a
slow language like bash

- most terminals are not designed to play video games in (shockingly), so
you cannot test if a key is currently pressed. instead you can only get
a single key that's being held down, usually really slowly debounced and
with a low limit for continued presses, so you probably get like 5-6
characters a second. you cannot even get multiple keys pressed at the
same time unless some are modifiers. the kitty keyboard protocol 100%
fixes all this, and i'm sure it will become a widely implemented standard
by the year 2100

- turns out that filling a terminal with colours takes a lot of data. at
my normal font size this does ~10mb of i/o per second, which isn't very
much in the grand scheme of things, but, you know, it's bash

- bash will never use a single syscall to print a string with more than one
newline, regardless of the type of file you're writing to. this is
pointless and dumb, and it's the reason why this never prints \n and
always moves the cursor in other ways. ultimately this ended up printing
more data than the size your terminal is likely getting in each read, so
it might not matter too much, but it still bothered me

- ecma48/vt100/vt200/xterm... were all designed by insane people who hated
me specifically

- holy shit i'm bad at maths, i went to uni for this what the fuck

### faq

- q: it fucks things up when i resize the window/it's a flickery mess/it
generally looks like shite on my terminal
- a: open an issue please

- q: my cpu heats up like crazy/my computer from 2005 slows down to a crawl
- a: try to reduce the resolution, or set the env variable FPS to something less
than 30. also, microsoft defender is known to do everything it can to tank
any resemblance of performance, so maybe disable it

- q: it doesn't work on my bash < 5.2
- a: yep

- q: is this code all pure bash?
- a: no. it also calls stty once at startup to disable echo, and once at exit
to re enable it. and some stats at the end are collected via other tools

### roadmap

- [x] semi-accurate pseudo 3d
- [x] fluid movement
- [x] decent framerate
- [x] parallel rendering
- [x] 24 bit colours
- [x] kitty keyboard protocol
- [ ] mouse support
- [x] framerate-independent speed
- [ ] textures
- [ ] sprites
- [ ] objects/enemies
- [ ] particles
- [x] sound (VERY EARLY PROTOTYPE)
- [ ] better perf
- [ ] multiplayer
- [x] dynamic wall colours
- [x] dynamic map (it technically is but no events change it at the moment)
- [x] basic animations effects for walls
- [x] basic on-screen minimap