This is a game engine created in Spring 2023 by Thuleanx for Brown's 3D Game Engine course. It is written from scratch, with the exception of a stencil graphics library, and heavily uses OpenGL and a custom Entity Component System. Here are the main selling points of the engine:
- Simple: Saga::Component can be any struct or class, Saga::Systems are any function that accepts a Saga::GameWorld, and Saga::Entity is an integer.
- Fast: Continuous collision detection runs at 60 fps even with a scene with 130000+ triangles on its mesh colliders. All dynamic colliders are modelled as axis-aligned ellipsoids, which means fast continuous collision detection.
- Integration: With FMOD Audio Engine for adaptive 3D sound, and imgui for editor GUI.
How it works
Applications inherits from App and is managed by Core. They manage a collection of active GameWorld, each containing entities, components, and systems. Applications can create and add the current game world to the list of active game world by running:
std::shared_ptr<GameWorld> world = createGameWorld();
After this, entities, components, and systems can be added to the world. For instance, to add a Sphere that circles around the origin, you can do:
Saga::Entity entity = world->createEntity();
auto objectCirclingSystem = [](std::shared_ptr<Saga::GameWorld> world,
float time, float deltaTime) {
glm::vec2 orbitDir(std::cos(time), std::sin(time));
float orbitDistance = 3;
transform->setPos(orbitDistance * orbitDir);
}
};
world->getSystems()->addStagesSystem(objectCirclingSystem, Stage::Update);
Wrapper around the GraphisEngine's material.
Definition: material.h:13
A wrapper around a shared_ptr to a GraphicsEngine's shape.
Definition: mesh.h:11
Under the hood, Saga stores components next to each other in memory, allowing for better cache locality when iterating through all components of the same type. Of course, one can also iterate through a group of components, which contains all entities with the specified components. The following code iterate through all meshes and draw them on screen.
{c++}
void drawSystem(std::shared_ptr<GameWorld> world) {
//... setup camera
for (auto [entity, material, mesh, transform] : *world->viewGroup<Material, Mesh, Transform>()) {
GraphicsEngine::Global::graphics.drawShape(*mesh, *transform, *material);
}
}
If these groups are registered beforehand with `registerGroup`, then these group can be iterated through in $O(n)$ where n is the number of elements in the group.