Pong Clone in C++ // Code Review
Vložit
- čas přidán 26. 08. 2024
- The first 1000 people to use the link will get a free trial of Skillshare Premium Membership: skl.sh/thecher...
Patreon ► / thecherno
Instagram ► / thecherno
Twitter ► / thecherno
Discord ► thecherno.com/...
This video is sponsored by Skillshare.
Thanks to watching! You can send your code to chernoreview@gmail.com for review, and don’t forget that the first 1000 people to use the link will get a free trial of Skillshare Premium Membership: skl.sh/thecherno12201
The login didn't work and I came when there were 380 viewers 😞
Did you have any experience with device driver. If yes please make series with deep diving. And yes I love you C++ series also.
Hello! Do you also accept Java Swing based project? I've got a small framework with 2 games in it (Pong and Brick Breaker). Yeah.. Java does the Rendering part, there are still over 20 classes though.
Please tell how to make game engine in C
The commit 'remove swear words' is fantastic.
"Hey what's up guys, my name is The Cherno" is my morning alarm ringtone
Pretty weird but ok
@@ShivamJha00 pretty weird but u know what u have todo in the morning :D
@@rickarmbruster8788 wake up?
@@techquire You, good sir, gave me a nice laugh
“I love documentation” and “I wonder what this function does” is very relatable to someone who’s written excessive amounts of jsdoc lol
"C++ is getting a little bit messy." Getting?
🤣
i thought the same^^
9:11 self descriptive code is really underappreciated, I can't tell you how much code I've had to sift through with "no shit" comments that eat up time and space.
No shit.
@@Nick-lx4fo No shit.
// This is my youtube comment where I explain I agree with you about unnecessary comments in code that add no value whatsoever. Instead they just clutter the code and induce face palm syndrome.
I agree. Comments in code that add no value whatsoever just clutter the code and induce face palm syndrome. But I think in this case the guy might have had a teacher that tells the students to put comments on every function.
@@LPFan33 breaker of the "no shit" chain
@@matthewe3813 no shit
9:04 - I am studying CS at not at all prestigious university and they explained to us on like every course what self-documenting code is and what the point of comments is. You would get minus points for code readability for these kinds of comments as well as minus points for variables like "a, b, c, x, y, z (..)" unless they're like obvious iterators.
I mean it's common sense too. After a while of coding you develop these habits yourself.
At our university programming assignments regularly had requirements like „every method needs to have a doc string“ Funnily, these assignments were graded automatically and you would get full points for just an empty doc string above the method signature😂😂
@@zombi1034 The google C++ guide says every class needs a comment explaining what it is
Thanks Cherno for reviewing code by others. It really helps coders like me, who are still in track of learning C++ .
For a first year (I assume) CompSci student that is excellent quality code. I agree the assert macros are a little odd but I have a feeling this might be some Professor requirement to demonstrate understanding of _something_. In fact I am going to assume all of that "odd" choices this person has made is to meet some specific requirement set by the Prof. Yes it is verbose but that is always what a Prof will want to see to grade understanding of topics being taught. It is still good quality code though, I do not doubt the person could (and would no doubt prefer) to cut it down but has to tick a bunch of boxes to meeting submission reqs.
Overall though this is some very good quality code. It is well organised, clean and is simple to follow. If this person applied for an internship or junior position I would most likely hire them based on the quality of this project. Great job to whoever wrote this I think you have a bright future as a programmer!
Thats what I was thinking, this person knows how to construct something but did it in a required way ..
He has his code reviewed by Cherno so he gets a perfect grade handing it in to his professor. XD
"-5 Not enough comments."
21:09 it's probably written this way because you multiply two floats and then multiply with vector, basically one float-float multiplication and one vec-float multiplication. the other way around (the logical way you suggested) it would do two vec-float multiplication.
basically it's a minor optimization
a better way to write it , i think would be delta * speed * direction
I would love to see you a code review of the Unreal engine.
i bet thats the length of the lord of the rings book series a few times
Unreal engine isn't open source, so it's source code isn't available to anyone apart from its developers in Epic Games
@@typicalretard6968 No, it isn't open source but its source code is freely available to anyone on Github (You have to create an EpicGames account). I actually use it as a kind of reference/inspiration when developing my game engine.
@@typicalretard6968 download the engine, you have the source.
@@mattiapezzano1713 have fun reverse engineering the whole engine
Wish more people did this type of content for other languages and project types.
Its pretty much an industry standard technique. Get a job and you will get your code reviewed all the time.
Just fucking program.... are you trying to learn languages? try using the languages the languages are written in, most are C or C++... so then read what it does and you will know how to change a tire because you've worked for a tire manufacturer..... EVERY SINGLE SUCCESSFUL PROGRAMMER DOES SHIT THAT WAY.... all the C++ devs anyway... the rest of you are scripters LOL!
One uni teacher here (can’t speak for everyone): when I’m assessing the commenting and formatting I give out fewer marks for submissions with redundant comments and I explain why. It creates a bad signal to noise ratio like you said, plus the extra scrolling - the less code you have on screen due to loads of comments, the higher the strain on working memory, and the harder it is to see the entirety of functions/loops/conditionals. We teach it that way too.
Re the complexity: there are serious skills on display, buuut it does feel like starting a catering business one morning to have some beans on toast. It’s fine but there’s a big opportunity cost. That time and brain juice spent on flexibility and expandability isn’t going towards great feel in the controls, physics, player feedback. Maybe they created frameworks in a previous life?
21:04 it's an optimization technique to save one vec to float multiplication. This way there is a float to float and a vec to float multiplication. The "easy on eyes way" you suggested is vec to float and again a vec to float multiplication.
PS: Just to be clear, by no means I'm saying anyone is right or wrong.
Thats actually cool.
slight tangent, he could have embedded speed in the direction vec2 and eliminated a float member from the ball class
21:40 actually any grouping makes sense. you can think of moveSpeed * delta as figuring out the distance to move as well.
moveSpeed is m/s and delta is seconds so if you multiply them you get meters.
And (scalar * scalar) * vector, is less operations than (vector*scalar) *scalar. And even if it does feel more logical to apply dt last, it's not that strange as it was. So in that case performance should take priority imo.
@@Girugi do you REALLY care about performance that much in Pong?
@@jurchiks it's not about pong. It's about a principle to not leave performance on the table when it's this simple. It should always be a consideration of what order to do operations. It gets automatic in your head if you do it, and if done all over a big project it makes a difference.
If it just was written in an suboptimal way I would not have said anything, but for churno to talk about it and teach everyone to do it suboptimal is enough to warrant a few comments.
@@Girugi Too bad the compiler doesn't optimize this. Or does it?
@@jurchiks yeah, that is unfortunate that it can't do that. As floating point values has precision issues, changing the order without knowing the numbers can give different results.
Same for int, due to potential overflow and such.
I know you're following your passion and glad that you have people to support you.
I've been a regular watcher of your C++ series. Yea it's one of the (if not the) best on CZcams. Watching your opengl ones. But I feel like the channel is headed in a different direction from where it started. Those raw tutorials which were the regular content are now becoming rarer by the day.
Probably it's for the best & probably it's just me being nostalgic but I do miss those old content.
"Just stomp the ball with a fresh ball" 16:10
I'm happy you started to upload again :)
great code, love it. But the coder is struggling with c vs c++.
Looking at this I feel like I am looking at a completely different language
Glad I’m not the only one
This code is overly confusing for what it is
I agree: I made pong in C and it took about 2 days and I was left with about 250 lines of code across 2 files.
I wouldn't say confusing but it is verbose (which yes you can argue is confusing...). To me it reads exactly like what a Prof wants to see as part of an assignment to demonstrate understanding of a bunch of features they have been teaching. So while it is verbose I understand _why_ and it doesn't detract from the overall quality of the code IMHO.
Yeah but I think here the point was to show clear and well structured code, so that this is more of a scalable canvas for a larger project than the ideal one for this game as an end product. I think the author demonstrated capability to scale up code base big time here
I’m 20 and no game engine yet.
Oh same 19 and no engine, will society even accept us?
I'm 22 and I haven't made one yet. It's an arduous process and takes a long time so don't expect to make Unreal in a week. Just take your time and be patient.
I'm 28 and have been re-writing my game engines since my late teens. I may never have a game engine haha
@@whykekesneaky2310 I'm 19 and I am slowly getting choked
by my own engine's increasing complexity XD
im between 18 and 22 and i made a bad multiplayer game engine c:
I really liked how you weren't roasting him only corrected his code, how would you do it instead of 'this' or 'that'. This is pure educational. Well Done :).
For students: the name of the function should explain what it's doing, your comments should explain why the function is needed.
For devs: there are no comments and the Jira story description is full of acronyms.
Function is an interface. The interface cannot assume who the client is and why it is needed. It should only make a clear promise about what it does. Different clients may call it for different reasons.
Thank you i’ve been learning to code in c++ from your tutorials and other sources for awhile now I’m still far from perfect but I always look forward to your videos as they’ve helped me a lot great coding teacher. 👍
I bet the project was written with clion, which sometimes gives pretty arguable suggestions.
For 20:55 the movepspeed-delta thingy:
"i move this far (speed*time) in that direction" - is imo better - Speed*time gives us the distance, and then we set it to the correct direction.
"i move this much, i actually only need to move this much" seems way more counterintuitive, and the "direction*speed" gives us a directional speed, and then we decide how far to move.
The compiler likely will turn both into similar assembly, but with multiplying the vector first, if the compiler really does that, you would also have more operations.
Regarding the global time function, statics also add an extra conditional to every call as the compiler inserts a check to see if the static has been initialized. Sure, the branch predictor makes it cheap, but if its not needed better to just not have it.
i think it's time to take some courses in c++ ... keep it up i love your channel ❤️👍🏼
Take the course, man!
10:20 it's called a hash table.. it's not always memory addresses, a lookup table is perhaps the correct term.
Cherno when you allocate 1MB on the stack: **I sleep**
Cherno when you compare a string with length 4: **real shit???**
Aaaand the understatement of the decade award goes to ... 5:54 !
cant wait to see how Jonathans Blow Jai language will compare.
~21:35 - If I told myself from like 5 years ago that I'd some day be watching two people disagreeing on where to put parenthesis in a pure multiplication, I'd probably have slapped myself
I'm a first year electronics and telecommunications and we've been doing introductory-level C. Yes, not everyone in the uni had programming classes before, but holy fuck the progress is slow and only a few of my colleagues are actually interested in programming. Along with online only courses caused by the *unspecified virus of unknown origin*, it's been a frustrating experience, to say the least.
"an idiot admires complexity, while a genius admires simplicity"
its always harder to make something as simple as possible while keeping the functionality rather than making it as complicated as possible
@@elllieeeeeeeeeeeeeeeeeeeeeeeee well, simple isnt same thing as basic, if you want to keep it simple, unix developers once came up with "worse is better approach" where you just hack a thing in to add a certain feature, that sounds bad, but it really isn't
@@elllieeeeeeeeeeeeeeeeeeeeeeeee dude someone could have literally made something like this with 100 lines in a main.cpp file, this is absurdly complex for a pong clone
Your keyboard sounds sooo good :D
All nice and good, but this is the code equivalent of the pretentious kid in middle school who reminds the teacher he forgot to assign homework
Lol
So glad you’re doing this series man. Been rocking wit you since I was in 8th mf grade bro😂 I’m a senior in college about to get my bachelors in CS thank you so much for all your videos man💯
Just to add to the self-documenting code thing… I've been told pretty explicitly by career programmer types who manage the open source projects I contribute for that I need to write my javadoc in excruciating detail, otherwise I generally get dressed down and the pull requests get delayed and so on and _ugh._ It's annoying so the self evident stuff is there, but I also include things like notes like why the function is even necessary.
For example, I contribute to a lot of Spigot plugins and I added a basic API that checks whether a given block is a crop, and I was asked why this was necessary since you can just check if the block data inherits from Ageable, so I included a little note in the javadoc explaining how fire and ice inherit from Ageable, thus isn't a reliable way to determine whether something is a crop.
0:38 Oh.. Shit! 27 and not a single game engine, i definitely live wrong way 😱😏
It's weird to find code from a student so clean, I find if I'm ever helping a classmate with something it's so hard figure out what they are doing (and it's seldom commented or we variables well named)
Most students of anything don't care until they have to. C's get degrees and whatnot.
What is the k prefix on some variables? I'm not a fan of these single letter prefixes personally. Regarding const, no, it makes no difference in code generation. For local stack variables, there's really no need to use const for primitives. For objects, setting it as const will make sure you can't accidentally call a mutating function, so it makes sense there, but for primitives, I dunno. Maybe if the code function is really long, but maybe then the code needs refactoring anyway.
This "I love documentation" just make me have second thoughts of how i document🤣🤣
FYI at 3:32 if you are like me and are wondering: the shortcut to switch the focus to the address bar is CNTR+L
I had to pause the video and google it because I wanted to know.
if you wrap it in a macro Tav you can compile it as a DLL... external dependency and have pong in any game... only problem with his macro is that it isn't defined that way and if you really wanted it for that purpose you should have a generic resolution built into it, so you can place it in an arcade machine or have it adapt to the screen size just like the main game.
TLDR; Ultimate example of over engineering
10 minutes in and I can't take it. I can really see part of my young self here, learning C++ with passion and taking seriously every advice about how writing comments and doing things only certain way is sooo important. Once you follow these great advices like an idiot enough times, you start to grow mentally and question your life. Hold on guys, maybe the great advices about writing comments and unit tests for everything is not the best way to use my time even though the mighty professor said so in the university. Hold on guys, maybe the C++ language is not the greatest thing out there and it actually forces me to burn my brain with all of these mandatory boilerplate steps and pitfalls. Maybe I should actually start thinking on my own and see what works, what is worth the time and what makes sense, you know, like any sane person would normally do.
What would you suggest?
@@systematicloop3215 For what exactly?
@@systematicloop3215 Python.
@@systematicloop3215 C :D
At least I write my game engine in C :D
// this is my comment where I explain that I think unit tests are actually a good and undervalued practice but I do agree with your remark about annoying trivial comments that add no value whatsoever
unit tests good
comments bad
I have graduated from university recently and the biggest projects are assignment 😥
Me during this entire video: * pretending to understand everything *
I could imagine those assertion macros were inspired by GLib, the library on which e.g. GTK is based on. There, you have e.g. the macros g_return_if_fail(condition) and g_return_val_if_fail(condition, value)
This perfectly defined the gap between a student and a real developer. The coder should be praised for his neat style but the style is abused so bad. I think education in uniersity should be more real-work-oriented.
Yeah, I would be upset if one of my developers did a PR with that much in there... like Jesus, how much did I pay you to write a comment to say, "This init function inits the app". Self document where you can, comments where the "obvious answer" isn't the correct answer.
Unless you are making a public api, and your comments get converted into the actual documentation
Very instructive
I made a pong clone using the console awhile back. It wasn't perfect but worked pretty good.
Interesting with the delta - the way I've understood it before was this is the distance I'm moving, but this is the amount of time that has passed, and add that on to the base position,
In one of my projects (on Windows, because Linux is simpler) I load internal functions from the process loader DLL that are used to further load other functions by manually parsing the PE header and export table of the DLL.
This is quite educating
can you please tell us which keyboard you are using , the typing sound great
21:00 Actually the brackets do nothing in this expression because its all multiplication which is commutative ie. a*b*c == (a*b)*c == a*(b*c) but in terms of expressing an idea yea you're right
The brackets will decide which order the variables are multiplied in, which can matter for implicit type conversion reasons. For example, if one of the variables was an integer, the order of operations could impact the result. Not that it might be a great way to write code that way. And as someone pointed out, the way it is written currently since moveDirection is a vector, there will be a float*float operation followed by a vector*float operation, rather than a vector*float operation followed by another vector*float operation. Now likely the compiler will find a way to optimize this particular instance to make them equal. But just in general, it's not safe to assume that just because something works out the same mathematically, it will do it the same way computationally.
I've been watching for a while, but I just realized that you say "the cherno" at the beginning. With the accent it just sounded like random syllables to be.
is a mixture of assembly and C a well accepted codebase for a review?
I would get behind that
Sounds interesting
by a mixture you mean 10% assembly and 90% C or 50% each?
Thanks for this video. Watching this interesting code review I would really like you to make videos on design patterns :)
PongChamp!
@5:56 "a little bit messy..."
C++ has been a spaghetti language from the very beginning. Splitting up header files from program files, and everything else to be backwards compatible with C, is already bad karma foreshadowing "messy". Syntax is a nightmare. Today the language has been totally borked to keep up with new features that someone seems to want but 95% of projects never use.
C++, slow to type, fast to run. Rust was a nice idea but it doesn't appear to be gaining popularity.
Fine, you're my little codechamp
Hi Cherno, I am working on something different, its a raycasting engine that using software rendering, the goal is to optimised it as much as I can, is it qualify to review?
You mean something like Doom or Wolfenstein 3D, that's nice.
I guess Cherno takes everything :D
fading the color *and* the alpha results in an r^4 drop-off of intensity, which is why the ball looks wrong.
loved the background music!!
CODE 👏 REVIEW 👏
Regarding the noexcept, outside of move constructor/assignment(if you are actually defining them) it's probably not going to help. When code is doing something high level based on is_nothrow_move_constructible_v like thing(std::vector).
Would you review some C++ code that is for an embedded platform? No heap or dynamic memory at all.
You should make C# tutorials
Amazing Video 👍🏻
I prefer auto on the left side because the type names IMHO are mostly noise. Where not obvious you can still put the type to the right of the `=`. It's a stylistic choice sure, but I can't really agree that there's an obviously better one. auto isn't about typing less; Nobody needs help typing, we have IDEs to do completions.
Also, again you don't use const to aid code generation. That's silly. Compilers can figure out whether or not something is (effectively) const in most cases where it'd affect code generation anyway. The reason we write const is because unfortunately C++ has everything be mutable by default and it's helpful to signal the difference between mutable and immutable variables somehow. If I'm seeing that something is *not* declared as const I'm expecting that to be an accumulator or otherwise mutated and I always have to do a double take if I see it's not actually used that way anywhere.
When you are scanning code quickly, seeing that something is 'bool' is much more useful than 'auto'.
I love these
His main C++ is in C Cherno... that's why you don't recognize it... I've written that before windows used to not handle references.... if you pass a program through the CLI like an EXE then that code become highly useful.... but in modern c and c++ it's not written that way and you would likely use a plugin lib instead.
Not gonna lie, the code is not very good. You see a clean main. I see 3 function calls with no local variables macros and no return statements from a function returning int. I also see only global state.
Why is everything global?
Why are attributes replaced by macros?
Why is every function documented but no macros are?
noexcept is for when you use exceptions but want to make sure some parts doesn't use exceptions. If you don't use exceptions, just don't enable them.
nodiscard however is pretty good though for finding bugs in your code. Great for finding when the following issues:
std::stringstream stream;
std::vector vector;
//...
stream.str();
vector.empty();
5:40 both nodiscard and noexcept are not part of the 'data structures', also not sure why you suddenly go of on a tangent about "modern c++". Not sure what you mean by keywords for datastructures. I use struct. That is 1 less keyword than C and 2 less than your code.
It'd be interesting to see someone submit a jumbo build ( one big compilation unit like handmade hero, AKA the Ubisoft style )for review. It's quite a polarizing code style, I'm not sure Cherno would approve of it.
been watching Casey
for a couple years, some have preordered the final "game" but man, he's been working on lighting for a long time.. also he refactors so much code it's hard to keep up with.
hey , love your content, would you be down to doing a cmake tutorial series?
yeah that would be cool. CMake seems pretty mean at times. I love its functionality but debugging is a nightmare for me :(
Neat code, good review, thank you! I learned a lot hearing your thoughts on this code base.
One nit-pick that's arguably a style preference: I'd have asked the author to leave the GPU resource handles out of the `Ball` class entirely. I think it's generally a good habit wherever possible to avoid coupling render state with logical state - just like how "OnUpdate" and "OnRender" are separate concepts that should be thought of in isolation, I think `Ball` and `BallRenderable` (name?) should ideally be thought of as separate.
For a small project like this it's definitely over-engineering to set up some elaborate resource store and scene graph, but it could be practice with a nice pattern to focus on attaching logical and render objects at render time only, e.g. `renderBall(Ball logicalBall, GLint ballVbo, GLint ballProgram)` instead of `ball.render()`
Cherno will you teach data structures in C++ please!!!
struct Data { int x; }
@@LPFan33 based
It just hit me: how would you know if there is a virus you just run after build?
How to check, without reading/understanding the whole code?
21:04
I think either way is fine. Speed is in m/s while dt is in s so speed*dt is in m. The direction is unitless, so multiplying by it doesn't change anything.
Directly shutting down the application if init() fails makes sense if we're only talking about systems that only allocate memory. There may be other types of resources allocated/acquired during init that need to be explicitly cleaned up.
Most OSes these days will free all resources during process termination, not just memory. No need to manually clean up before terminating.
@@20thCB You should always clean up memory/resources/handles regardless of what you "assume" your OS or drivers will do. Vulkan for example will literally error out if you try to destroy device instances/terminate without cleaning up buffers, imageviews, descriptor sets etc.
The reset functions looked over done a bit too much for sure. As Cherno said creating new object is a better way. Then you need not keep resetting it every time.
It’s like he’s deliberately avoided using the primary purpose of c++, OO principles with classes and there inherent benefits of constructors and member functions.
And for good reason. OOP and c++ are crap when it comes to heavy game engines and games implementations. Check the handmade hero series.
P.S: There are no real benefits to member functions and constructors.... in the long run, you realize they actually impede your design and make it harder to create robust systems. RAII itself is not a good thing... But hey, I'm not trying to start a war over here. Maybe one day, while you write a complex system, you'll come to the same realization.
@@Borgilian then what's the alternative? That's all anyone teaches for good design principles like SOLID. I would be open to an alternative bc I do find the whole OO paradigm a bit messy but, ya know, what else do we have?
@@carsonholloway ECS may be alternative (see entt video tutorials here).
@@Borgilian Handmade Hero, while it contains a great deal of valuable educational material, has an incredibly verbose and fragile codebase. Its approach to an alternative design paradigm is just as extreme as OOP. I am curious to know what difference a member function makes than a non-member function? Why is RAII not a good thing?
@@systematicloop3215 I fail to see how it is fragile. As a matter of fact, do you know that lots of tools that Casey Muratori made (the guy with the "fragile" code base) are still used in the game development world even now, 10 years later? Check the intro screen in Cyberpunk 2077 and you'll see one of his "fragile" works, in the form of Bink 2.
as a 19 year old I now feel incredibly old knowing he had to explain what Pong is because there are people alive now that have probably never heard of it..
disagree: you should use const liberally and **without** regard to code generation.
Please keep reviewing different codes ; i hope i'll be sending one asap.
Can you have a discussion on Intel new iris xe gpu. is it good for OpenGl developers..or should I go with nvidia?in laptops.
At 17:55 I would recommend not to use "auto" too much. Just use the type if it's simple like int, float, some class etc. auto is useful for shortening overly verbose things like long_name::renderrer_iterator::abstract_iterator_type.
I wanna be like you cool programmer
Position += (moveDir*speed) *dt;
Is more expensive than:
Position += moveDir*(speed*dt) ;
That is likely why it was written that way.
What kind of bullshit micro-optimization is that?
@@jurchiks I see you commented on another thread here so a more elaborate answer here is not needed. Just FYI, I wrote that on my phone just as I was about to sleep, so, I'm sorry that it was a bit short and not explaining much.
it should be written more verbose in cases like this.
doxygen can take those comments and output a full manifesto on the classes, function names, etc... don't be too surprised by cloned comment/function names... that is also code actually.
This is some amazing insight
wonder what would it be like to write this in c++ 98
That smart feeling when you check if something is 0 using 5 macroes in a separate cpp file
more like making sure no one can read and understand the code
nice job mate
What keyboard do you use?
Guys help me, what is this theme name(in video) in visual Studio marketplace