🎯 目标:
掌握 UE5 中的 Tick() 函数,学习如何让 Actor 动态移动、旋转、缩放,实现游戏对象的实时更新!
1️⃣ 什么是 Tick() 函数?
在 Unreal Engine 5(UE5) 中,Tick(float DeltaTime) 是 Actor 每一帧都会执行的函数,用于持续更新对象状态,如:
- 移动(不断调整位置)
- 旋转(物体持续转动)
- 动画更新(实时改变外观)
- AI 行为(控制敌人移动、追踪玩家)
🔹 Tick() 的核心概念
- DeltaTime:当前帧的时间间隔(秒),用于 帧率无关的平滑运动。
- 默认情况下,Tick 是禁用的,需要在 构造函数中启用。
2️⃣ 如何在 C++ 中启用 Tick()
🔹 创建一个新的 Actor
- 在 UE5 中,点击 “工具” → “新建 C++ 类”。
- 选择 Actor 作为基类,命名为 MovingActor。
- 创建并添加到项目,等待 UE5 生成代码并打开 Visual Studio。
- 找到MovingActor,并将其拖入到场景中
🔹 在 C++ 代码中启用 Tick
📌 修改 MovingActor.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "MovingActor.generated.h"
UCLASS()
class MYFIRSTCPPGAME_API AMovingActor : public AActor
{
GENERATED_BODY()
public:
AMovingActor();
UPROPERTY(VisibleAnywhere)
UStaticMeshComponent* MeshComponent;
protected:
virtual void BeginPlay() override;
public:
virtual void Tick(float DeltaTime) override;
};
📌 修改 MovingActor.cpp
#include "MovingActor.h"
AMovingActor::AMovingActor()
{
PrimaryActorTick.bCanEverTick = true; // 启用 Tick()
MeshComponent = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("MeshComponent"));
RootComponent = MeshComponent;
static ConstructorHelpers::FObjectFinder<UStaticMesh> MeshAsset(TEXT("/Engine/BasicShapes/Cube.Cube"));
if (MeshAsset.Succeeded()) {
MeshComponent->SetStaticMesh(MeshAsset.Object);
}
}
void AMovingActor::BeginPlay()
{
Super::BeginPlay();
}
void AMovingActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
UE_LOG(LogTemp, Warning, TEXT("Ticking every frame! DeltaTime: %f"), DeltaTime);
}
🎮 运行后,你将在 Output Log 看到 “Ticking every frame!”,说明 Tick() 已成功启用!
3️⃣ 使用 Tick() 让 Actor 移动
现在,我们让 MovingActor 沿 X 轴前进,实现 持续移动:
void AMovingActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
FVector NewLocation = GetActorLocation();
NewLocation.X += 100 * DeltaTime; // 每秒前进 100 单位
SetActorLocation(NewLocation);
}
💡 解释:
- GetActorLocation() 获取当前坐标。
- NewLocation.X += 100 * DeltaTime; 每秒移动 100 单位。
- SetActorLocation(NewLocation); 设置新位置。
✅ 运行游戏,Actor 将自动向前移动! 🎮
4️⃣ 使用 Tick() 让 Actor 旋转
如果想让 Actor 不断旋转,可以这样做:
void AMovingActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
FRotator NewRotation = GetActorRotation();
NewRotation.Yaw += 90 * DeltaTime; // 每秒旋转 90 度
SetActorRotation(NewRotation);
}
✅ 运行游戏,Actor 将持续旋转! 🔄
5️⃣ 使用 Tick() 让 Actor 缩放
我们可以让 Actor 周期性地放大和缩小:
void AMovingActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
float Time = GetWorld()->GetTimeSeconds();
float ScaleFactor = FMath::Sin(Time) * 0.5f + 1.0f; // 生成 0.5 - 1.5 之间的缩放
SetActorScale3D(FVector(ScaleFactor));
}
✅ 运行游戏,Actor 将周期性地变大变小! ⚡
6️⃣ 优化 Tick() 性能
🔹 什么时候不应该使用 Tick()?
过度使用 Tick() 可能会影响游戏性能,尤其是在有 大量 Actor 需要更新时。如果 Actor 不需要每帧更新,可以使用:
- 定时器(Timers) 让对象 间隔执行,减少 Tick 负担:
GetWorldTimerManager().SetTimer(TimerHandle, this, &AMovingActor::SomeFunction, 2.0f, true); //
每 2 秒执行一次 SomeFunction(),而不是每帧调用 Tick()!
- 基于事件触发(Event-Driven),如 Overlap、输入等,而不是持续计算。
🔹 关闭 Tick() 以提升性能
如果对象 不再需要更新,可以 禁用 Tick:
SetActorTickEnabled(false);
💡 这样可以显著提升游戏性能!
7️⃣ 常见问题 & 解决方案
问题 | 解决方案 |
---|---|
Tick() 没有触发 | 确保 PrimaryActorTick.bCanEverTick = true; |
Actor 速度太快或太慢 | 调整 DeltaTime 乘数(如 X += 100 * DeltaTime;) |
Actor 移动或旋转不正确 | 检查 GetActorLocation() / GetActorRotation() 的使用方式 |
Tick() 影响性能 | 使用定时器或事件触发代替 Tick() |
🎯 总结:今天你学到了什么?
✅ 理解 Tick() 的作用(每帧执行更新)
✅ 让 Actor 移动、旋转、缩放
✅ 优化 Tick(),避免不必要的性能开销
👏 恭喜你完成 Tick() 学习! 🎮 明天我们将探索 输入控制(Input),让玩家控制游戏对象! 🚀
📌 记得收藏专栏,每天进步一点,最终独立开发属于你的 UE5 游戏! 🔥