en un clic
unreal-cpp
写 Unreal C++/蓝图时使用。UObject/GC、反射宏、Tick 性能、蓝图边界。
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Menu
写 Unreal C++/蓝图时使用。UObject/GC、反射宏、Tick 性能、蓝图边界。
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Basé sur la classification professionnelle SOC
做 Cocos Creator 多机型/多分辨率适配时使用。Canvas、Widget、安全区。
Cocos Creator 用 AssetBundle 做分包/远程资源时使用。加载、释放、依赖、缓存。
优化 Cocos Creator 渲染性能时使用。合批、图集、动静分离、Label。
给 Cocos Creator 原生包做热更新时使用。version manifest、增量、校验、回滚。
写 Cocos Creator 动效/动画时使用。tween、Animation、Spine、性能与清理。
做 Cocos Creator 大量条目列表时使用。虚拟列表、节点复用。
| name | unreal-cpp |
| description | 写 Unreal C++/蓝图时使用。UObject/GC、反射宏、Tick 性能、蓝图边界。 |
| category | gamedev |
| tags | ["unreal","cpp","蓝图"] |
规则: 所有持有 UObject 派生类(Actor、Component、Asset 等)的成员变量,必须加 UPROPERTY();弱引用用 TWeakObjectPtr;原生裸指针不做持有。
为什么——真实会犯的错:
在 .h 里写了 AEnemy* CachedEnemy; 没加 UPROPERTY(),开发期看起来没问题,进入关卡切换或 GC 整理周期后,引擎把 CachedEnemy 回收了,下一帧 CachedEnemy->TakeDamage(...) 直接崩溃。Crash log 里只有 Access violation,根本看不出是 GC 问题,排查半天。
怎么做:
UPROPERTY()(至少空括号),让 GC 追踪引用计数。TWeakObjectPtr<AEnemy>,使用前先 IsValid()。UPROPERTY(),GC 周期内不会出问题。new UObject() 也不要手动调,用 NewObject<T>() 或 SpawnActor<T>()。规则: UCLASS/UFUNCTION/UPROPERTY 只在真正需要反射、蓝图互操时标注;不把所有东西都往蓝图暴露。
为什么——真实会犯的错:
把所有函数都加 BlueprintCallable、所有变量都加 EditAnywhere,编译时间膨胀,蓝图节点列表被几百个无意义函数污染,策划误用了不该在蓝图调的内部函数,出现生命周期顺序问题。另一个常见错误:忘记在 UFUNCTION() 里标 BlueprintImplementableEvent 却在 C++ 里给了函数体,导致链接错误,新手往往不知道该怎么修。
怎么做:
BlueprintCallable;只给蓝图重写的函数加 BlueprintImplementableEvent 或 BlueprintNativeEvent。BlueprintImplementableEvent 的 C++ 函数不能有函数体;BlueprintNativeEvent 的实现写在 FuncName_Implementation 里。EditAnywhere/BlueprintReadWrite;运行时内部状态加 Transient 或不标。规则: Actor/Component 创建时默认设 PrimaryActorTick.bCanEverTick = false;确实需要逐帧逻辑再开,并评估能否用 Timer 或事件替代。
为什么——真实会犯的错:
场景里生成了 300 个 ABullet,每颗子弹的 Tick 里做了一次 LineTrace,帧率掉到 20 fps,Profiler 里看到几百条 ABullet::TickComponent 占满 CPU。这些子弹大多数时间都在直线飞行,根本不需要每帧 LineTrace——改成 SetActorTickInterval(0.05f) 或抛给 Projectile Movement Component 之后帧率立刻回来了。
怎么做:
PrimaryActorTick.bCanEverTick = false 作为默认值。GetWorldTimerManager().SetTimer(),比 Tick 里减计数更清晰。PrimaryActorTick.TickInterval 降低频率;或在运行时 SetActorTickEnabled(false) 关掉不活跃对象的 Tick。规则: 性能敏感、核心计算逻辑放 C++;数值调参、流程编排、视觉表现留蓝图;不在蓝图里写复杂循环或频繁调用的重计算。
为什么——真实会犯的错:
策划在蓝图里写了一段「扫描半径内所有敌人并按距离排序」的逻辑,用蓝图 ForLoop + GetAllActorsOfClass,每帧执行,场景有 200 个敌人时帧率腰斩。换成 C++ 用空间查询 OverlapMultiByChannel 之后性能恢复正常。另一个方向的错误:程序把所有技能参数写死在 C++ 里,策划调个伤害值要重新编译,浪费大量来回时间。
怎么做:
UPROPERTY(EditDefaultsOnly) 把 C++ 的可调参数暴露给蓝图默认值编辑,而不是写死常量。规则: 严格遵守 Unreal 命名前缀(A/U/F/E/I),头文件只包含真正依赖的头,模块间依赖在 .Build.cs 里显式声明。
为什么——真实会犯的错:
在 FPlayerData 前面忘了加 F,写成 PlayerData,和蓝图变量名冲突,反射系统报警告且行为诡异。另一个常见事故:在 .h 里 #include "Engine.h" 图省事,导致增量编译时几乎所有 .cpp 都重编,编译时间从 30 秒变 5 分钟。还有在 A 模块直接 #include B 模块的私有头而不在 .Build.cs 添加依赖,本地能编过,CI 上缺头文件报错。
怎么做:
A;继承 UObject → U;纯 C++ 结构体 → F;枚举 → E;接口 → I。依赖方.Build.cs 的 PublicDependencyModuleNames 或 PrivateDependencyModuleNames 里添加被依赖模块,不能靠传递依赖碰运气。// ❌ 反例 — 裸指针没有 UPROPERTY,GC 随时可能回收;Tick 默认开着
UCLASS()
class AWeapon : public AActor
{
GENERATED_BODY()
public:
AWeapon();
ACharacter* OwnerCharacter; // ❌ 裸指针,GC 不追踪,随时野指针崩溃
virtual void Tick(float DeltaTime) override; // ❌ 什么都不做却每帧执行
};
AWeapon::AWeapon()
{
// 没有关 Tick,默认开着
}
void AWeapon::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// 空的,白白占 CPU
}
// ✅ 正例 — UPROPERTY 保护引用;默认关 Tick;需要周期逻辑用 Timer
UCLASS()
class AWeapon : public AActor
{
GENERATED_BODY()
public:
AWeapon();
UPROPERTY()
ACharacter* OwnerCharacter; // ✅ GC 追踪,销毁时自动置 null
UPROPERTY(EditDefaultsOnly, Category="Combat")
float FireCooldown = 0.5f; // ✅ 参数暴露给蓝图,策划可调
UFUNCTION(BlueprintCallable, Category="Combat")
void StartFire();
private:
FTimerHandle FireTimerHandle;
void OnFireTick();
};
AWeapon::AWeapon()
{
PrimaryActorTick.bCanEverTick = false; // ✅ 默认关,不浪费 CPU
}
void AWeapon::StartFire()
{
GetWorldTimerManager().SetTimer(
FireTimerHandle, this, &AWeapon::OnFireTick,
FireCooldown, true); // ✅ Timer 替代 Tick,频率可控
}
UPROPERTY(),没有裸指针持有。PrimaryActorTick.bCanEverTick = false,或有明确理由开启 Tick。UPROPERTY(EditDefaultsOnly) 暴露,没有写死常量。BlueprintImplementableEvent 的 C++ 函数无函数体;BlueprintNativeEvent 的实现在 _Implementation 里。#include "Engine.h" 或其他大而全的万能头。.Build.cs 显式声明。