2D Game Engine by 13-YEAR-OLD! // Code Review

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey what's up guys my name is the channel welcome back to the first episode of another little series that i'm just starting here right now which is going to be called code review now as you can probably guess from the title what code review is going to be all about is me taking a look at some of your code and then just giving my thoughts on it now quick disclaimer i'm not some kind of programming god to be able to just objectively tell you that your code is wrong or right this is completely going to be just my thoughts looking at your code trying to help you out giving suggestions that are hopefully going to be helpful to you and the rest of the community that's all this is about don't take this as some kind of absolute guide or anything but hopefully it's going to both help the community and show some common mistakes maybe or things that just shouldn't really be done but then also just be a general good time for us to hang out and look at some code together so if you're new to the series which of course you are because this is the first episode you can email me at cherno review gmail.com the email address will be in the description below basically just attach your code or some kind of link to your code as well as the description of what your code is what kind of stuff maybe that you struggle with or that you want me to specifically review and then i'll download it set it up i'll just pick someone arbitrarily and we'll go with that also feel free to mention whether or not you want me to actually say your name on video maybe you don't and that's totally fine just let me know so today we're going to be looking at this gentleman's code he has written a small 2d game engine with no graphical editor it can render quads render textured chords render text play music handle basic stuff move the quads a bit more still learning opengl and c plus plus how to run there's some instructions here as well as a very dodgy looking dot ra file but i'm willing to take that risk for you guys also he's 13 years old let's just take a moment to appreciate that i started programming when i was 16. this person here claims that they're 13. so whatever this code is going to be and whatever i'm going to say about it it's gonna be just i'm trying to be helpful absolutely no disrespect absolutely not going to be making fun of this person's code so let's extract this raw file and dive into it but first this video is sponsored by skillshare for those of you who don't know what skillshare is skillshare is an amazing online learning community where millions of creative and curious people from all around the world can come together to learn a new skill whether you're interested in creative topics such as photography videography illustration that kind of stuff or you're looking for some help with your business maybe with marketing or productivity skillshare has got you covered they've really got like this huge library of very high quality courses that all have lessons around five to ten minutes each they're really bite-sized and they're really easy to just sit down do a couple in your spare time and then continue going about your day and that's one of my favorite things about skillshare now coming in at just under 10 a month for an annual subscription i think it's a really great price for all of the skills that you will be learning but of course you can get a free trial for a limited amount of time by clicking my link in the description below so definitely check it out a really good place to put some of the free time that you may have is into being productive and learning new skills for sure thank you again to skillshare for sponsoring this video okay so let's take a look at this 2d game engine so the person here has specified that we need to go into the script and then the run debug batch file let's just take a look at what it actually is first we have basically echo off clear screen here pro blah blah title echo starting building okay so we're compiling using g plus plus here in goes a bunch of simple plus code as well as a bunch of libraries to link this seems to be divided up into various different directories and the output files here are the intermediate files the g plus plus will actually generate as well as this final kind of linking stage where we actually link all of these object files here with the library files and all of that and produce an executable called sandbox.exe now i think i forgot to mention that i've never looked at any of this code before or this project structure before whatsoever this is my fresh eyes on this so obviously i might be reading things slightly wrong or just keep that in mind and then there's echo running well like okay cool so i already have a few things to say about this this is very unsustainable right as your engine grows and you have more and more files you have to manually keep adding them here now you can use g plus plus in slightly a better way to like just include all of the cpp files and h files and all of that stuff and just make things generally easier but in general just having a little batch file that has all of your files that you're trying to compile and all of that it's cool that you're starting that way because i think a lot of people do start that way and it's i think that it's arguably better than starting with like a full-on ide and having all of that manage that for you but my recommendation would be for sure to use something like premake or cmake to just you know be able to generate project files for you so that you can easily run this inside visual studio and not have to manage the whole build system yourself in like a text file because this stuff is definitely going to get harder to maintain as you as the project grows anyway let's try and run this so apparently we should be able to just open up command prompt and then just run scripts slash i think run debug.bat now this doesn't work because well i don't have g plus installed so let's go ahead and open a min gw terminal here and hopefully if i navigate to this directory and then i will run scripts slash run debug.bat we should be okay okay so check this out we have some pretty interesting music going on and i think we can even kind of move this around a little bit looks a little bit kind of uh well not very smooth here but 60fps here we've got some text going on looks pretty cool i even like the attention to detail here we have an icon and all this stuff oh frame rate seems to have dropped a little bit no we're okay pretty cool so we can run the quads and can't resize the screen or anything like that but that is basically what the project looks like so now let's dive into the thing that matters the code so just a few more thoughts regarding the project structure now we have an assets file here a bin file an include file a scripts file and a source file and of course when i'm saying file here i mean folder uh with all of this stuff in here so that's pretty nice i like to see this kind of layout usually it's good one thing i would recommend is maybe since this is an engine and not just a game project it would be good to see some kind of separation of projects so maybe the engine code should be in a single folder and then the actual game code can be somewhere else and the game can contain like assets and all of that whilst the engine code will contain more of the kind of engine engine code base so if we were to open this folder in visual studio code over here we'll just be able to easily browse this repository it would be nice to see some kind of uh you know setup environment here to be able to run and debug this through vs code if that's what you've chosen to use and not visual studio but that's obviously okay now i'm apparently in this file here let's go and uh i guess we'll start at the top so so far the source uh directory is fairly standard i like to see this vendor folder again this looks a little bit similar to the design that i'm using for hazel which is fantastic because it's cool to see this kind of structure you know with like a vendor folder with all the third-party stuff coming from someone who's 13. like that's really cool to see so i'm glad to see that hopefully what i'm doing here on youtube is also helping out people with this because this looks pretty good i would never have guessed this was someone who was 13. my code at that age was well non-existent but my code in my first couple years of programming was nowhere near this organized so that's already really really cool okay so we've got sandbox we've got tools again this this this stuff to me like sandbox obviously seems like it should be in a separate project now this person doesn't really have projects uh i mean they are just compiling everything with g plus plus which is fine they could still compile this into like a you know the engine code into like a library file to a static library file then link it to an exe file and all of that stuff but you know we're not going to get into that that's not that important especially not at this stage in their programming career okay so uh basically the the i guess the main function is over here let me just make this slightly bigger we start by just playing the music which is cool um then we also set the icon on display manager now i'm noticing that these these kind of variables here these instances of classes i presume are coming out of nowhere right like they're obviously global and you can see them up here actually in the sandbox.cpp file they're not even like static global meaning they're confined to this translation unit to the cpp file they're actually just full on global not a great design uh in this case i mean honestly like it doesn't really matter too much but what i would have liked to have seen is this display manager you know there's probably no reason for it to actually be global like it's not even used in this kind of stuff this is also slightly dodgy what i probably would do is just cut this code out and just put it over here into main this is already a lot better because for one you'll be calling the destructor as you exit over here and not sometime in static destruction but also this stuff is just kind of bound to the scope and it won't leak out into the rest of your entire project in that kind of global space but yeah everything else is okay setting up some icon stuff setting a resizable yeah this looks pretty pretty standard to me we've got this kind of while loop here which is the uh game loop here or the application loop looks pretty fine i i would just say that this kind of stuff definitely shouldn't be in your main file i would make an application class and have maybe a function called run which contains this actual game loop more of like an organizational thing not really going to impact the like performance or the general like way this application runs but it's something that's very useful to do just to keep your code more organized so display manager is pretty much the first thing that gets created let's take a look at the display manager class i'm going to try and be fairly brief here just because obviously this this is quite large and uh i could definitely sit here forever but i'm going to try and be kind of brief so we have um we have the display manager class which uh takes in a width and height and a title so immediately looking at this i would give a couple suggestions first of all try not to use unsigned int it's a little bit outdated use something like uint32t what this is is a it's kind of a more modern we'll say unsigned in type the big thing that it actually has is a size you know there's no there's never a dispute about how big this integer is we know that it's an unsigned int is fairly arbitrary we don't know what the size is 32 bits is actually written here we know this is a four bit unsigned integer as an added bonus it's less characters than unsigned int so it would actually make everything else look a little bit cleaner so i always try and use um 32 underscore t for my unsigned int types now std string title with this no point taking it in by value like this put a little const reference here because if you don't what you're doing is actually copying the entire string into the display manager constructor this is this is bad i mean it doesn't necessarily have to be bad depending on the size of your title string and all that but essentially by by changing this to a const reference you're doing one less copy potentially i mean you'll still need to copy it eventually into win title but you're not copying it first into the constructor and then again into when title copying strings is not that great because every time you copy a string the new string has to heap allocate memory for it to be able to be stored and again this is subject to like things like small string optimization but for the most part we want to avoid that pretty much any time you take in a string or any class that is like larger than let's just say eight bytes for the most case you want to just make it a const reference uh you know unsigned in as i said to un-32t everything else looks pretty good now personally this is a very minor thing but personally i like to actually store this kind of private stuff at the bottom of the file now the reason i like doing this and i actually used to do it the other way around but the reason i like doing it like this is because when someone is looking at this header file for the most case right usually they want to be able to see what they can do with this class right they don't really care about the implementation details which is like you know all of this stuff i don't care that it has some private functions that i'm not even going to be able to call right for the most case they just well for the most frequent case i should say uh in most cases and that's the right that's the right phrase i was looking for they just want to see what is up and what they can do with this class and by putting the public stuff first you're just kind of keeping everything a bit more organized and making it so that you can actually have that stuff here we have this usenvidia.h little file here basically what this does is tries to force uh dedicated graphics if you're on a laptop that has integrated graphics this is this is fine i guess uh this is a little bit of a consequence of using opengl for rendering and not something like vulcan which actually lets you programmatically pick what physical gpu you want to use and that way you'd usually pick something dedicated uh instead of like an integrated card for something like a game engine so that's what this is doing that's totally fine it's in a header file which i assume gets included into some kind of translation unit later on um text shader just stumbled upon this file accidentally this is like my first thought on looking at this is why is everything in the header file this stuff should be implemented in a cpp file as you're developing this file any kind of change to this code is going to force everything to be recompiled it includes this header file it's a lot better to have that in the cpp file um this stuff seems pretty good i tend to not really use exceptions just as a stylistic thing in most of my code but it's totally fine to use them in most cases um yeah just creating opengl shader stuff i'd probably separate this stuff into like a cpp file as i mentioned um but everything else i think looks pretty good pretty standard uniform setting going on here check compile errors for our shader that looks pretty good as well uh text rendering stuff um yeah this stuff is this stuff seems pretty good uh again i stuff whenever i see um scd map i i tend to usually use an unordered map the reason is an arnold map is a hash map it just tends to in most cases be faster than a map for looking up things but it definitely depends on the size and certain other things so i'm not gonna just you know blindly give that advice but i usually use arnold map and i think that for the most part that should be the first thing you choose um okay sound manager stuff renderer stuff okay this is interesting so we have a vector of float pointer which are our vertices okay uh let's take a look at render or cpp because i'm really interested to see why we have a vector of pointers so it looks like we have um in the renderer add we can add a quad i don't know what a quad is it'd be nice to let's just uh what's the right i think that's it quads um okay so what this is is we're creating a bunch of vertices here on the stack and indices then we're copying them onto the gpu here as an array buffer and an element array buffer so we have our vertex buffer and our index buffer and that seems that that seems like that's all we do here um this gl core macro which i'm assuming i'm not sure if i can go to it not really uh i'm assuming this gl call thing let's just try and search for it here it is debugger yeah so this is kind of like an old way of checking errors in opengl you don't really need to do anything like this anymore if i open up hazel and i try and just go to to be honest i don't even know where this is probably in like gl context maybe i have no idea where my own code is i think opengl render api you can see we've actually got a callback for error messages now so gl debug message callback is something you can use as of like opengl maybe 4.3 just off the top of my head and if you enable gl debug output and gl debug output synchronous then you don't actually have to wrap every gl call in that kind of gl error check because anytime you get an error it will just simply call this callback and you can even put a breakpoint in here and see whenever it's called and then use that as long as you've got synchronous enabled so it's not asynchronous you'll be able to look at the call stack and see exactly where it's coming from so basically gives you the same uh the same features as what this does except you know with the assertion for the breakpoint and all that stuff but without having to wrap everything in this macro so it just makes life a little bit easier and i would recommend that you use something like that um okay so we we take in a quad we push it back uh and then what we do here this is very interesting so into the into the m vertices vector we're actually getting the vertices from the quad so let me first of all see how that what that's even doing um [Music] so where are the vertices from here am i misunderstanding something so quad dot vertices vertices i can't see vertices so that's a bit odd quad dot vertices where is this this thing anyway it looks like oh it's no it's not here i've actually found another quad class here so maybe this is what it is but anyway this is a vector of vertices here and i guess this is what's being pushed back into here now this is already uh very dodgy i'm not even sure how this is working exactly because this is a temporary object right so what we're doing here is we're copying a quad over here which first of all isn't ideal because the quad contains a vector and so we're actually copying all of this data every time we enter this function which means that well that's not great for performance because vectors for example will dynamically allocate memory in most cases as well as will like potentially other stuff here so it's a pretty heavy copy but on top of that um this object is obviously temporary it's going to cease to exist at the end of this function and yet we're actually getting the pointer to this vertices vector contained within this quad instance that later gets destroyed and putting it into our member function so in other words after this function m vertices is going to contain a float pointer to memory that's been deleted so that's already like a bug um this stuff uh okay so this shouldn't really work either i'm fairly sure because at i think returns a constant reference potentially which means that how we're assigning to a constant reference not sure how that compiled unless i'm just looking at the wrong thing um yeah but this stuff definitely shouldn't be happening uh if you want to actually push indices back you should allocate your own memory and copy that instead of relying on this pointer because that's that that memory is likely to get deleted um yeah that's that's very likely to cause a bug if it's not if it even works now which i doubt it okay gl call this stuff um again gel call can get removed everything else is probably okay this is just preparing some opengl stuff for rendering which is totally fine and then we have uh the actual render function which just enables the shader here sets the view matrix calculates the model v projection matrix binds the vertex array and then does the draw call now this again not being called at the moment so i assume half of this is broken maybe this is why but uh this doesn't do anything but we will be setting the uniform here into the shader okay so that's the renderer seems pretty fine i think to me uh let's try and go back to our files here what else should we look at um i'm trying to just uh figure out what even to look at because obviously we could be here for hours uh okay the text renderer itself so this is um interesting we're drawing a string here again you know try and use const references for this kind of stuff then we're doing a con iterator here we're iterating through all the characters i did see um free type being used earlier which is great so we're actually able to um you know when we initialize the text renderer it's going to uh fetch certain characters i assume from the aerial font here and then we can actually use uh opengl here and in this case um we're actually going through 128 different characters and then retrieving them from free type the actual pixel data and then storing them using opengl like into a texture essentially now this again is going to create 128 different textures uh it's a lot better to use something called a texture atlas or a sprite sheet to just store all of these characters in one texture so instead of having to generate 128 different textures and then having to rebind them all the time you just have one kind of sprite sheet which contains all the characters that you need right there now obviously that's something a little bit more advanced a little bit harder to set up especially for someone who's 13 let's be real but uh definitely something that i would do because having 128 different textures for your characters aren't great also um you are going through all of the characters here right so c is being used here we're literally going through all the characters that this font contains almost so that's also not really necessary what you can do is just do this on the fly so whenever you are going through text that um you know requires a certain character you can check to see if that character exists and if it if it doesn't exist yet because it's the first time you've used like the letter a at that point in time you can actually retrieve it from free type instead of having to like create 128 different textures up front without even potentially needing half of them so that's also something i would do but other than that you know this is pretty standard just creating a quad basically so that we can actually you know with all the font matrix and all that so that we can actually draw each character here as a quad and then just drawing it over here pretty sanded um and then advancing x so that we can draw like sentences and stuff like that pretty standard text rendering using free type cool that's really impressive uh you know i feel i remember one of the like when i did text rendering for the first time i it probably took me a month if not more to figure it out and i was like 20 i think ish so text rendering definitely isn't that easy and it's definitely the most impressive thing in this engine um you know rendering quads is not that hard i think again it's hard for me to picture what it's like for a 13 year old but i would think that that's kind of like not too difficult but i'm definitely impressed by all of this text rendering stuff this looks this looks really good and to be honest like looking through this code like yeah you know sure there's some you know stuff here that probably belongs in like the engine state and like the renderer not necessarily the text renderer specifically and you know there's this you know creating 120 different textures not great either but you know for the most part it definitely very like tidy code very impressive and like yeah i honestly this code i would not be surprised to see this kind of code laid out in this way you know from someone on my team at ea or something like that back when i used to work there and that's not to say that ea code is bad it's just that this person's code is pretty good okay uh there's some very physics stuff here which you know i mean it's just a vector 2 class and i think textured quad is also something really interesting now one thing i do want to mention is that um one thing i've noticed here is that uh the quads that we're creating here they're basically different every time so we create a chord with an x y width and height right which is what's going on over here uh and then every time we need a quad at a different position we create a new quad and we create a new vertex buffer and you know set up all the attributes and do all of that stuff and this is a textured chord so we also um you know do all of this stuff for it you don't really need to do this what you can do instead is basically what we do inside hazel and if we look at the 2d renderer we just have a quad that we create once that's what's happening here we have a bunch of coordinates actually this is this is for the batch renderer but what we do is we basically create a single quad that is a one by one unit quad and then with that quad in mind we upload it like to the gpu and create a vertex buffer out of it as usual but then if we want to render a different size quad at a different position and if we let's say we weren't using a batch renderer we could just simply use a transformation matrix so like a scale rotation translation matrix to just manipulate this one quad so you can draw the same chord many times but then set a uniform mat four to be a different transform matrix and that way you can get any kind of quad you want with just these vertices and you can create them once and you never ever have to create another quad vertex buffer again ever so it's really really useful um and that of that that's basically how i would probably write a little quad renderer if i was not trying to bash them all together or do anything like that so definitely something to consider because you don't really need to have a textured quad class you can just have a function inside your renderer called like submit quad kind of like what you're doing here with the add function but then what that can do is just simply create a matrix based out of what the translation rotation and scale that the person wants the quad to be rendered at or the core league i should say wants um the quad to be rendered at on your screen and then that's really all you need to do then you can just do a draw call um or push it back into some kind of uh queue here or a list with that matrix and then do a draw call with that matrix being set as a uniform and that's kind of it hopefully that makes sense uh everything else um i think that's about it i think we've gone through pretty much everything i would definitely clean up that second quad file i don't know why i found two there's looks like there's one in source um no that is a cpp file i'm really curious why i found two different ones that's kind of weird isn't it because i definitely go i definitely didn't open this project twice not sure anyway hopefully you guys enjoyed this little code review as i i mean i i there's no huge problems here uh from the code that i've been looking at this could easily be like a 20 year old 25 year old university student's code like this is this is great and if you really are 13 then amazing work and if you really did write it yourself um then i'm definitely very impressed uh i think you've got a lot of potential obviously and you know just some minor c plus plus issues like path part like passing things by const reference and using you and 32 t instead of unsigned int and you know just some standard stuff that i see all the time as well with you know maybe not really quite understanding how pointers work and how if you really want to take ownership of memory you may have to copy it and you know all of that stuff like what we saw with the whole vector of float pointers and then just simply setting that to be the data of some other quads vector that may be deleted later on that apart from that kind of stuff yeah looks absolutely great particularly impressed with the whole text rendering situation that's really cool and if you figure that kind of stuff out on your own as well then like absolutely well done if you have some code that you want me to look at then check the email address in the description below it's channelreview gmail.com and i'm looking forward to reviewing a lot more code in the future let me know what you thought this is the first episode if you just don't like the format of it or if you did like the format of it or if you want me to focus on some other stuff definitely leave a comment below i am trying to get as much feedback as possible since we've just started the series and i hope that it will be something that we can enjoy doing a lot more of in the future don't forget to hit the like button if you did enjoy this video and don't forget to check out skillshare using the link in description below thank you all for watching i will see you later goodbye [Music]
Info
Channel: The Cherno
Views: 201,038
Rating: undefined out of 5
Keywords: thecherno, thechernoproject, cherno, c++, programming, gamedev, game development, learn c++, c++ tutorial, game engine, how to make a game engine, code review, 2D Game Engine by 13-YEAR-OLD! // Code Review, 2d game engine, c++ code review
Id: 9HCboZHTyrw
Channel Id: undefined
Length: 27min 35sec (1655 seconds)
Published: Fri Oct 02 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.