mcpField
U
unreal-engine-cpp-pro

unreal-engine-cpp-pro

github.com/sickn33开发48.7k1.4k 次安装今天更新
代码仓库

关于 unreal-engine-cpp-pro

面向 Unreal Engine 5.x 开发者的 C++ 指导技能,涵盖引擎规范、对象生命周期、性能和常见实现模式,适用于开发与维护项目。

主要功能

  1. 01UObject 生命周期与垃圾回收
  2. 02反射系统与 Blueprint 暴露
  3. 03Tick 与性能指导
  4. 04Epic 命名规范
  5. 05资源加载与软引用

适用场景

  1. 01实现 Actor 和 Component
  2. 02排查垃圾回收问题
  3. 03优化性能关键代码
  4. 04向 Blueprint 暴露 C++ 功能

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill unreal-engine-cpp-pro

安装后在 Claude Code 中输入/unreal-engine-cpp-pro确认已加载。

附带文件examples/ExampleActor.cppexamples/ExampleActor.h

详细介绍

Unreal Engine C++ 专业指南

本技能提供使用 C++ 开发 Unreal Engine 5 项目的专家级指南,重点介绍如何编写健壮、高性能且符合标准的代码。

适用场景

在以下情况下使用本技能:

  • 为 Unreal Engine 5.x 项目开发 C++ 代码
  • 编写 Actor、Component 或 UObject 派生类
  • 优化 Unreal Engine 中对性能要求较高的代码
  • 调试内存泄漏或垃圾回收问题
  • 实现可通过 Blueprint 访问的功能
  • 遵循 Epic Games 的编码标准和约定
  • 使用 Unreal 的反射系统(UCLASS、USTRUCT、UFUNCTION)
  • 管理资源加载和软引用

在以下情况下不要使用本技能:

  • 仅使用 Blueprint 开发项目(不涉及 C++ 代码)
  • 为早于 5.x 的 Unreal Engine 版本开发
  • 使用非 Unreal 游戏引擎开发
  • 任务与 Unreal Engine 开发无关

核心原则

  1. UObject 与垃圾回收:

    • 始终为 UObject* 成员变量使用 UPROPERTY(),确保垃圾回收器(GC)跟踪这些变量。
    • 在反射式 UObject 对象图之外使用作用域内的强引用时,谨慎使用 TStrongObjectPtr<>;不要常规地手动将对象设为根对象。手动调用 AddToRoot() 时,必须认真管理生命周期,并配对调用 RemoveFromRoot()。
    • 理解 IsValid() 检查与 nullptr 的区别。IsValid() 可以安全处理待销毁状态。
  2. Unreal 反射系统:

    • 使用 UCLASS()、USTRUCT()、UENUM()、UFUNCTION() 将类型暴露给反射系统和 Blueprint。
    • 尽可能减少 BlueprintReadWrite 的使用;对于不应被 UI/Level BP 中的逻辑随意修改的状态,优先使用 BlueprintReadOnly。
  3. 性能优先:

    • Tick:默认禁用 Tick(bCanEverTick = false)。只有绝对必要时才启用。优先使用计时器(GetWorldTimerManager())或事件驱动逻辑。
    • 类型转换:避免在热点循环中使用 Cast<T>()。在 BeginPlay 中缓存引用。
    • 结构体与类:对于数据量大且非 UObject 的类型,使用 F 结构体以降低开销。

命名约定(严格遵守)

遵循 Epic Games 的编码标准:

  • 模板:以 T 为前缀(例如 TArray、TMap)。
  • UObject:以 U 为前缀(例如 UCharacterMovementComponent)。
  • AActor:以 A 为前缀(例如 AMyGameMode)。
  • SWidget:以 S 为前缀(Slate 控件)。
  • 结构体:以 F 为前缀(例如 FVector)。
  • 枚举:以 E 为前缀(例如 EWeaponState)。
  • 接口:以 I 为前缀(例如 IInteractable)。
  • 布尔值:以 b 为前缀(例如 bIsDead)。

常见模式

1. 稳健的组件查找

避免在 Tick 中使用 GetComponentByClass。应在 PostInitializeComponents 或 BeginPlay 中执行查找。

void AMyCharacter::PostInitializeComponents() {
    Super::PostInitializeComponents();
    HealthComp = FindComponentByClass<UHealthComponent>();
    check(HealthComp); // Fail hard in dev if missing
}
2. 接口实现

使用接口解耦系统(例如交互系统)。

// Interface call check
if (IsValid(TargetActor) && TargetActor->Implements<UInteractable>()) {
    IInteractable::Execute_OnInteract(TargetActor, this);
}
3. 软引用(同步示例)

对于会强制产生加载顺序的大型资源,避免使用硬引用(UPROPERTY(EditDefaultsOnly) TSubclassOf<AActor>)。应使用 TSoftClassPtr 或 TSoftObjectPtr。

UPROPERTY(EditAnywhere, BlueprintReadWrite)
TSoftClassPtr<AWeapon> WeaponClassToLoad;

void AMyCharacter::Equip() {
    if (WeaponClassToLoad.IsPending()) {
        WeaponClassToLoad.LoadSynchronous(); // Or use StreamableManager for async
    }
}

调试

  • 日志:使用带有自定义类别的 UE_LOG。
    DEFINE_LOG_CATEGORY_STATIC(LogMyGame, Log, All);
    UE_LOG(LogMyGame, Warning, TEXT("Health is low: %f"), CurrentHealth);
    
  • 屏幕消息:
    if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("Died!"));
    
  • 可视化日志:对 AI 调试极为有用。实现 IVisualLoggerDebugSnapshotInterface。

PR 前检查清单

  • 这个 Actor 需要 Tick 吗?可以改用 Timer 吗?
  • 所有 UObject* 成员是否都使用 UPROPERTY 包装?
  • 硬引用(TSubclassOf)是否会导致加载链?可以改用软指针吗?
  • 是否已在 EndPlay 中清理已验证的委托?

限制

  • 仅当任务明确符合上述范围时,才使用此技能。
  • 不要将输出视为针对特定环境进行验证、测试或专家审查的替代方案。
  • 如果缺少必需的输入、权限、安全边界或成功标准,请停止并要求澄清。

这些 Actor 文件仅供示例参考,需要替换 MYGAME_API、生成项目头文件,并在目标引擎中构建。LoadSynchronous() 可能会阻塞游戏线程;对于对延迟敏感的路径,请使用目标版本的流式异步加载 API。在支持的情况下,优先使用经过反射的 TObjectPtr 成员。Epic 对象指针指南。

评论

支持 Markdown