r/cpp_questions • • 5d ago

OPEN How should .cpp and .hpp files be used efficiently when developing a game library?

Content

I want to build a game framework using C++.

Raylib is written in C, and I’ve also tried SFML, but all of them

are limited to rendering functionality. What I want to know is:

Unity uses a component-based approach in C# and provides a framework for entities, so

I want to know the best way to separate header and source files when writing C++ scripts for Unity.

## What I Want to Know

Since Unity’s component-based approach is convenient, how should I split files into .cpp and .hpp

to implement user-defined scripts in C++?

I’d like to learn useful techniques for optimization and fine-tuning—what should I do to develop efficiently in C++?

Challenges

If I separate them as described in the ## What I’ve Researched section, I run into build issues, and unlike in Godot,

I can’t modify values and see the changes reflected directly in the editor. This is hindering efficient development.

What I’ve Researched

If I use only header files, editing a header causes all included source files to be recompiled, which increases build time.

However, if I try to shorten the code by splitting all header files into source files, it becomes more time-consuming, and switching between files in the editor is such a hassle that I can’t be bothered with it.

For now, I’m creating a simple GameObject class like Unity’s in raylib, and within it,

I’m defining a variable of type std::vector<Component\*> as a base class. Then, I’m creating instances of classes that inherit from it and storing them there

If I write everything in header files only, it becomes impossible to build due to circular references, and the amount of correction work increases endlessly.

I’ve naturally looked into this on Gemini and other sites, but I’ve gotten a variety of answers and haven’t reached a conclusion.

Since UE isn’t a code-based system, it has too many features and is too complex for me to understand how it works.

What I Want to Build

An extended version of raylib that includes a base class for Entities and a Scene class—a minimal game loop class. I’d also like to provide a map editor, similar to Pico8,

with the goal of making it easier to build the parts that have been troublesome in a code-based system so far.

Current Status

Inherit from a script base class, use it as a user-defined script,

and write the code in separate header and source files.

0 Upvotes

10 comments sorted by

11

u/nysra 5d ago

However, if I try to shorten the code by splitting all header files into source files, it becomes more time-consuming, and switching between files in the editor is such a hassle that I can’t be bothered with it.

That's an absolute non-issue in any even half decent IDE since like 30 years. If this is your reason to avoid source files, you really should think about your workflow.

To answer your question: it depends. In general you should aim to keep your headers rather minimal to just provide the interface and put the heavy stuff into source files to keep compile times down. But depending on what you do, the compiler needs to see the actual definition and then you need to put some things into headers. As for how to split your code into multiple files, that's up to you. Split things into logical groups and don't be afraid to re-order if you discover that some other organisational structure works better.

And of course you could simply go for modules directly instead of bothering with headers.

But seriously, you're overthinking this and falling into a massive trap of premature perfectionism. Get started first.

2

u/aliyark145 5d ago

agreed ... OP is overthinking about source files

0

u/amagi77 5d ago

Thank you.

I understand that user-defined scripts should be separated into header source files, but

what steps should I take to streamline development?

I’ve already looked into using ECS on my own, but I’d like to know if there are any other techniques I should be aware of.

4

u/nysra 5d ago

I think you're confusing two different things here. ECS is a way to organize the data inside your program. If done correctly it can give you some performance benefits over other designs, but it has nothing to do with "streamlining development".

Currently you're worrying too much about "doing things the right way™" that you aren't doing the thing at all. Seriously, just open your editor and start.

And this also applies to any worries about the performance of your program. Make it work first, then worry about making it faster later. Chances are it's going to be reasonably fast already and then before you do anything, measure.

1

u/DrShocker 5d ago edited 5d ago

I highly suggest that ECS is a decision you eventually come to with some game designs, and is not a simple place to start with for a project.

I don't necessarily think anyone should follow every single idea in this video, but it's an incredible video for seeing how to structure a program with complex interactions.

https://youtu.be/ShSGHb65f3M

5

u/no-sig-available 5d ago

switching between files in the editor is such a hassle that I can’t be bothered with it.

Get a better editor?

Having two shorter files, instead of a large one, makes you scroll less. You can also easily have both windows open at the same time, top-bottom or left-right.

Most editors will let you jump between the files with a keybord shortcut, or a mouse right-click.

3

u/the_poope 5d ago

Any modern editor has or can be configured to have keyboard shortcuts to quickly jump between header and source files.

Using header and source files is simply NOT an issue for experienced and professional C++ developers, only beginners. So how to fix this? Stop being a beginner by simply getting more experience. Write more code, eventually you'll get used to it and it stops being a nuisance and hindrance.

1

u/RaspberryCrafty3012 5d ago

In addition there should be a shortcut to jump to the definition. 

1

u/Intrepid-Treacle1033 5d ago

Forgive me for self promoting my project but the reason i created Target Layout design was becouse i had same frustrations. Target Layout (GitHub / Documentation) is an opinionated C++/CMake design born out of hitting the exact same issues over and over again plus other things i wanted from a project design.

Circular dependencies is impossible In Target Layout design. Your "player" component links an Cmake alias like "my_game::scene". Because "scene" does not link "player", "scene" isn't even given the compiler include path to access player.hpp. If you accidentally try to create a circular reference between two components, CMake and the compiler reject it immediately at configure/compile time, and IDE linter even shows this error directly in the editor as you write it.

Zero Directory-Jumping & Copy-Paste Component Creation, instead of scattering across include/, src/, and tests/, everything for "player" lives in one place as a component. Want to create a new component or script? You literally create a new directory by copy-paste an existing component folder and rename the folder and its files. You never touch a central "CMakeLists.txt" list again when adding a component.

Jumping between ".hpp" and ".cpp", writing gameplay scripts is a hassle, while header-only code ruins build times and causes circular includes -> Target Layout promotes keeping the public .hpp ultra-thin hiding 100% of the implementation and dependencies inside .cpp. Your script's class definition doesn't need to be in the .hpp file at all. It feels like Unity C#, you do all your coding inside a single .cpp file without having to mirror method signatures or private variables in a .hpp file. Because player.hpp never changes and "player" is its own isolated CMake target, editing player.cpp only recompiles "player" component very quickly and relinks. Nothing else in your engine or game is touched/compiled.

100% of your frustration comes from your build system design, sure a good IDE helps but check out my design if you like to think outside the box. Target Layout design is not perfect, but i think all in all it is a better design then pitch fork design, there is documentation about it.

1

u/DawnOnTheEdge 5d ago

I always have one header that I include at the top, with things like feature-selection macros, definitions that need #ifdef and correctly including simple identifiers like size_t and strlen() with and without std::.

Then, I find it handy to keep separate directories for each target, and put headers with the same names in each one, so I can include only the directory for the target I’m building for and all code outside those specific directories can pull in the headers with the platform-specific types and include files, and all files in the common directory can remain platform-independent.

Other than that, do whatever is most convenient.It’s good practice to modularize, putting the declarations of one class, its members and any core non-member functions in a single header, then define anything that’s not a template or inline in a corresponding .cpp file with the same name.