|
SleakEngine 1.0.0
C++23 multi-backend game engine
|
This page describes the application/game/scene ownership chain, the GameObject/Component object model, and smart pointer ownership.
| Type | Role |
|---|---|
| Sleak::Application | Owns the window, the renderer, and the game loop; one per process. |
| Sleak::GameBase | Your game's top-level class; owns the scene registry and the active scene. |
| Sleak::SceneBase | Where scene behavior lives: object list, state machine, lights, physics world, camera. |
| Sleak::Scene | Thin SceneBase subclass adding the bEnableFixedUpdate toggle. |
| Sleak::GameObject | Named entity with a tag, an optional parent/child link, and attached components. |
| Sleak::Component | Base class for attached behavior with its own update hooks. |
| Sleak::RefPtr<T> | The engine's owning pointer, used in place of std::shared_ptr. |
Each arrow is real ownership. Deleting a level of the tree destroys everything below it, which is why objects are never deleted by caller code.
Per frame, Application::Run calls into the active scene, which fans the call out to its objects and their components in this order:
The three cyan hooks run every frame. Everything else runs once per load/activate cycle.
Sleak::Application (include/public/Core/Application.hpp) owns the window, the active renderer, and the game loop; one instance exists per process. Sleak::CommandLine is parsed once in main() before an Application is constructed. Application::Run(GameBase* game) drives the loop described in the rendering pipeline page.
Sleak::GameBase (include/public/Core/GameBase.hpp) is the class a game's top-level object derives from. It owns the scene registry and the active scene:
Application only drives whichever GameBase* it is given; GameBase's own Initialize(), Begin(), and Loop(deltaTime) are pure virtual and implemented by the game.
Sleak::Scene (include/public/Core/Scene.hpp) is a thin subclass of Sleak::SceneBase (include/public/Core/SceneBase.hpp) that adds one toggle, bEnableFixedUpdate. SceneBase is where scene behavior actually lives:
SceneBase owns the object list, a SceneState machine (Unloaded, Loading, Active, Paused, Unloading), a LightManager*, a Physics::PhysicsWorld* (see Physics and Spatial Partitioning), a Skybox*, and the active camera. It does not itself perform render-pass submission or frustum culling; those are handled by the renderer and the cullingsystem respectively.
Sleak::GameObject (include/public/Core/GameObject.hpp) is the base entity type. A GameObject does not automatically receive a TransformComponent: one must be added explicitly with AddComponent<TransformComponent>(...), as the static factory helpers (GameObject::CreatePlane, CreateCube, CreateSphere, ..., src/Scene/GameObject.cpp) do.
Sleak::Component (include/public/ECS/Component.hpp) is the base class for attached behavior:
Real components include TransformComponent, MeshComponent, MaterialComponent, AnimatorComponent (all under include/public/ECS/Components/), the CameraController base with its FreeLookCameraController and FirstPersonController subclasses, and RigidbodyComponent / ColliderComponent (which live under include/public/Physics/, not ECS/Components/).
Although the headers live under a folder named ECS/, this is not a data-oriented entity component system. Each GameObject owns its components directly in a List<RefPtr<Component>>; components are individually heap-allocated, GetComponent<T>() performs a linear dynamic_cast scan, and updates dispatch through virtual calls rather than a system iterating packed component arrays. It is best described as a GameObject/Component object model, similar to Unity's original MonoBehaviour composition.
GameObject instances are deleted only from within Scene. SceneBase::DestroyObject() defers deletion: it marks the object and its children with MarkForDestroy() and deletes them later in ProcessPendingDestroy(). SceneBase::RemoveObject() and DestroyAllObjects() / ~SceneBase() delete objects immediately instead. Nothing in the engine prevents calling delete on a GameObject directly, since GameObject's destructor is public, but by convention destruction always goes through one of Scene's own paths rather than caller code.
OnActivate runs before Begin, not after. GameBase::SetActiveScene deactivates the outgoing scene, activates the incoming one, initializes it if this is its first activation, fires OnActivate, and only then calls Begin. Anything Begin depends on has to be ready by OnActivate.
Begin is what actually switches objects on. It walks the scene's object list calling SetActive(true), which is the call that fires Component::OnEnable. There is no Start hook anywhere in the engine.
Inside SceneBase::Update, objects tick before the rest of the scene. The order is objects, then light manager bind, then skybox, then the physics step, then debug line flush, then deferred destruction. Object updates come first on purpose so camera matrices are current before anything reads them.
FixedUpdate and LateUpdate iterate only root objects, and each GameObject recurses into its own active children. An object parented to an inactive parent stops receiving updates even if it is active itself. Scene::FixedUpdate returns immediately unless bEnableFixedUpdate is set, so the fixed path is opt-in per scene.
| Question | File |
|---|---|
| Scene state transitions and the update order | src/Scene/SceneBase.cpp |
| Scene registry and activation order | src/Core/GameBase.cpp |
| Startup, the frame loop, and shutdown | src/Core/Application.cpp |
| Component storage, hierarchy, and factories | src/Scene/GameObject.cpp |
| The component hook contract | include/public/ECS/Component.hpp |
| Reference counting and the control block | include/public/Memory/RefPtr.hpp |