unreal

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Unreal Engine Development Skill

Unreal Engine 开发技能

Engine Detection

引擎识别

Look for:
.uproject
,
.Build.cs
,
.uplugin
,
Source/
,
Content/
,
Config/DefaultEngine.ini
,
Binaries/
查找以下文件/目录:
.uproject
.Build.cs
.uplugin
Source/
Content/
Config/DefaultEngine.ini
Binaries/

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.uproject
MyGame/
  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.uproject

Actor/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

核心规则

  1. Always use UPROPERTY for UObject pointers - Prevents garbage collection of referenced objects
  2. Call Super:: on overridden functions - BeginPlay, Tick, EndPlay all need Super calls
  3. Use GENERATED_BODY() in all UCLASS/USTRUCT - Required for reflection
  4. Use soft references for large assets -
    TSoftObjectPtr<UTexture2D>
    loads on demand
  5. Disable Tick when not needed -
    PrimaryActorTick.bCanEverTick = false
  6. Use timers over Tick for periodic logic -
    GetWorldTimerManager().SetTimer()
  7. Use const references for FString parameters -
    void Foo(const FString& Name)
  8. Forward declare in headers, include in cpp - Faster compile times
  9. Use IsValid() checks - Not just null checks, also checks pending kill
  10. Profile with Unreal Insights - Built-in profiling for CPU, GPU, memory
  1. UObject 指针务必使用 UPROPERTY - 防止被垃圾回收机制回收引用对象
  2. 重写函数时必须调用 Super:: - BeginPlay、Tick、EndPlay 等生命周期函数都需要调用父类实现
  3. 所有 UCLASS/USTRUCT 必须包含 GENERATED_BODY() - 反射机制的必要条件
  4. 大型资源使用软引用 -
    TSoftObjectPtr<UTexture2D>
    可按需加载
  5. 不需要时禁用 Tick - 设置
    PrimaryActorTick.bCanEverTick = false
  6. 周期性逻辑使用计时器而非 Tick - 调用
    GetWorldTimerManager().SetTimer()
  7. FString 参数使用 const 引用 - 例如
    void Foo(const FString& Name)
  8. 头文件中前向声明,cpp 文件中引入头 - 加快编译速度
  9. 使用 IsValid() 检查 - 不仅检查空指针,还检查是否标记为待销毁
  10. 使用 Unreal Insights 进行性能分析 - 内置的 CPU、GPU、内存分析工具

Common Anti-Patterns

常见反模式

  • Cast<>
    in Tick without caching - expensive and repeated
  • 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);
}