A tiny ray caster game rendered using raw SDL2, written in F#:
Why? Because I wanted to have a go using raw SDL2 from F# (not even using the SDL2-CS bindings from flibitijibibo).
Also, given that Dmitry's work is just 486 lines of C++, I was interested to see how a language almost on the other end of the high/low spectrum from C++ would do :)
Running and Building
This has been coded in .NET Core 2.2, using VS Community 2017 on Windows 10. You can run it either using VS, or via
dotnet run on the command line.
I have not tested it on other platforms - the only likely point of incompatibility would be the SDL2 library: included is the SDL2.dll from 2.0.9 for 64 bit windows.
Alternative versions of SDL can be acquired from here
Things I learned building this include:
- the netbpm format (https://en.wikipedia.org/wiki/Netpbm_format)
- to open/view ppm files, I had to install gimp on windows.
- on linux/osx, it might be easier to install & use display in the terminal
- ppm is an uncompressed image format, so is not generally recommended for images (which is probably why the support is so poor, plus its almost 40 years old)
- Note: when I move to SDL, I removed the ppm code. Its in the history around this commit if you want to see it.
- basic raycasting for wolfenstein 3D-esque rendering
- the 'fish-eye' issue when rendering is something I learned more about (specifically how to solve it) from The Black Book by Fabien Sanglard. I recommend it.
- I didn't include the monsters from Dmitry's demo - I was more interested in ray casting and SDL interop, to be honest. Maybe something to do in future.
- As a performance improvement, the raycasting uses a more granular jump rate, then walks back to find the exact point once it finds a hit.
- SDL2 Interop and Interop and general
- My implementation is a combination of replicating what Dmitry did, with a conversion of the interop declarations by Flibit
- I restricted to just what I need, so the SDL interop module is quite small. Where appropriate, I would declare flag-like constants as their raw value, generally derived by running SDL2-CS as a console app to get the value and then putting it here (e.g. SDL_PIXELFORMAT_ABGR8888 as 376840196u)
- Event polling was complicated, and I ended up restricting to just the event I needed. The union hack in the SDL2-CS lib I couldn't get working with F# (ironic, since F# actually has unions)
- Other reasons for not using SDL2-CS (i.e. other than the educational challenge) is that I only need a small subset of SDL2's signature, and SDL2-CS is not net standard (its Net Framework 4, as opposed to this project which is Net Core 2.2).