4 ms·
Show HN: A 2D game engine in under 1000 lines of C
- caymanjim 7y agoWhat's with the majority of the code being in header files?
- Koshkin 7y agoGood question... (In fact, a small project with a single .c file does not even need include files.)
- microcolonel 7y agoI think Ryan just wants a single compilation unit, for the time being. I would personally just put all the code in one file if it's this small (though I think some text editors are not good at editing one file from multiple views, so I can see that being annoying for some).
- ryanpcmcquen 7y agoI know that using .c and .h files is the traditional way of doing it in C, and I started the engine this way, but to be honest, is there any gain to it in this scenario? The headers are library code, and having more files just means more maintenance and build complexity. Is there another advantage I am not aware of?
- jdmoreira 7y agoYou can read some of the criticisms here https://en.m.wikipedia.org/wiki/Header-only https://en.m.wikipedia.org/wiki/Header-only
- macleginn 7y agoNone of them seem relevant for a small-scale unitary project.
- chongli 7y agoEven a large project like SQLite is provided as a single, unified header file!
- flohofwoe 7y agoA better resource is this: https://github.com/nothings/stb/blob/master/docs/stb_howto.txt https://github.com/nothings/stb/blob/master/docs/stb_howto.t... There's an important difference between C++ style header-only libs, where the implementation is often done in inline code (especially for template-heavy APIs) and thus visible in each compilation unit (which is indeed bad for compile times), and "STB-style single-file libs", where the implementation is only visible in a single compilation unit. The difference between a single .h file and a .h/.c pair is really just different packaging for distribution and integration into projects.
- flukus 7y agoThe question should probably be what you gain from the header files? If you just want the simplicity you can "#include \"some_file.c\"" instead. Functionally it's no different, but it's less surprising to other people and it's an easier transition to a real build system if/when you need it. I think the reason it's being raised is because people think your writing a header only library.
- ryanpcmcquen 7y agoIn my experience, including `"some_file.h"` is more common than `"some_file.c"`. I also like knowing at a quick glance what the entry point/main file is. That's less explicit when all the files have the same extension.
- babuskov 7y agoUsing header files is great when starting new projects. When I wrote my first game engine, I tried to keep everything in .h files. There are two benefits: A minor one, but still saves some time: You don't have to think about build system. Just compile a single .c file on the command line. You can quickly add and remove .h files while prototyping, without having to add/remove files to the project. A major one: is that you cannot create cyclic dependencies. This helps to get your call hierarchy right. When using header files only, the only way to get cyclic dependency is to use a forward declaration and every time you feel like you need to do that, a big red flag is raised in your mind. And then you start to think how to do it properly. This is even more important in C++ where you have to think about responsibilities of every class. It prevents you from creating too coupled code. When the project grows and compilation times get long, you should split all of those into separate compilation units, so that you can use multi-threaded builds (via ninja, or make -j).
- pjmlp 7y agoFile->New Project isn't that hard.
- pjmlp 7y agoNot bothering to learn how to deal with compiler toolchains.
- w0utert 7y agoIt's not uncommon in game development to do 'unity builds', by basically including all code to get a single compilation unit. It can reduce build times and the compiler has more options for optimizations (inlining, mostly). This doesn't require putting everything in header files, just including the .c files gets you the same result. But if you're doing unity builds the distinction between header files and source files is basically reduced to the file extension anyway...
- jsd1982 7y agoLooking at your `init` function, I would refactor it to not be so nested with if statements. Try logically inverting the if checks and returning early up near the top of the method and remove the else branches. Keep repeating this kind of refactoring on all your if statements. Eventually, you'll find that the "happy path" ends up at the bottom of the method and can return a success status without being so far indented. This style makes it easier to reason about what conditions are possible at various points in the method, i.e. you don't have to mentally compose the boolean logic conditions of all the nested if/else statements. Here's an example I did: https://gist.github.com/JamesDunne/a94782bc39d95515f7dcc8516a18c5cb#file-init-refactor-c-L113 https://gist.github.com/JamesDunne/a94782bc39d95515f7dcc8516... Also, I would generally move all implementation code out of header .h files into standard .c files. Header files are traditionally just meant to contain forward-declarations of types and methods.
- blondin 7y agonested ifs work here too. i personally don't think cognitive overload is an issue because you are not composing all the conditions at once. in fact, each block should only care about one condition. but you make a good point. tbh, i have seen nested ifs used in video game programming a lot. and i came to the conclusion that it has to do with the else clause that the return early method doesn't provide. the else clause is always doing something because games are never supposed to fail...
- setr 7y ago? If cond return err means everything after is an implicit else block
- dragonwriter 7y ago> If cond return err means everything after is an implicit else block Right, but inverting to get to return early format means that the “else block” that needs to do substantive work becomes the if block, and it needs to be doing something substantive not just “return err”. Which may be a valid criticism in some cases, but doesn't seem to be in this particular code base, where most of the ifs don't have an else and those that do it's log-error-and-return.
- kazinator 7y agoThere is no need for this nonsense: #if defined(__WIN32__) || defined(__WINRT__) || defined(_WIN64) fopen_s(&file_to_read, path, "rb"); #else file_to_read = fopen(path, "rb"); #endif
- ryanpcmcquen 7y agoWhat would you recommend?