3D Game Engine from scratch in C++

56 Replies
Enceladus
EnceladusOP5mo ago
I actually started working on it a few days ago, I have the very basics of the engine. Today I've done a mesh cube, I'm still working on it. Next I'm gonna add stuff to make a mesh component from an object file I'd load. That way I'll be able to easily render whatever I want which could be design on Blender. (I have to make a logo for the engine, it's called Dust Engine)
Enceladus
EnceladusOP5mo ago
No description
Enceladus
EnceladusOP5mo ago
I like that I'm opened to suggestions though! like "Dust Engine: making a rock from dust")
BackSlash
BackSlash5mo ago
thats a cool engine! im sure this logo isnt the aesthetic you're going for, but whenever I think of dust, I think of the moon. Also since its a renderer, I made the logo resemble a camera.
No description
Dumb Bird
Dumb Bird5mo ago
Looks pretty neat I prefer this over the other one provided But it could use some touch ups I think a rock would be best, as the idea "making a rock from dust" is used In that regard I think of a planet like mars So maybe those kinds of colors could be used?
Enceladus
EnceladusOP5mo ago
maybe we could use a shape and a color like that:
Enceladus
EnceladusOP5mo ago
No description
Enceladus
EnceladusOP5mo ago
and put a "DUST" or "DUST ENGINE" on it somewhere OR
Enceladus
EnceladusOP5mo ago
No description
Enceladus
EnceladusOP5mo ago
simpler
Enceladus
EnceladusOP5mo ago
and some shadows
No description
Enceladus
EnceladusOP5mo ago
Anyway, I'm having hard time on components system, with templates and multiple heritance. Like I have an Entity object, a child: Component, then a MeshComponent and I made a MeshCubeComponent. Firstly when I add an entity, let's say a meshCube, from the main of the project using the engine, I can't specify the arguments from the object constructor, due to the Entity template (I didn't make that one object, and it's using some complex C++ stuff, I'm wondering of a better / simpler way to do, yet I still have no idea how though) Next, in the render system, I have to specify the type of the components (still because of the template) I want to draw, and this is not ideal if I have multiple different components (different types) Here's Entity object
class Entity
{
public:
template<typename T, typename... Args>
T& addComponent(Args&&... args)
{
T* component = new T(std::forward<Args>(args)...);
m_components[typeid(T)] = std::unique_ptr<Component>(component);

return *component;
}

template<typename T>
T* getComponent()
{
auto it = m_components.find(typeid(T));

if (it != m_components.end())
{
return dynamic_cast<T*>(it->second.get());
}
return nullptr;
}

private:
std::unordered_map<std::type_index, std::unique_ptr<Component>> m_components;
};
class Entity
{
public:
template<typename T, typename... Args>
T& addComponent(Args&&... args)
{
T* component = new T(std::forward<Args>(args)...);
m_components[typeid(T)] = std::unique_ptr<Component>(component);

return *component;
}

template<typename T>
T* getComponent()
{
auto it = m_components.find(typeid(T));

if (it != m_components.end())
{
return dynamic_cast<T*>(it->second.get());
}
return nullptr;
}

private:
std::unordered_map<std::type_index, std::unique_ptr<Component>> m_components;
};
So everyone, feel free to help!
Dumb Bird
Dumb Bird5mo ago
You might have some better luck looking at how other ECS’ are done There is a good c++ one out there which I saw not to long ago
Enceladus
EnceladusOP5mo ago
Alright thanks And do you know how I could find it?
Dumb Bird
Dumb Bird5mo ago
GitHub
GitHub - skypjack/entt: Gaming meets modern C++ - a fast and reliab...
Gaming meets modern C++ - a fast and reliable entity component system (ECS) and much more - skypjack/entt
Dumb Bird
Dumb Bird5mo ago
The biggest c++ ECS
Enceladus
EnceladusOP5mo ago
Wow alright thanks! Did you do a game engine? You made an ECS system?
Dumb Bird
Dumb Bird5mo ago
I have yes That is obviously not my library though I do have a small Zig library for my own use though
Enceladus
EnceladusOP5mo ago
Oh cool! Can I ask you some advice or errors not to make for my engine?
Dumb Bird
Dumb Bird5mo ago
There really is no reason to plan so far ahead. The advice I will give though is: don't implement what you don't have to. You might want a super general and epic game engine for any game but it's drowning to think of it that way. Implement only what you need in that moment. Have a simple game idea / demo in your head and implement what you need to get it done. Focus on the problem and think of a solution, rather than looking at how other people do it and try to work backward. Don't try to optimize early and make sure to design with a pattern of some kind in the back of your head as to keep your code organized in the future. In my experience I've had to rewrite entire files simply because I knew a better way to do it in the end. Especially focusing on only what you need now can blind side you and cause you to make a choice that in the end should've been done some other way. Despite this you'll find its a lot easier to work like this. At least I have Looking at implementations is cool and all, but the best way to work is from the problem and think of a solution. Not going and looking at someone elses.
Enceladus
EnceladusOP5mo ago
Alright thank you! That's what a kinda realized by myself, with making big plans, take some code and watch stuff, but at the end I just end up with deleting files and start simpler. It's like cutting your project in small missions you have a deal with, always little improvements which eventually will lead to a complex thing I think I'll go with that, with just some gears for "engine" somewhere @earth's bird For the global structure, like in the main project, do you have
Engine engine(...);
engine.init();
// engine.addEntity(...);
engine.run();
Engine engine(...);
engine.init();
// engine.addEntity(...);
engine.run();
or with more stuff in the main, I would say, like:
Engine engine(...);

