The tick system executes game logic every frame. Classes receive time delta values and can implement update logic, movement, input handling, etc.
Architecture
The engine runs ticks in this order each frame:
- GameModule::preTick()
- All ITickable::preTick() (entities with Ecs::Tick component)
- GameModule::tick(deltaTime)
- All ITickable::tick(deltaTime) (entities with Ecs::Tick component)
- GameModule::postTick()
- All ITickable::postTick() (entities with Ecs::Tick component)
ITickable Interface
Classes that implement the tick interface inherit from EngineCore::ITickable.
File: Engine/include/Engine/Core/Tick.h
Methods
virtual void preTick();
virtual void tick(double deltaTimeSeconds);
virtual void postTick();
All methods have empty default implementations. Override only what you need.
Example: Actor with Tick
class MyActor : public EngineCore::Actor {
public:
void tick(double deltaTime) override {
Actor::tick(deltaTime);
position += velocity * deltaTime;
}
};
Entity and Actor already inherit from ITickable. Override tick() directly.
Enabling Tick
Entities don't tick by default. You must enable ticking.
Scene Tick
Engine::Entities::Scene inherits from Engine::Core::ITickable, so a scene subclass can override tick(double). The active scene is not registered in the ECS tick view, so overriding Scene::tick() alone does not make it run.
Forward tick from your GameModule if you want the active scene to receive per-frame updates.
Scene Subclass
public:
}
void tick(
double deltaTimeSeconds)
override {
}
};
virtual void tick(double deltaTimeSeconds)
Function called each frame when a tick component has been registered with EnTT Ecs::Tick.
A scene is the overarching structure which can spawn, contain and destroy actors or entities.
virtual void loadContent()
GameModule Forwarding
void MyGame::tick(float deltaTime) {
GameModule::tick(deltaTime);
if (engine == nullptr) {
return;
}
if (scene != nullptr) {
scene->tick(static_cast<double>(deltaTime));
}
}
const std::unique_ptr< Core::SceneManager > & getSceneManager() const
static EngineManager & getInstance()
gets a reference to the engine manager
EngineKern * getEngineModule()
gets the pointer to the engine object
With this wiring, MyGame::tick() calls the active scene before the engine calls tick-enabled entities. Move the scene call inside MyGame::tick() if you need game-level work before or after scene logic.
Do not call enableTick(true) on a scene. Only Entity and Actor expose enableTick() because they own an EnTT entity handle.
If a scene needs preTick() or postTick(), forward those from GameModule::preTick() and GameModule::postTick() the same way.
For Entity/Actor
class MyActor : public EngineCore::Actor {
public:
MyActor(std::shared_ptr<SceneNode> node, Scene* scene)
: Actor(node, scene) {
enableTick(true);
}
void tick(double deltaTime) override {
Actor::tick(deltaTime);
}
};
What enableTick Does
Adds an Ecs::Tick component to the entity's EnTT registry entry:
void Entity::enableTick(bool enable) {
auto& registry = Ecs::RegistryManager::get();
if (enable) {
registry.emplace<Ecs::Tick>(data, this);
} else {
registry.remove<Ecs::Tick>(data);
}
}
The engine queries all entities with Ecs::Tick each frame and calls their tick methods.
LogicComponent Tick
LogicComponent doesn't inherit from ITickable but has its own tick system.
Enabling Component Tick
class MyComponent : public EngineCore::LogicComponent {
public:
MyComponent(Scene* scene) : LogicComponent(scene) {
setCanTick(true);
}
void tick(double deltaTime) override {
}
};
How It Works
Actor::tick() iterates through components and calls tick() on those with ticking enabled:
void Actor::tick(double deltaTime) {
Entity::tick(deltaTime);
for (auto& component : components) {
if (component->canTick()) {
component->tick(deltaTime);
}
}
}
Non-ITickable Classes
For classes that don't inherit from ITickable, wrap them or call their update methods manually.
Option 1: Manual Calls in Actor
class ThirdPartySystem {
public:
void update(float dt) { }
};
class MyActor : public EngineCore::Actor {
ThirdPartySystem system_;
public:
void tick(double deltaTime) override {
Actor::tick(deltaTime);
system_.update(static_cast<float>(deltaTime));
}
};
Option 2: Wrap in LogicComponent
class ThirdPartySystem {
public:
void update(float dt) { }
};
class ThirdPartySystemComponent : public EngineCore::LogicComponent {
ThirdPartySystem system_;
public:
ThirdPartySystemComponent(Scene* scene) : LogicComponent(scene) {
setCanTick(true);
}
void tick(double deltaTime) override {
system_.update(static_cast<float>(deltaTime));
}
};
actor->addComponent<ThirdPartySystemComponent>(scene);
Option 3: Ticker Class (Unused)
The codebase includes EngineCore::Ticker but it's not connected to the main loop. The tick() method is empty. Use the EnTT-based system instead.
GameModule Tick
Override GameModule methods for global game logic.
File: Engine/include/Engine/Game/GameModule.h
class MyGame : public EngineCore::GameModule {
public:
void preTick() override {
}
void tick(float deltaTime) override {
gameTime_ += deltaTime;
}
void postTick() override {
}
};
Async Tick (Asset Pipelines)
Asset pipelines use tick() for state machine advancement, not frame timing.
Example: Ecs::ModelAssetPipeline::tick(bool async)
void tick(bool async = true) {
submitLoadModel(async);
processModel(async);
processMaterial(async);
processMeshData(async);
}
These ticks happen each frame but advance background loading tasks. The async parameter controls whether work happens on background threads or the main thread.
Delta Time
Delta time is the seconds elapsed since the last frame.
Get delta time:
double dt = EngineManager::getInstance().getEngineModule()->getDeltaTimeSeconds();
Typical usage:
void tick(double deltaTime) {
position += direction * 5.0f * static_cast<float>(deltaTime);
rotation += 90.0f * static_cast<float>(deltaTime);
}
Checking Tick State
if (entity->canTick()) { }
if (entity->canEverTick()) { }
if (component->canTick()) { }
Summary
| Class Type | Inherits ITickable? | How to Enable | Tick Method |
| Entity/Actor | Yes | enableTick(true) | Override tick() |
| LogicComponent | No | setCanTick(true) | Override tick() |
| GameModule | No | Always ticks | Override tick() |
| Scene | Yes | Forward active scene tick from GameModule | Override tick() |
| Other classes | No | Wrap in component or call manually | N/A |
Default execution order: GameModule → Entities (with Ecs::Tick) → Components (within their entity)
Scene forwarding order: GameModule → Scene (where you call it) → Entities (with Ecs::Tick) → Components (within their entity)
Files: