タイトル: 毎秒実行するイベントの定義方法
SEOタイトル: UE5 毎秒実行 (Timer) 完全ガイド
| この記事の要点 |
|
UE5 でタイマーを使う 3 つの方法
| 方法 | 用途 | 負荷 |
|---|---|---|
| Set Timer by Event / Function Name | 一定間隔で実行 (1 秒毎、5 秒毎) | 軽い |
| Event Tick | 毎フレーム実行 (60〜120 回/秒) | 重い(軽い処理に限定) |
| Delay ノード (Latent) | 一回だけ N 秒後実行 | 軽い |
方法1: Set Timer by Event (Blueprint 推奨)
もっとも一般的。1 秒ごとにイベントを呼びたい場合:
Event BeginPlay
→ Set Timer by Event
Event: [Custom Event "OnSecondTick"]
Time: 1.0
Looping: true
→ 戻り値の Handle 変数を保存
カスタムイベントを定義
Custom Event: OnSecondTick
→ Print String: "1 秒経過"
→ Stamina -= 1
→ Update HUD
方法2: Set Timer by Function Name (C++ 主流)
C++ では UWorld::GetTimerManager から取得する FTimerManager 経由で設定:
// MyCharacter.h
private:
FTimerHandle SecondTickHandle;
UFUNCTION()
void OnSecondTick();
// MyCharacter.cpp
void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
// 1 秒ごとに OnSecondTick() を呼ぶ
GetWorld()->GetTimerManager().SetTimer(
SecondTickHandle,
this,
&AMyCharacter::OnSecondTick,
1.0f, // 間隔 (秒)
true // ループ
);
}
void AMyCharacter::OnSecondTick()
{
UE_LOG(LogTemp, Log, TEXT("Tick at %.2f"), GetWorld()->GetTimeSeconds());
Stamina = FMath::Max(0.0f, Stamina - 1.0f);
}
void AMyCharacter::EndPlay(const EEndPlayReason::Type Reason)
{
// タイマー解除(リーク防止)
if (UWorld* W = GetWorld())
{
W->GetTimerManager().ClearTimer(SecondTickHandle);
}
Super::EndPlay(Reason);
}
方法3: Set Timer for Next Tick
「1 フレームだけ遅延して実行」したい場合(次フレームに値を見たい等):
GetWorld()->GetTimerManager().SetTimerForNextTick(
[this]()
{
// 次フレームで実行される
UE_LOG(LogTemp, Log, TEXT("Next tick"));
}
);
Tick イベント (毎フレーム実行)
1 秒に何度も実行したいなら Timer ではなく Tick。DeltaSeconds で正規化が必須:
void AMyActor::Tick(float DeltaSeconds)
{
Super::Tick(DeltaSeconds);
// ❌ 悪い例 (フレームレートで速度が変わる)
// Position.X += 1.0f;
// ✅ 良い例 (秒速で正規化)
Position.X += Speed * DeltaSeconds;
SetActorLocation(Position);
}
// Actor の Tick を有効化(コンストラクタで)
AMyActor::AMyActor()
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.TickInterval = 0.0f; // 0 = 毎フレ
}
// 任意間隔の Tick (Timer 代替)
AMyActor::AMyActor()
{
PrimaryActorTick.bCanEverTick = true;
PrimaryActorTick.TickInterval = 0.5f; // 0.5 秒ごと
}
Timer の主要 API
| 関数 | 説明 |
|---|---|
SetTimer(Handle, Obj, Func, Rate, bLoop, FirstDelay) | タイマー開始 |
SetTimerForNextTick(Func) | 次フレーム実行 |
ClearTimer(Handle) | 停止 |
PauseTimer(Handle) | 一時停止 |
UnPauseTimer(Handle) | 再開 |
IsTimerActive(Handle) | 動作中か |
GetTimerRemaining(Handle) | 残り時間 |
GetTimerElapsed(Handle) | 経過時間 |
GetTimerRate(Handle) | 設定間隔 |
具体的なユースケース
HP リジェネレーション
// 5 秒間ダメージを受けないと、1 秒ごとに +5 HP
void AMyCharacter::TakeDamageEvent(float Dmg)
{
HP -= Dmg;
// ダメージ受けたらリジェネ Timer 解除
GetWorld()->GetTimerManager().ClearTimer(RegenHandle);
// 5 秒後にリジェネ開始
GetWorld()->GetTimerManager().SetTimer(
RegenStartHandle,
[this]()
{
GetWorld()->GetTimerManager().SetTimer(
RegenHandle,
this, &AMyCharacter::Regen,
1.0f, true // 1 秒ごとループ
);
},
5.0f, false // 5 秒後一回
);
}
void AMyCharacter::Regen()
{
HP = FMath::Min(MaxHP, HP + 5.0f);
}
スポーン処理 (3 秒ごとに敵生成)
void ASpawner::BeginPlay()
{
Super::BeginPlay();
GetWorld()->GetTimerManager().SetTimer(
SpawnHandle,
this, &ASpawner::SpawnEnemy,
3.0f, true
);
}
void ASpawner::SpawnEnemy()
{
if (EnemyClass)
{
FActorSpawnParameters Params;
GetWorld()->SpawnActor<AEnemy>(EnemyClass, GetActorLocation(), FRotator::ZeroRotator, Params);
}
}
カウントダウン UI
void AMyController::StartCountdown(int32 Seconds)
{
RemainingSeconds = Seconds;
GetWorld()->GetTimerManager().SetTimer(
CountdownHandle,
this, &AMyController::TickCountdown,
1.0f, true
);
}
void AMyController::TickCountdown()
{
RemainingSeconds--;
UpdateHUD(RemainingSeconds);
if (RemainingSeconds <= 0)
{
GetWorld()->GetTimerManager().ClearTimer(CountdownHandle);
OnCountdownFinished();
}
}
Niagara System での Tick 制御
パーティクル側で「毎秒スポーン」は Niagara の Spawn Rate モジュールを使うのが正解。Blueprint Timer で Activate / Deactivate を切り替える方法も:
// 毎秒パーティクル発射
GetWorld()->GetTimerManager().SetTimer(
FXHandle,
[this]()
{
UNiagaraFunctionLibrary::SpawnSystemAtLocation(
this, FXSystem, GetActorLocation()
);
},
1.0f, true
);
パフォーマンス注意
- Timer はTick より大幅に軽い(必要なときだけ呼ばれる)
- ただし大量に作るとマネージャ自体の負荷になるので、1 アクタに数個まで
- Tick は最終手段。毎フレ更新が本当に必要か再考
- 不要になった Timer は必ず ClearTimer(リークでメモリ・CPU 共に圧迫)
- キャラ EndPlay / Destroy では Timer 自動解除されるが、念のため明示的に
FAQ
Q: Timer と Tick、結局どちらを使うべき?
A: 0.1 秒以上の周期なら Timer、毎フレ位置更新やアニメ補間なら Tick。判断基準は「FPS に関係するか」。
Q: タイマーが止まらない
A: FTimerHandle を保存し損ねている可能性大。SetTimer の戻り値(out 引数)を確実にメンバ変数として保持する。
Q: ゲームを一時停止すると Timer も止まる?
A: デフォルトでは止まります。SetTimerInPausedState やカスタム TimerManager で動作継続可能。