while (engine.isRunning())
{
game.read_input();
game.update();
game.render();
}
Engine engine(...);

while (engine.isRunning())
{
game.read_input();
game.update();
game.render();
}
or maybe something different because I just want to make sure I'm starting on a good solid structure for next
Dumb Bird
Dumb Bird5mo ago
That is pretty much what I have but it's a bit different That should work fine though Instead of a general run I have functions like beginDrawing and endDrawing. That kind of stuff, just splitting everything up a bit more More for performance reasons than anything
Enceladus
EnceladusOP5mo ago
yeah but which one xd
Dumb Bird
Dumb Bird5mo ago
Oh sorry The second one Although the second one kind of makes it hard to multi thread the main thread But regardless that's fine Actually I take that back
Enceladus
EnceladusOP5mo ago
That's a little problem for me because, I mean, in the first way, It's more difficult for things to be modified and added, because more things are directly managed in the engine itself instead of the project. ok interesting and for events for example, how do you do?
Dumb Bird
Dumb Bird5mo ago
Assuming your engine is more of a library rather then something like Unity and Godot then the second option should really be your only option Whats your definition of an event? In most cases that's handled on the user end. For example two objects colliding can be done with an if check
Enceladus
EnceladusOP5mo ago
because typically that's something you want to be very modulable, for multiple projects, some keys won't do the same things, so it has to be set in the main
Dumb Bird
Dumb Bird5mo ago
Nothing needs to really be set in main. I would say if checks can be done there. Never hard code what keys do in your engine
Enceladus
EnceladusOP5mo ago
yeah I see And no i'm not planning on a GUI Game Engine like Unity or whatever
Dumb Bird
Dumb Bird5mo ago
Ah ok
Enceladus
EnceladusOP5mo ago
btw when I say "main" I mean "project's main file" not engine's main
Dumb Bird
Dumb Bird5mo ago
If you mean InputEvents could just be an object or struct that stores a key and some function to call when pressed. Something along those lines
Enceladus
EnceladusOP5mo ago
yep I see well thank you for that information, it's useful, i'll have to do some refactoring already, but I thing that will make the whole thing easier to work oh and just by curiosity: what was your engine about? What can it do / for what type of game?
Dumb Bird
Dumb Bird5mo ago
The engine is dedicated towards 2d pixel art games. Nothing else as to keep the scope of the engine small But it has a particle engine and a basic lighting engine + shader support + support for Aseprite
Enceladus
EnceladusOP5mo ago
nice!
Dumb Bird
Dumb Bird5mo ago
Yep, I might one day improve it to a point I can release it
Enceladus
EnceladusOP5mo ago
maybe ! ¯\_(ツ)_/¯
Enceladus
EnceladusOP5mo ago
I also found that quick tutorial from sfml: https://github.com/SFML/SFML/wiki/Tutorial%3A-Basic-Game-Engine
GitHub
Tutorial: Basic Game Engine
Simple and Fast Multimedia Library. Contribute to SFML/SFML development by creating an account on GitHub.
Enceladus
EnceladusOP5mo ago
wait, but using an ECS, you'd just have a render function where all the entities stored will be displayed in a loop right? So yeah that's it, just one render method? And at the same time, with this way, it's not very nice to handle too. Like if you have some entities which should do some special things in special cases, you need to have that separated and in some general cases, transformations will be applied in System, but it can't everytime right?
Dumb Bird
Dumb Bird5mo ago
No You don’t want to draw everything at once And in almost all cases when you draw things really matters For example if an entity is off screen drawing it is pointless If you have entities with special cases you use a system Systems can cover all cases
Enceladus
EnceladusOP5mo ago
but it's hard coded
Dumb Bird
Dumb Bird5mo ago
When I notified my engine I was drawing and not drawing it was to open and close opengl contexts which have no reason to stay alive during times when drawing isn’t going to happen Give me an example of where this is a limiting factor also systems and components should be able to be removed and added during runtime Read up on the ECS document provided by the developer of flecs which goes very in depth about the design of an ECS system
Enceladus
EnceladusOP5mo ago
hmm, alright I'm still confused with the difference between a ComponentTransform and System, since they both make the component changing. Like if you want to set a velocity to an object, you could change that velocity from both (system and transform) right? yeah ty I started to read articles he made on how to build an ECS, it's really well made 👍 and I realize it's not the same system I had at all, and I think that new one will make my life way easier! and actually it seems to solve the major issue I had: all the entities types mixed together, so it was hard to get each type or implement, just hard to work with that
Dumb Bird
Dumb Bird5mo ago
Yeah I could see that you were confused about what an ECS even is Which is why I pointed you to that document because it has also helped me in the past
Enceladus
EnceladusOP5mo ago
I mean, I still had a quite right (small) idea of what it is, with the Entities which represent IDs, and contains Components; and systems which do the components logic. (I think, tell me if i'm wrong)
Dumb Bird
Dumb Bird5mo ago
Correct
Enceladus
EnceladusOP5mo ago
but in fact where I was mainly wrong is about what represent the entity and component like what it is technically
Dumb Bird
Dumb Bird5mo ago
Putting it all into one and how to use it seemed to be your problem
Enceladus
EnceladusOP5mo ago
Yeah If you want, I thought the Entity was just a LARGE object storing everything (even not components only), with Component which is itself a large object which contains various types of components like a Mesh Component (in my case with 3d) etc.. Like for example, a Player in a game would have been a component the huge pain was mainly in the Entity system which were supposed to store anything So it turns out a Player would be an Entity, and Velocity, Life and parameters like that will be Components. And there is an Archetype for each Entity, in case you would have many same entities (like Player), it's a vector of Players (with their ids) so that way is way simpler, way more organised and clear very nice You know, i'm not one of the people who use chatgpt all the time for everything, I usually think it's actually good at searching and resuming things, but not that much for coding and all of those things. And also because I think it's more reach to search yourself on the web, you can always find good stuff you didn't know. I always feel a bit ashamed for using it XD. But as I was stuck not finding good resources, I thought I would just begin the engine using chatgpt, just as a starter. Well... I shouldn't trust it so much, even if I already don't trust him that much 😂 i'm done with that (in reality I still learned some useful things with it, but still, it's wasn't probably worth it) @earth's bird For other things like interface, (buttons, Fps counter etc) do you think it should be an entity or something seperated?
Dumb Bird
Dumb Bird5mo ago
Up to you
Enceladus
EnceladusOP5mo ago
Ok
Dumb Bird
Dumb Bird5mo ago
I think in your cases a UI could be pretty easily done using an ECS For example Bevy (a popular rust framework) uses ECS for all their UI Although the reason people use it is slightly different then what you're probably thinking It's not speed, size, or anything of the like. It's actually just because it way easier to debug and with UI having so many moving parts you can decouple things.
Enceladus
EnceladusOP5mo ago
I see, thank you
Dumb Bird
Dumb Bird5mo ago
there is quite a lot of cons too not just pros I think I saw an article about bevy_ui at some point Let me find it
Enceladus
EnceladusOP5mo ago
sure
Want results from more Discord servers?
Add your server