Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when writing Unreal Engine 5 C++ - the gameplay framework classes and where logic belongs, UObject/AActor/UActorComponent lifecycle, UPROPERTY/UFUNCTION and GC-safe pointers (TObjectPtr, TWeakObjectPtr), subsystems, the C++/Blueprint boundary, Enhanced Input, tick discipline, and compiling from the command line.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
설치 방법 보기설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.
Unreal gives you a full gameplay framework, a reflection system and a garbage collector. Most bugs in Unreal C++ come from fighting them: raw UObject* members the GC frees underneath you, gameplay logic in constructors that only ever run on the class default object, logic on the wrong framework class (GameMode code running on clients), and everything ticking every frame.
Core principle: Put each piece of logic on the framework class that owns it, keep every UObject reference visible to the GC, and let C++ own systems while Blueprints own content and tuning.
| Class | Lives on | Owns |
|---|---|---|
AGameModeBase | Server only | Rules of the match: spawning, scoring rules, win conditions |
AGameStateBase | Server + replicated to all | Match state everyone sees (time left, team scores) |
APlayerController | Owning client + server | Input routing, UI ownership, camera for that player |
APlayerState | Replicated to all | Per-player persistent data (name, score); survives pawn death |
APawn / ACharacter | Replicated | The body: movement, the components that act in the world |
UActorComponent | With its actor | Reusable behaviour (health, inventory, interaction) |
UGameInstanceSubsystem / UWorldSubsystem / ULocalPlayerSubsystem | Process / world / local player | Services (save, matchmaking, spawning registries) — instead of singletons |
A client asking GetWorld()->GetAuthGameMode() gets nullptr — that is the design, not a bug to work around.
AHeroCharacter::AHeroCharacter() {
// Constructor: defaults and subobjects only. It runs for the class default object too,
// so no world access, no spawning, no gameplay.
PrimaryActorTick.bCanEverTick = false;
Health = CreateDefaultSubobject<UHealthComponent>(TEXT("Health"));
}
void AHeroCharacter::BeginPlay() {
Super::BeginPlay(); // always call Super
Health->OnDied.AddDynamic(this, &AHeroCharacter::HandleDied);
}
void AHeroCharacter::EndPlay(const EEndPlayReason::Type Reason) {
GetWorldTimerManager().ClearAllTimersForObject(this);
Super::EndPlay(Reason);
}
Order to remember: constructor → PostInitializeComponents → BeginPlay → Tick → EndPlay. Components: InitializeComponent (if bWantsInitializeComponent) → BeginPlay.
UCLASS()
class UInventoryComponent : public UActorComponent {
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Inventory")
bool TryAdd(const UItemDefinition* Item, int32 Count);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnInventoryChanged, const UInventoryComponent*, Inventory);
UPROPERTY(BlueprintAssignable) FOnInventoryChanged OnChanged;
private:
// ❌ UItemDefinition* Cached; invisible to the GC: freed under you, then a crash
// ✅ visible to the GC, editor-tunable, null-safe
UPROPERTY(EditDefaultsOnly, Category = "Inventory", meta = (ClampMin = "1"))
int32 SlotCount = 20;
UPROPERTY(Transient) TArray<FInventorySlot> Slots;
UPROPERTY() TObjectPtr<const UItemDefinition> LastAdded;
TWeakObjectPtr<AActor> LastInteractor; // non-owning: check IsValid() before use
};
UObject* member is a UPROPERTY (TObjectPtr<T> for members in UE5), a TWeakObjectPtr, or a TStrongObjectPtr (from non-UObject code). Raw pointers only as locals and parameters.NewObject<T>(Outer), CreateDefaultSubobject (constructor only) or GetWorld()->SpawnActor — never new.IsValid(Ptr) before using anything that may have been destroyed (IsValid also catches "pending kill").EditDefaultsOnly for tuning on the Blueprint class, EditAnywhere only when level instances should differ, VisibleAnywhere for components.BlueprintCallable for actions, BlueprintPure for queries, BlueprintImplementableEvent / BlueprintNativeEvent for designer hooks. No gameplay rule that exists only in a Blueprint graph nobody can test.TSoftObjectPtr) so loading one class does not pull the whole content graph (game-asset-pipeline).void AHeroController::BeginPlay() {
Super::BeginPlay();
if (auto* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer())) {
Subsystem->AddMappingContext(DefaultContext, /*Priority*/ 0);
}
}
void AHeroCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) {
auto* Input = CastChecked<UEnhancedInputComponent>(PlayerInputComponent);
Input->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AHeroCharacter::Move);
Input->BindAction(JumpAction, ETriggerEvent::Started, this, &ACharacter::Jump);
}
void AHeroCharacter::Move(const FInputActionValue& Value) {
const FVector2D Axis = Value.Get<FVector2D>();
AddMovementInput(GetActorForwardVector(), Axis.Y);
AddMovementInput(GetActorRightVector(), Axis.X);
}
Input actions and mapping contexts are assets (data); the legacy BindAxis/BindAction string API is not used in new code.
PrimaryActorTick.bCanEverTick = false by default; enable only where per-frame work is needed, with SetActorTickInterval where 60 Hz is not needed.GetWorldTimerManager().SetTimer) and events instead of polling in Tick.TActorIterator, GetAllActorsOfClass or FindComponentByClass per frame — cache, or register with a subsystem.# macOS (Win64: Engine/Build/BatchFiles/Build.bat ... Win64; Linux: Engine/Build/BatchFiles/Linux/Build.sh ... Linux)
"<UE>/Engine/Build/BatchFiles/Mac/Build.sh" <Project>Editor Mac Development \
-Project="$PWD/<Project>.uproject" -WaitMutex > /tmp/tt-<task key>/build.log 2>&1; echo "exit=$?"
-unattended, an out-of-date module fails instead of prompting.<Module>.Build.cs (PublicDependencyModuleNames / PrivateDependencyModuleNames), e.g. EnhancedInput, GameplayAbilities.Binaries/, Intermediate/, Saved/, DerivedDataCache/; .uasset/.umap go through LFS (asset-hygiene).DEFINE_LOG_CATEGORY_STATIC(LogInventory, Log, All); UE_LOG(LogInventory, Warning, TEXT("..."));. check() for programmer errors that must crash in development; ensure() for recoverable ones.UObject* members without UPROPERTY.Super:: calls in overridden lifecycle functions.new UMyObject or new AMyActor anywhere.GetAllActorsOfClass inside Tick.Binaries/ or Intermediate/ in the diff.아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.
로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.
아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.
Use when writing acceptance criteria for a task - express each as an observable Given/When/Then that QA can execute, including negative cases
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when the diff adds or changes an endpoint, resolver, RPC, job or query that takes an object id, a role check, a request binding or a tenant filter - BOLA/IDOR, function-level authorization, mass assignment and tenant scoping
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use on every UI change - semantic HTML, labels for controls, keyboard-navigable dialogs/menus, visible focus, and never color as the only signal
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when a task changes any screen, form, dialog, menu or control - Lighthouse/axe scan of the changed screens, a keyboard walk, and the thresholds that fail a task
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
How to work a task returned with review, QA or UAT findings. Use when a task is in need_revision or PR review comments are in your context.
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.
Use when the repository keeps its alerting in code, or a person asks for alerts outside TaskTrooper - PrometheusRule YAML, a Cloud Monitoring alert policy in Terraform, a Datadog monitor, each routed to TaskTrooper's alert ingest URL so it opens an incident here
한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.