docsReading time: 3 minutes
General
Basics
- Getting Started
- Game API
- Input API
- Configuration
- Tile Maps
- Resource Management
- Entity Framework
- Control Entities
- User Interface
- utiLITI
- Deployment
- Savegames
- Libraries and Tools
- Glossary
Advanced
- The Particle System
- Dynamic Lighting
- Static Lighting
- Performance Optimization
- Custom MapObjectLoaders
- String Localization
- Object Serialization
- Utility Classes
- Network Communication
- Advanced Entity Knowledge
Tutorials
Game Loop
LITIENGINE uses a game loop architecture where game logic and rendering are decoupled from variable framerates. The engine internally manages two separate loops:
- Game Loop (
Game.loop()) – Handles game logic AND rendering at a fixed tick rate - Input Loop – Processes player input independently (internal, not directly accessible)
This design ensures consistent game behavior regardless of hardware performance.
The Main Game Loop – Game.loop()
The Game.loop() method returns the main IGameLoop that executes all game logic and triggers rendering. It runs at a fixed tick rate (default: 60 ticks/second), ensuring physics, AI, and other time-dependent systems behave consistently.
Note: The game’s loop also executes the rendering process. This internally renders the currently active screen which passes the
Graphics2Dobject to allGuiComponentsand the Environment for rendering.
IUpdateable Interface
To execute custom logic every tick, implement the IUpdateable interface and attach it to the loop:
public class MyEntity extends Entity implements IUpdateable {
@Override
public void update() {
// This code runs every tick (default: 60 times per second)
setLocation(getX() + 1, getY());
}
}
// Attach the entity to the game loop
MyEntity entity = new MyEntity();
Game.loop().attach(entity);
// Later, detach when no longer needed
Game.loop().detach(entity);Loop Properties
// Get the time passed since the last tick (in milliseconds)
long deltaTime = Game.loop().getDeltaTime();
// Get total ticks since game started
long totalTicks = Game.loop().getTicks();
// Get the current tick rate (ticks per second)
int tickRate = Game.loop().getTickRate();
// Modify tick rate (default is 60)
Game.loop().setTickRate(30);Timed Actions
Schedule actions to execute after a delay:
// Execute after 2 seconds (120 ticks at 60 tick rate)
int actionId = Game.loop().execute(120, () -> {
System.out.println("Delayed action executed!");
});
// Cancel a timed action by setting execution time to -1
Game.loop().alterExecutionTime(actionId, -1);Why Separate Loops?
LITIENGINE separates game logic/rendering from input processing for several advantages:
- Consistent Physics: Game logic runs at a fixed rate, preventing physics bugs from variable framerates
- Responsive Controls: Input processing continues even if rendering slows
- Predictable Behavior: Game state updates are deterministic
- Decoupled Systems: Input doesn’t interfere with game logic timing
Configuration
Configure loop behavior in your config.properties:
# Game loop tick rate (updates per second)
client_updaterate=60
# Maximum FPS (0 = unlimited)
cl_maxFps=60
# Show game metrics (FPS, UPS)
cl_showGameMetrics=falseCommon Patterns
Entity with Update Logic
@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;
}
// AI behavior runs every tick
chasePlayer();
}
private void chasePlayer() {
// Movement logic
}
}Game State Timer
public class GameTimer implements IUpdateable {
private int secondsRemaining;
public GameTimer(int seconds) {
this.secondsRemaining = seconds;
Game.loop().attach(this);
}
@Override
public void update() {
// Track time using deltaTime
// 60 ticks = 1 second at default tick rate
}
}See Also
- Game.world() – Environment management
- Game.screens() – Screen management
- Player Input – Input handling details
Last updated 2 months ago
