The Game Loop
Every game is a loop. Dozens of times per second, the engine checks input, updates the world, and draws a new frame. Understanding this loop is the key to making things happen in HELIX.
The Big Three
BeginPlay — "The curtain rises"
Called once when an Actor enters the world. This is where you set up initial state: grab references, set default variables, play an intro animation. Think of it as your Actor's constructor for gameplay logic.
Tick — "Every single frame"
Called every frame (30, 60, 120+ times per second depending on framerate). Anything you put here runs constantly. Moving a platform, checking a distance, interpolating a value — Tick handles the continuous stuff.
EndPlay — "Lights out"
Called once when an Actor is destroyed or the game ends. Clean up timers, save data, release resources. If BeginPlay is where you set things up, EndPlay is where you tear them down.
Code Examples
- Blueprint
- Lua
- JavaScript
BeginPlay — Print a message on start:
Tick — Move an Actor upward each frame:
C++ equivalent (for reference)
void AMyActor::BeginPlay()
{
Super::BeginPlay();
UE_LOG(LogTemp, Log, TEXT("Hello, HELIX!"));
}
void AMyActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
FVector Loc = GetActorLocation();
Loc.Z += 50.0f * DeltaTime; // Move up 50 units/sec
SetActorLocation(Loc);
}
function MyActor:ReceiveBeginPlay()
-- Runs once when the actor spawns
print("Hello, HELIX!")
end
function MyActor:ReceiveTick(DeltaTime)
-- Runs every frame
local loc = self:K2_GetActorLocation()
loc.Z = loc.Z + 50.0 * DeltaTime
self:K2_SetActorLocation(loc, false, nil, true)
end
function MyActor:ReceiveEndPlay(Reason)
-- Cleanup when the actor is destroyed
print("Goodbye!")
end
class MyActor extends ue.Actor {
ReceiveBeginPlay() {
// Runs once when the actor spawns
console.log("Hello, HELIX!");
}
ReceiveTick(deltaTime) {
// Runs every frame
let loc = this.K2_GetActorLocation();
loc.Z += 50.0 * deltaTime;
this.K2_SetActorLocation(loc, false, undefined, true);
}
ReceiveEndPlay(reason) {
// Cleanup when the actor is destroyed
console.log("Goodbye!");
}
}
Event-Driven vs Tick-Based: Choose Wisely
Tick runs every frame whether something changed or not. That's expensive. If 200 actors all have Tick enabled, that's 200 functions running 60+ times per second.
Events fire only when something actually happens — a key is pressed, a collision occurs, a timer goes off. They're far cheaper.
| Use Tick for... | Use Events for... |
|---|---|
| Smooth continuous movement | Button presses |
| Real-time distance checks | Collisions and overlaps |
| Interpolating values over time | Timers and delays |
| Constant animation offsets | State changes |
If you can do it with an event, do it with an event. Disable Tick on actors that don't need it (uncheck Start with Tick Enabled in the class defaults). Your framerate will thank you, especially in multiplayer where every connected player adds load.