Programming a first person shooter from scratch like it's 1995

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone and welcome back to development on my verbal plan game today we're going to be oh I guess I I guess I asked that idea in the last video well I mean uh what's this video supposed to be about [Music] okay well no not exactly do but the exact idea from my list said Doom style 3D portals and time travel puzzle game and that is actually what we'll be working on today even though it is a little bit you know before my time but that doesn't stop me before so please join me on this journey back to the nine days since it's what we'll be focusing on in this video I do like I mean aside from the obvious an engine like this actually lends itself really well to the two key mechanics of the game portals and time travel portals are relatively easy because of the way the Doom style software vendor works or more accurately a build engine style software renderer but you know more on that later and time travel well Doom style levels tend to be relatively simple so there won't be too much to keep track of when actually doing the time travel and also I mean like you know the aesthetic is kind of justification enough in and of itself anyway enough about the reasons why let's hop into the code for this project in keeping with that early 90s theme we'll be using C if it will kindly have me back after my last project of course and also we'll be using STL to handle cross-platform windowing input things like that but aside from that we're on our own like I mentioned we're building a software render which means that just like for those early MS-DOS games we have to draw everything on the CPU completely without a graphics card which means it's just us and this buffer of pixels to fill no vertices no triangles no shaders no nothing so with our window opening up and you know we've got this little pig test pixel down here now how do we go from this to this well an easy First Step here is to take a look at Doom's predecessor Wolfenstein 3D instead of allowing for arbitrary wall angles and Heights like Doom Wolfenstein was combined to a 2d map of thick size blocks which happens to be much easier to render as the ore 3D through a simple raycaster we Define a simple map in our code using zero for empty space and one through four for different wall colors you can also imagine that there is a point in this map which is our player and another small line which defines our screen in map space then for each vertical column of pixels in the screen we cast array through the map grid and find the distance until that Ray hits a block this distance then determines the height of the pixel column longer distance meaning smaller pixel column and this is the most important thing to take away from this Wolfenstein style renderer because it's on this idea of the screen height divided by the length of the Slime segment that we're building our Doom Style renderer so with that in mind how then does Doom use a similar perspective division technique to draw its levels well let's start by taking a look at a dual map Doom uses a 2d top-down map representation which is built on sectors which is basically just a fancy word for an area enclosed by some lines with its own floor and ceiling height sectors can be attached to each other by sharing a line or a wall through which the camera can see one sector from another I'll be mostly referring to these as portals from here on out this is terminology that I've stolen from the build engine as a simple demo is only concerned with sectors and walls and not you know monsters and stuff like that this is all we need to draw a test map of Our Own so let's bust out our pen and paper and get to designing we get started with one sector in this octagon shape then we go on to Define some others making well not that I look at it kind of looks like a giraffe if you just you know give it some legs here but the most important thing is you know that it's made up of walls and sectors anyway if we label our vertices and our portals and everything then we have a pretty clear picture of what's going on so let's take this map that we've just drawn and then type it into a text file so that we can load it up on our program as some data notice that the sectors basically just Define a list of walls inside of them and the floor and ceiling height and the walls just to find a couple vertices and a portal to another sector if they are one this notion of a portal instead of two sectors just sharing a wall to be seen for one another is what makes our engine more build style than Doom style but that's not something I'm going to get into right now with binary space partitioning and all that fancy stuff because we're not using it for the interested there will be some links in the description of course anyway let's get to actually trying to draw this so after removing most of the Wolfenstein style demo code not needed since our map is no longer made up of Cubes we can start by defining some constants and math functions since we're in good LLC like I said earlier we don't really have any hand holding from the standard Library the most important function out of these for our purposes is this one which determines if two line segments intersect and if so where the intersection point is this is what we'll be using to determine how the walls fit into what the camera can say my implementation is shamelessly stolen from Wikipedia anyway though with our math and utility functions hashed out we can Define our two paid players here walls and sectors you can see that they're basically just a one-to-one mapping of what we typed into our data file the wall data has been neatly packaged into some vectors for our convenience though so with all that defined next up we just have to write a function to slip all the level data out of that text file and then we can get started with trying to draw things we'll just be starting with the simplest case and try to draw one wall the first step here is to determine where the wall is located relative to the camera and using this world pause to camera function is exactly how we do that we just throw the wall endpoints through this bad boy and then we can find out where they are as though the camera were the origin you can also see from the fancy diagram that I drew here that this has the added bonus of any wall points that end up behind y equals zero we can just throw out after some additional clipping according to the camera's field of view using that very important line segment intersection function I mentioned earlier we use this fancy screen angle to X function to find out where our wall endpoints are as x coordinates on the screen here's another Super high-tech hand-drawn diagram that shows what this does basically we find the angle of the wall endpoints relative to the camera with some trigonometry magic and then we convert that angle to an x-coordinate in our screen pixel buffer and that's going to be where we'll draw the wall from there we just use the same principles the Wolfenstein renderer the height of each vertical column of pixels depends on its distance from the camera with some added linear interpolation here and there and with this pretty simple core rendering Loop we have a wall drawing on screen as though we're 3D you could notice that the only pixel drawing function we need is still just this vertical line function so with one wall drawing drawing multiple balls is then as trivial as throwing all that line drawing code in a loop over the walls of the sector and even though it's a little hard to tell due to the lack of shading we have our original octagon shape back but what about the walls that might connect to other sectors the ones we called portals to draw portals first we figure out the window in which we're drawing the height of the window is determined by the floor and ceiling Heights of the neighboring sector relative to the heights of the current sector of course and then the width of the window is just where we would have drawn the wall anyway these pink Parts here denote the window you can see on the left we have a relatively small one and on the right we can't even see the top because the neighboring sector ceiling is higher than the ceiling of the current sector from there we actually just repeat the exact same process that we used to draw the sector that the camera is in just as though it were happening in a smaller window of the screen we just throw the clipping data into a queue along with which sector needs to be drawn and then the process repeats all the way until we just hit a solid wall add in some fancy shading according to wall angles and floor and ceiling colors like the Wolfenstein render and we've got something pretty darn 3D looking in order to make this look a little more like doom and a little less like hovertank 3D though we do need some textures on our walls the basic idea behind this is that we need to find the world space position of each screen pixel in order to fix it to a texture sample as the camera is moving the code for this is a little more complicated than I'll go into in this video but if you check out the link in the description you can see it for yourself we can see some Beautiful Textures in the background here with a little bit of stretching and over sampling but you know things are working and if you haven't noticed by the general look of things being a little more you know scuffed here I've actually ran out of demo code for this video now so everything you see from here on out is me experimenting in real time with the code mistakes and all just a fair warning with texture mapping working I wanted to try out something that the do mention definitely couldn't do which was Ray traced light Maps so I really quickly threw this together the code ended up being pretty quick but after I added some nice smooth interpolation to the light map sampling I kind of just realized that this look was going to be too modern for what I was going for so I had to throw this code out oh and I also added billboard and Sprites at this point as you can see from our beautiful friend this little uh the smiley face here billboarded Sprites for drawn almost exactly the same way as walls they're just adjusted to always be facing the camera and are just kind of you know floating there it was also runs time added some of the other basic capabilities of the graphics engine like top middle and bottom textures lighting and palletization the engine was also upgraded to handle non-convex sectors and transparent portal overlays which you can see here with the graphics basically perfect at this point I started looking at the other problems that I had before I could you know make a game and the next one was I don't really want to be riding all of my levels in a text file so I needed to write a level editor and this was pretty simple you know I kind of just took a look at what the do map editor did try to do something like that you know man oh well would you look at that the project is 13 000 lines of code now yeah so rather than explaining all of this and making a video that's about three hours long let's do a brief overview instead though no promises that that three hour video won't come later basically I started by introducing a 2d View for the levels just like the Doom level editor and then added some basic types which can be added and edited for the level those being vertices walls sides which can Define texture and collision information for each side of each wall sectors which are the same as our old notion of a sector and then objects which will be any pickups monsters basically anything that can be interacted with and then decals which are basically just objects except they're only confined to being on walls this will be used for buttons and things like that but more about these in a second because they're also important for portal drawing I also have some other material types which Define the materials that each side and sector have including some texture offsets and other goodies you can see here that I've given each of these base level types A menu so that I can conveniently edit its properties this is the only part of this project that isn't software rendered or done from scratch I use the dear IM GUI there imgui this incredibly popular immediate mode UI library to do the heavy lifting for the interface code for me all this 2D stuff though in case you couldn't tell by the incredibly low quality and complete lack of anti-aliasic is still drawn by my own homegrown Seacoast though so no cheating there anyway though the editor can switch back and forth between the 3D view from the game and the 2D view with the Press of a button so things can be edited in 3D with some extra data that I had the render start spitting out about what was being drawn to each pixel so with the ability to modify level geometry and sector Heights and other properties like that next step was populating the levels with those decals and objects but you can see our first little test decal here that smiley which we had earlier now we can just drag it around the wall to reposition it these decals started out as Sprites that were drawn directly on top of walls but that didn't work due to some issues that I had with Z fighting so instead I moved to a system where each wall keeps track of its decals in a linked list and they get drawn directly where the wall pixels would otherwise be and remember those portals that I mentioned earlier adopt the portals between sectors but the portals that are actually going to have something to do with gameplay yeah those are actually going to be rendered on decals so they can appear in arbitrary points on the wall still need to figure out the rest of the code for that one though so you know come back next time but decals working properly though we need to be able to interact with them since to interact with decals we need to Cast Away from where the camera is looking into near walls this also meant that I kind of need to dissolve my Collision detection problem because up until now you could kind of just walk your way out of the level and into the endless void and I kept doing this when I was editing and then I wasn't able to find my way back so you know two birds with one stone like Doom I solved this problem in 2D with a simple raycast through the level every time you want to move from point A to point B in the interest of doing things quickly the level gets divided up into these blocks of walls which means that we don't need to check collisions against every wall on the level every time we want to move so with the implementation of this path tracing function and the magic of function pointer callbacks we now have collision and the ability to interact with decals please also take a second to appreciate the Doom style wall sliding that took me a little bit to get right anyway now that we could interact with things I added our first test button to this wall but what does the button do well that's where something that I've come to call tags come in you can see in the editor menu here that decals and also sides and sectors for that batter have something called a tag which is just a number the two things in the level have the same number or tag than they can talk to each other and by talk I mean that the level has a table of values somewhere corresponding with each tag number and that these level objects can read or write to that table depending on what they do for example if we press this button the tag value gets set to 1 and then this sector over here with the same tag number notices that it's tag change and will start moving its floor height it's dead simple but it's enough to get some basic doors and other Dynamic things into the level now the other Dynamic element on our levels are objects these are just rendered as billboarded Sprites and their only defining property is their type they can be monsters pickups pedestals or you know whatever gets added later in the game objects can also have their own Ai and interact with the player things like that with our engine looking pretty good I decided it was time to get a little proof of concept game implemented in just a couple hours just so I could test things out and make sure everything was working so I used all of my brain power to come up with the best concept for a game possibly ever a first person shooter where your enemies are these things they shoot spinach at you and you shoot bananas back there is no end game I promise the real gameplay is coming in the next video but you know we just needed something to test out the engine so just indulge me for a minute so after cooking up these Sprites I give our enemies possibly the world's worst AI where they kind of just walk randomly and bump into walls and walk towards the player if they see them of course with complete disregard for anything in the way or personal space for that matter and as they go they shoot spinach at the player and you know try and damage them I also made this 100 original definitely not seen before banana gun for our player to shoot bananas from and that was pretty much it I added this little banana power and score up here and you know we've got a game oh and uh portals time travel puzzles what's that you're talking about oh yeah the actual game yeah that will be coming next time for now we'll have to be content with spinach cat banana game but we can be reasonably happy that our engine is all up and running and ready to get some gameplay I mean real gameplay anyway though the demo code for the Wolfenstein and doom style renders is in the description and the full engine source code stands right now is released on patreon which Speaking of I have a patreon the link is in the description so you can head on over there if you'd like to support me where you'll also get full access to the source code for this project my old game engine project and a brand new Discord group for everyone to chat in and a huge thank you to everyone supporting me over there especially my top supporters for this month Coop MC horse and danish pirate anyway though as always thank you very much for watching and come back next time for some non-spinach non-banana non-cat based gameplay [Music]
Info
Channel: jdh
Views: 710,891
Rating: undefined out of 5
Keywords: c++, programming, coding, opengl, graphics, java, gamedev, gaming, code, minecraft, indie, 3d, unity
Id: fSjc8vLMg8c
Channel Id: undefined
Length: 16min 37sec (997 seconds)
Published: Sun Mar 05 2023
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.