Game Loop¶
The GameLoop is the heart of LITIENGINE. It coordinates logic updates, physics calculations, timed actions, and rendering in a deterministic sequence on each tick.
Game Loop Architecture¶
In LITIENGINE, the main GameLoop executes update logic and triggers the render pass sequentially within each tick iteration:
flowchart TD
subgraph InputProcessing["Input Device Polling"]
HW["Hardware Devices"] --> InputState["Input.keyboard / Input.mouse / Input.gamepads"]
end
subgraph TickExecution["GameLoop.process() (Tick Interval: 1000 / getTickRate())"]
Step1["1. updateInvariableEngineComponents() (Clock & runtime state)"] --> Step2["2. super.process() (Update IUpdateable components & active Environment)"]
Step2 --> Step3["3. executeTimedActions() (Evaluate perform callbacks)"]
Step3 --> Step4["4. updateCamera() (Focus target tracking & shake offsets)"]
Step4 --> Step5["5. render() (Render active Screen on Graphics2D canvas)"]
Step5 --> Step6["6. trackMetrics() (Compute FPS, UPS, and frame timing)"]
end
Execution Order in GameLoop.process()¶
On every tick, GameLoop runs the following stages sequentially:
- Invariable Engine Updates: Updates internal runtime components and state.
IUpdateableExecution & Environment: Iterates over registeredIUpdateablecomponents, advancing entity behaviors, physics simulation, and particle systems.- Timed Action Dispatch: Evaluates scheduled delay callbacks registered via
Game.loop().perform(...). - Camera Focus Update: Recalculates camera target tracking, bounding box map clamping, and screen shake trauma offsets.
- Screen & Component Render: Renders the active
Screenand environment layers via the AWT graphics pipeline to the window render canvas. - Metrics Tracking: Records tick execution duration and calculates live FPS / UPS metrics.
Using Game.loop()¶
The Game.loop() method provides global access to the active IGameLoop:
The IUpdateable Interface¶
To execute custom game logic every tick, implement IUpdateable and attach your object to the loop:
public class MovingPlatform extends Entity implements IUpdateable {
public MovingPlatform() {
super("platform");
Game.loop().attach(this);
}
@Override
public void update() {
// This method executes on every game loop tick
setLocation(getX() + 1, getY());
}
public void destroy() {
// Detach when no longer active
Game.loop().detach(this);
}
}
Tick Rate & Timing Configuration¶
The tick interval is dynamically calculated based on the configured tick rate:
// Get the time passed since the last tick (in milliseconds)
long deltaTime = Game.loop().getDeltaTime();
// Get total tick count since game startup
long totalTicks = Game.loop().getTicks();
// Current tick rate (default: 60 ticks/second)
int tickRate = Game.loop().getTickRate();
// Adjust the tick rate programmatically
Game.loop().setTickRate(60);
Configuring Max FPS¶
The engine tick rate and frame rate target are configured via client properties or Game.config():
# Maximum FPS and update tick rate (default: 60)
cl_maxFps=60
# Show game metrics overlay (FPS, UPS)
cl_showGameMetrics=false
Scheduling Timed Actions¶
GameLoop provides built-in action schedulers without needing raw Java Thread.sleep or timer threads:
// Schedule an action to execute after a delay in milliseconds (e.g. 2000 ms = 2 seconds)
int actionId = Game.loop().perform(2000, () -> {
System.out.println("Delayed task executed!");
});
// Cancel a scheduled action by its ID before it executes
Game.loop().removeAction(actionId);
Common Patterns¶
Entity AI Update with Lifecycle Cleanup¶
@EntityInfo(width = 32, height = 32)
public class Enemy extends Creature implements IUpdateable {
public Enemy() {
super("enemy");
Game.loop().attach(this);
}
@Override
public void update() {
if (this.isDead()) {
Game.loop().detach(this);
return;
}
chasePlayer();
}
private void chasePlayer() {
// Enemy movement and AI logic
}
}
See Also¶
- Game World & Environments - Loading maps and managing entity lifecycles
- Screens & Game States - Managing title, gameplay, and UI screens
- Player Input - Handling keyboard, mouse, and gamepads