My first thought was, with modern engines, or even raw OpenGL that isn't that hard... I did it in a weekend for my "Advanced Computer Graphics" elective in college using OpenGL and that was 2008. But this is kind of cool... it's more of a tiny ray tracer and... well to borrow the title... old-school arcade game.
He added it, but now it unfortunately looks like it says “build your own school shooter in a weekend...”
Wolf3D was 1992, 16 years before. SGI released OpenGL a few months later. IIRC, the first gfx cards were thousands of dollars. The first successful consumer gfx was 3DFX Voodoo2 in 1996. We take so much for granted nowadays.
Programming a game from scratch, even a simple looking one without the aid or modern APIs is certainly much more difficult. Which is why I was saying this posting is amiss by excluding the fact this Github project uses older techniques from the title.
It's a ray caster, where the rays are sent out from the camera to intersect the map. With ray tracers, the rays are sent out from the light source, IIRC.
Your point on OpenGL is valid, but that just removes all the learning from it. OpenGL does so much of the grunt work for you. This kind of old-school game engine is a great learning experience.
Not correct. I see this pedantry often, but it's factually wrong. If you look at the Wikipedia articles for both ray casting [0] and ray tracing [1], they BOTH describe the methods as sending rays from the camera/eye.
From what I can tell, the difference between ray casting and ray tracing is that in ray casting, only the primary ray is traced. The ray does not get reflected, refracted, or even traced to light sources for checking shadows. At most, surface normals are dealt with for lighting and texture mapping is applied.
Are there any implementations which send rays from the light source(aka. forward ray tracing)? This is astoundingly inefficient, as most rays will not intersect the camera.
I've never seen one, other than in brief academic discussions. What you can use forward ray tracing for is to compute shadows.
Ray casting on the other hand is basically ray tracing without any reflections or shadows, in other words each ray stops with the first collision.
It's definitely a lot of fun to implement (and I recommend trying if you've never done it before) but it's very different and much more limited than what we expect from a 3D engine nowadays.
Well, the original Wolfenstein 3D, the third game in the series.
Or there's the time-tested path to gamedev: modding existing games.
Godot's 3D capabilities, while almost certainly not as full-featured as Unity, are plenty enough to make an old-school FPS, and a lot more.
The Godot online docs are quite good; well organized, clean layout, easy to find stuff. But for tutorials and howtos, I've had more success with YouTube screencast videos vs the Godot docs.
Definitely for kids, modding an existing game is the right way to go. It will be way more fun, and it'll be a lot more motivating to share things with friends than to do stuff because dad said so.
I think you're also right that Unity is better but it's still pretty challenging. Programming is really crazy hard, especially for young kids.
That's despite great things like Code.org and Scratch. Those activities are substantiated by good observational (qualitative) evidence measuring creativity, not programming ability.
The only hard quantitative data people have is engagement time--that kids spend more time in apps than equivalent regular instruction when learning idiosyncratic turtle graphics in apps. Pretty unsurprising in my opinion.
As far as I know, there is no evidence that these pre-high school programming experiences retain acceptably-performing students in high school programming like AP Computer Science better than forcing them to take the class. Scratch's educational mission, which I am most familiar with, has for now not made such test-based outcomes an investigative priority.
Honestly an old-school 3D shooter is just about the worst thing you can coerce a disinterested kid into doing. If they're pre-puberty and still care what dad thinks, this sort of activity is exactly what kids drop when they get older. If they're in high school and don't care what dad thinks: it's not a multiplayer game, it doesn't inhabit some social space/it isn't a "third place," it's not taking advantage of the greatest power of the classroom in high school, peer pressure.
This is based on my experience making a game that kids 12+ regularly mod, being the only kid in high school that programmed regularly before 18, and interacting with (but not conducting research with) the wonderful people at Scratch, who really do know how to make algorithmic thinking and creativity work for kids 12 and younger.
Maybe at Stuyvesant parents are making the kids learn C++, but you gotta understand that coercion is the placebo, not the treatment. If you're going to coerce your kids into doing something incredibly boring, it might as well be whatever narrow testing regime is hot these days and not what we fantasize vicariously they should be interested in doing.
I’ve built a Raspberry Pi Retropie NES clone and they’re all over super bomberman, and old school Pokémon.
The last game I modded was OpenTTD before my kids were born.
It is not tutorial, but the code is very clean and readable and it use modern techniques (compared to Wold3D/Doom style raycasters). The codebase could be extended easily.
Royalties, risk of you game ending up unplayable in 10 years, running into limitations you can't fix because you don't have the source, performance ceilings you can't change, bugs you can't fix.
On the other hand if you do things from scratch you can spend years and years and years.
I had enough fun with it that I think it might become my new "trying out a new programming language" test, since it was easy enough to get done quickly, but difficult enough to where I had to actually learn the language.
Better than my 10-second explanation: https://lodev.org/cgtutor/raycasting.html
Interesting note about this technique: you get perspective correct texturing for free. "Real" 3D rendering usually had to cope with affine texturing due to performance costs until dedicated hardware for it came along.
https://htmlgames.github.io/htmlgames/differences/gallery/in...
type something like lego into the search query and it renders pictures of lego in the maze as well.
https://permadi.com/1996/05/ray-casting-tutorial-table-of-co...
It has real legacy, was created in 1996! https://permadi.com/1996/05/ray-casting-tutorial-table-of-co...
I looked at this after doing GCSe project, finding it to hard and skipping to a real 3D engine like quake because it was conceptually easier.
They had an example app that was a FPS made from scratch. The HUD was there, enemies, weapons, environment.
There might be a Metal FPS base game available on GitHub, I can't remember what it was called.
Does std::vector automatically handle the memory releases? This is called every frame, so I wanted to check here to see if I'm crazy or not.
Yes. What is going on here is that "img" is being assigned. The "old vector" will have its destructor called, which will call the destructor of all of its elements by default.
-------
I assume you're talking about this code: https://github.com/ssloy/tinyraycaster/blob/master/framebuff...
void FrameBuffer::clear(const uint32_t color) {
img = std::vector<uint32_t>(w*h, color);
}
Which seems inefficient to me. But it is correct code, even if it is inefficient. There's no memory leak here, but the code probably would be way more efficient if it were instead a simple memset. memset(&img[0], color, w*h*sizeof(uint32_t));
This memset is likely easier to understand, since it doesn't rely upon destructors / constructors / assignment C++ Magic. And its more efficient to boot. Vectors are guaranteed to be contiguous in memory, which is why it is compatible with memset.EDIT: Hmmm... the img is never initialized. You'd also have to do "img = std::vector<uint32_t>(w*h, color);" somewhere.
----------
The rectangle is also inefficient.
for (size_t i=0; i<rect_w; i++) {
for (size_t j=0; j<rect_h; j++) {
If i and j were reversed, the draw rectangle function would be more efficient. As it is, "j" iterates in the wrong direction with regards to cache lines... // This would be faster!
for (size_t j=0; j<rect_h; j++) {
for (size_t i=0; i<rect_w; i++) {
Overall though, efficiency isn't a goal at all. Its designend to be a quickie project to get things done as soon as possible. Thinking about all of these details slows down development, so there's something to be said about "just getting it done"I always wondered 'what if' someone released Doom like FPS game in 1993 that required you to flip monitor on its side ;-). Both Ray-casting and Mode-X work best in vertical plane, while video memory access is only efficient when done linearly. Some quick back of a napkin calculations lead me to believe you could deliver 400x320 at the speed of Dooms 320x200.
" img = std::vector<uint32_t>(w*h, color); "
What is more interesting if you have been away from c++ is that the assignment is not a copy! The vector in this case is a temporary and it dies on assignment. Thus img takes the guts of this new vector.
Movement semantics didn't exist in the language per se, but they were supported back then by std::swap and std::auto_ptr. Today, it is far easier to represent movement semantics with RValues, std::move, and std::unique_ptr.
But yeah, std::vector's assignment operator was originally at least std::swap based and therefore efficient.
All source and assets included
learning how to raycast, the maths involved, how to make your own game engine, none of those things are covered in that repo. It's a different thing. This kind of negativity is damaging.