unreal
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseUnreal Engine Development Skill
Unreal Engine 开发技能
Engine Detection
引擎识别
Look for: , , , , , ,
.uproject.Build.cs.upluginSource/Content/Config/DefaultEngine.iniBinaries/查找以下文件/目录:、、、、、、
.uproject.Build.cs.upluginSource/Content/Config/DefaultEngine.iniBinaries/Project Structure
项目结构
MyGame/
Source/
MyGame/
Public/ # Headers (.h)
Player/
Enemies/
UI/
Systems/
Private/ # Implementation (.cpp)
Player/
Enemies/
UI/
Systems/
MyGame.Build.cs
MyGame.h
Content/
Blueprints/
Maps/
Materials/
Textures/
Meshes/
Audio/
UI/
Config/
DefaultEngine.ini
DefaultGame.ini
DefaultInput.ini
Plugins/
MyGame.uprojectMyGame/
Source/
MyGame/
Public/ # 头文件(.h)
Player/
Enemies/
UI/
Systems/
Private/ # 实现文件(.cpp)
Player/
Enemies/
UI/
Systems/
MyGame.Build.cs
MyGame.h
Content/
Blueprints/
Maps/
Materials/
Textures/
Meshes/
Audio/
UI/
Config/
DefaultEngine.ini
DefaultGame.ini
DefaultInput.ini
Plugins/
MyGame.uprojectActor/Component Architecture
Actor/Component 架构
Unreal uses an Actor/Component model. Actors are placed in the world, Components add functionality:
cpp
// Header - Public/Player/MyCharacter.h
UCLASS()
class MYGAME_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
AMyCharacter();
protected:
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(UInputComponent* Input) override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
float MaxHealth = 100.f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
UHealthComponent* HealthComponent;
UFUNCTION(BlueprintCallable, Category = "Combat")
void TakeDamage(float Amount, AActor* DamageCauser);
private:
UPROPERTY()
float CurrentHealth;
};cpp
// Implementation - Private/Player/MyCharacter.cpp
AMyCharacter::AMyCharacter()
{
PrimaryActorTick.bCanEverTick = true;
HealthComponent = CreateDefaultSubobject<UHealthComponent>(TEXT("HealthComp"));
}
void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
CurrentHealth = MaxHealth;
}Unreal 采用 Actor/Component 模型。Actor 被放置在游戏世界中,Component 用于添加功能:
cpp
// Header - Public/Player/MyCharacter.h
UCLASS()
class MYGAME_API AMyCharacter : public ACharacter
{
GENERATED_BODY()
public:
AMyCharacter();
protected:
virtual void BeginPlay() override;
virtual void Tick(float DeltaTime) override;
virtual void SetupPlayerInputComponent(UInputComponent* Input) override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
float MaxHealth = 100.f;
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
UHealthComponent* HealthComponent;
UFUNCTION(BlueprintCallable, Category = "Combat")
void TakeDamage(float Amount, AActor* DamageCauser);
private:
UPROPERTY()
float CurrentHealth;
};cpp
// Implementation - Private/Player/MyCharacter.cpp
AMyCharacter::AMyCharacter()
{
PrimaryActorTick.bCanEverTick = true;
HealthComponent = CreateDefaultSubobject<UHealthComponent>(TEXT("HealthComp"));
}
void AMyCharacter::BeginPlay()
{
Super::BeginPlay();
CurrentHealth = MaxHealth;
}UPROPERTY Specifiers
UPROPERTY 说明符
cpp
// Editable in editor, readable/writable in Blueprints
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
float Speed;
// Only visible in editor, read-only in Blueprints
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
USceneComponent* Root;
// Replicated for multiplayer
UPROPERTY(Replicated)
int32 Score;
// Replicated with notification
UPROPERTY(ReplicatedUsing = OnRep_Health)
float Health;cpp
// 可在编辑器中编辑,在 Blueprints 中可读可写
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
float Speed;
// 仅在编辑器中可见,在 Blueprints 中只读
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
USceneComponent* Root;
// 用于多人游戏同步
UPROPERTY(Replicated)
int32 Score;
// 同步并触发通知
UPROPERTY(ReplicatedUsing = OnRep_Health)
float Health;Blueprints vs C++ Decision Guide
Blueprints 与 C++ 选择指南
Use C++ for:
- Core gameplay systems and base classes
- Performance-critical code (AI, physics, networking)
- Complex algorithms and data structures
- Low-level engine interaction
- Systems other programmers will extend
Use Blueprints for:
- Level-specific scripting and sequences
- UI logic and widget behavior
- Quick prototyping and iteration
- Designer-tunable parameters
- Visual effects and animation triggers
Best pattern: C++ base class + Blueprint child class
cpp
// C++ base with BlueprintNativeEvent
UFUNCTION(BlueprintNativeEvent, Category = "Combat")
void OnDeath();
void OnDeath_Implementation(); // Default C++ behavior, overridable in BP优先使用 C++ 的场景:
- 核心游戏玩法系统与基类
- 性能敏感型代码(AI、物理、网络)
- 复杂算法与数据结构
- 底层引擎交互
- 供其他开发者扩展的系统
优先使用 Blueprints 的场景:
- 关卡专属脚本与序列
- UI 逻辑与控件行为
- 快速原型制作与迭代
- 设计师可调整的参数
- 视觉效果与动画触发
最佳模式:C++ 基类 + Blueprints 子类
cpp
// 带 BlueprintNativeEvent 的 C++ 基类
UFUNCTION(BlueprintNativeEvent, Category = "Combat")
void OnDeath();
void OnDeath_Implementation(); // 默认 C++ 行为,可在 BP 中重写Gameplay Ability System (GAS)
游戏玩法能力系统(GAS)
For complex ability/effect systems:
cpp
// Ability
UCLASS()
class UGA_FireBall : public UGameplayAbility
{
GENERATED_BODY()
public:
virtual void ActivateAbility(...) override;
virtual void EndAbility(...) override;
virtual bool CanActivateAbility(...) const override;
};
// Gameplay Effect for damage
UCLASS()
class UGE_FireDamage : public UGameplayEffect
{
// Configure in editor: damage value, duration, tags
};适用于复杂的能力/效果系统:
cpp
// 能力类
UCLASS()
class UGA_FireBall : public UGameplayAbility
{
GENERATED_BODY()
public:
virtual void ActivateAbility(...) override;
virtual void EndAbility(...) override;
virtual bool CanActivateAbility(...) const override;
};
// 用于伤害的游戏玩法效果
UCLASS()
class UGE_FireDamage : public UGameplayEffect
{
// 在编辑器中配置:伤害值、持续时间、标签
};Delegates & Events
委托与事件
cpp
// Single-cast delegate
DECLARE_DELEGATE_OneParam(FOnHealthChanged, float);
// Multi-cast delegate (Blueprint compatible)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChangedDynamic, float, NewHealth);
// Usage in class
UPROPERTY(BlueprintAssignable)
FOnHealthChangedDynamic OnHealthChanged;
// Broadcast
OnHealthChanged.Broadcast(CurrentHealth);cpp
// 单播委托
DECLARE_DELEGATE_OneParam(FOnHealthChanged, float);
// 多播委托(兼容 Blueprints)
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealthChangedDynamic, float, NewHealth);
// 在类中使用
UPROPERTY(BlueprintAssignable)
FOnHealthChangedDynamic OnHealthChanged;
// 广播事件
OnHealthChanged.Broadcast(CurrentHealth);Enhanced Input System
增强输入系统
cpp
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInput)
{
auto* EIC = CastChecked<UEnhancedInputComponent>(PlayerInput);
EIC->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMyCharacter::Move);
EIC->BindAction(JumpAction, ETriggerEvent::Started, this, &AMyCharacter::StartJump);
}cpp
void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInput)
{
auto* EIC = CastChecked<UEnhancedInputComponent>(PlayerInput);
EIC->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMyCharacter::Move);
EIC->BindAction(JumpAction, ETriggerEvent::Started, this, &AMyCharacter::StartJump);
}Key Rules
核心规则
- Always use UPROPERTY for UObject pointers - Prevents garbage collection of referenced objects
- Call Super:: on overridden functions - BeginPlay, Tick, EndPlay all need Super calls
- Use GENERATED_BODY() in all UCLASS/USTRUCT - Required for reflection
- Use soft references for large assets - loads on demand
TSoftObjectPtr<UTexture2D> - Disable Tick when not needed -
PrimaryActorTick.bCanEverTick = false - Use timers over Tick for periodic logic -
GetWorldTimerManager().SetTimer() - Use const references for FString parameters -
void Foo(const FString& Name) - Forward declare in headers, include in cpp - Faster compile times
- Use IsValid() checks - Not just null checks, also checks pending kill
- Profile with Unreal Insights - Built-in profiling for CPU, GPU, memory
- UObject 指针务必使用 UPROPERTY - 防止被垃圾回收机制回收引用对象
- 重写函数时必须调用 Super:: - BeginPlay、Tick、EndPlay 等生命周期函数都需要调用父类实现
- 所有 UCLASS/USTRUCT 必须包含 GENERATED_BODY() - 反射机制的必要条件
- 大型资源使用软引用 - 可按需加载
TSoftObjectPtr<UTexture2D> - 不需要时禁用 Tick - 设置
PrimaryActorTick.bCanEverTick = false - 周期性逻辑使用计时器而非 Tick - 调用
GetWorldTimerManager().SetTimer() - FString 参数使用 const 引用 - 例如
void Foo(const FString& Name) - 头文件中前向声明,cpp 文件中引入头 - 加快编译速度
- 使用 IsValid() 检查 - 不仅检查空指针,还检查是否标记为待销毁
- 使用 Unreal Insights 进行性能分析 - 内置的 CPU、GPU、内存分析工具
Common Anti-Patterns
常见反模式
- in Tick without caching - expensive and repeated
Cast<> - Raw pointers to UObjects without UPROPERTY - GC can collect them
- Tick enabled on actors that don't need per-frame updates
- Loading assets synchronously on the game thread
- Not calling Super in lifecycle overrides
- 在 Tick 中重复调用 而不缓存结果 - 开销大且重复执行
Cast<> - UObject 裸指针不使用 UPROPERTY - 可能被垃圾回收机制回收
- 不需要每帧更新的 Actor 仍启用 Tick
- 在游戏线程中同步加载资源
- 生命周期重写函数中未调用 Super
Multiplayer Patterns
多人游戏模式
cpp
// Server-authoritative function
UFUNCTION(Server, Reliable)
void ServerFireWeapon(FVector Direction);
// Multicast to all clients
UFUNCTION(NetMulticast, Unreliable)
void MulticastPlayFireEffect();
// Client-only
UFUNCTION(Client, Reliable)
void ClientShowDamageNumber(float Amount);
// Replication conditions
void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutProps) const override
{
Super::GetLifetimeReplicatedProps(OutProps);
DOREPLIFETIME_CONDITION(AMyCharacter, Health, COND_OwnerOnly);
}cpp
// 服务器权威函数
UFUNCTION(Server, Reliable)
void ServerFireWeapon(FVector Direction);
// 多播至所有客户端
UFUNCTION(NetMulticast, Unreliable)
void MulticastPlayFireEffect();
// 客户端专属函数
UFUNCTION(Client, Reliable)
void ClientShowDamageNumber(float Amount);
// 同步条件
void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutProps) const override
{
Super::GetLifetimeReplicatedProps(OutProps);
DOREPLIFETIME_CONDITION(AMyCharacter, Health, COND_OwnerOnly);
}