From 1053bdec732c87ed030f6d76b376c71c96940b0a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 8 Jan 2026 15:19:06 +0000
Subject: [PATCH] Address PR feedback: improve part-1, add Expected Results,
split parts 4-9 into separate files
Co-authored-by: kuhyx <147418882+kuhyx@users.noreply.github.com>
---
.../unreal/tutorial/QUICKSTART-CODE-FIRST.md | 2 +-
games/unreal/tutorial/README.md | 16 +-
.../tutorial/part-1-cpp-project-setup.md | 94 ++-
.../tutorial/part-2-cpp-create-player.md | 44 +-
games/unreal/tutorial/part-4-9-cpp-summary.md | 210 -------
.../tutorial/part-4-cpp-create-enemy.md | 548 ++++++++++++++++++
.../tutorial/part-5-cpp-create-spawner.md | 247 ++++++++
.../part-6-cpp-create-game-director.md | 167 ++++++
games/unreal/tutorial/part-7-cpp-create-ui.md | 209 +++++++
.../tutorial/part-8-cpp-create-game-mode.md | 96 +++
.../unreal/tutorial/part-9-cpp-final-setup.md | 160 +++++
11 files changed, 1547 insertions(+), 246 deletions(-)
delete mode 100644 games/unreal/tutorial/part-4-9-cpp-summary.md
create mode 100644 games/unreal/tutorial/part-4-cpp-create-enemy.md
create mode 100644 games/unreal/tutorial/part-5-cpp-create-spawner.md
create mode 100644 games/unreal/tutorial/part-6-cpp-create-game-director.md
create mode 100644 games/unreal/tutorial/part-7-cpp-create-ui.md
create mode 100644 games/unreal/tutorial/part-8-cpp-create-game-mode.md
create mode 100644 games/unreal/tutorial/part-9-cpp-final-setup.md
diff --git a/games/unreal/tutorial/QUICKSTART-CODE-FIRST.md b/games/unreal/tutorial/QUICKSTART-CODE-FIRST.md
index 7984387..a14dc5f 100644
--- a/games/unreal/tutorial/QUICKSTART-CODE-FIRST.md
+++ b/games/unreal/tutorial/QUICKSTART-CODE-FIRST.md
@@ -10,7 +10,7 @@
- **New Project?** → Start with [Part 1 (C++): Project Setup](part-1-cpp-project-setup.md)
- **Already have Blueprint project?** → See [Migration Guide](#migrating-from-blueprint-to-c) below
-- **Just need code?** → See existing implementations in `Source/MCPGameProject/`
+- **Just need reference code?** → See existing implementations in `Source/MCPGameProject/`
### 2. Create C++ Project (New Projects Only)
diff --git a/games/unreal/tutorial/README.md b/games/unreal/tutorial/README.md
index 86dae02..beb316b 100644
--- a/games/unreal/tutorial/README.md
+++ b/games/unreal/tutorial/README.md
@@ -144,10 +144,18 @@ This tutorial offers **two ways** to implement the game:
### For Code-First Approach (Recommended)
1. Read [3-Minute Quickstart](QUICKSTART-CODE-FIRST.md)
-2. Start with [Part 1 (C++): Project Setup](part-1-cpp-project-setup.md)
-3. Follow parts 2-3, then [Parts 4-9 Summary](part-4-9-cpp-summary.md)
-4. **Complete the game in 2-3 hours** instead of 6-8 hours!
-5. **Already have Blueprint project?** See [Migration Guide](QUICKSTART-CODE-FIRST.md#migrating-from-blueprint-to-c)
+2. Follow the C++ tutorial parts:
+ - [Part 1 (C++): Project Setup](part-1-cpp-project-setup.md)
+ - [Part 2 (C++): Create Player](part-2-cpp-create-player.md)
+ - [Part 3 (C++): Create Bullet](part-3-cpp-create-bullet.md)
+ - [Part 4 (C++): Create Enemy](part-4-cpp-create-enemy.md)
+ - [Part 5 (C++): Create Spawner](part-5-cpp-create-spawner.md)
+ - [Part 6 (C++): Create Game Director](part-6-cpp-create-game-director.md)
+ - [Part 7 (C++): Create UI](part-7-cpp-create-ui.md)
+ - [Part 8 (C++): Create Game Mode](part-8-cpp-create-game-mode.md)
+ - [Part 9 (C++): Final Setup](part-9-cpp-final-setup.md)
+3. **Complete the game in 2-3 hours** instead of 6-8 hours!
+4. **Already have Blueprint project?** See [Migration Guide](QUICKSTART-CODE-FIRST.md#migrating-from-blueprint-to-c)
### For Blueprint Approach
diff --git a/games/unreal/tutorial/part-1-cpp-project-setup.md b/games/unreal/tutorial/part-1-cpp-project-setup.md
index 8f2ab47..38ed727 100644
--- a/games/unreal/tutorial/part-1-cpp-project-setup.md
+++ b/games/unreal/tutorial/part-1-cpp-project-setup.md
@@ -28,8 +28,8 @@ This is the **C++ version** of Part 1. Unlike the Blueprint tutorial which creat
6. On the right side panel, configure:
- **Project Defaults:** **C++** ⚠️ (NOT Blueprint!)
- **Target Platform:** Desktop
- - **Quality Preset:** Maximum (or Scalable for faster iteration)
- - **Starter Content:** UNCHECKED (we don't need it)
+ - **Quality Preset:** Scalable (faster compile times, easier iteration)
+ - **Starter Content:** UNCHECKED (reduces project size and avoids unnecessary assets for this bullet-hell game)
- **Raytracing:** UNCHECKED
7. At the bottom:
@@ -42,41 +42,62 @@ This is the **C++ version** of Part 1. Unlike the Blueprint tutorial which creat
Unreal will:
1. Generate C++ project files (~30 seconds)
-2. **Open your IDE** (Visual Studio, Rider, or VS Code)
-3. **Compile the initial project** (2-5 minutes, first time only)
-4. Open Unreal Editor
+2. **Open your IDE** (Visual Studio Code will launch if configured)
+3. **Automatically start compiling** the initial project (2-5 minutes, first time only)
+ - You'll see a terminal/console window showing compilation progress
+ - On Linux: Uses clang++ or g++ to compile C++ files
+ - Progress shown as: "Compiling C++ source files...", "Linking...", etc.
+4. Open Unreal Editor once compilation completes
-> **⚠️ IMPORTANT:** Do NOT close the IDE or compilation window! Wait for compilation to finish.
+> **⚠️ IMPORTANT:** Do NOT close the IDE or compilation window! Wait for compilation to finish. You'll see "Build succeeded" or similar message when done.
### Expected Result
After compilation completes:
-- **Unreal Editor opens** with an empty level
-- **Your IDE is open** with the project (Visual Studio/Rider/VS Code)
-- Main 3D viewport in the center
-- Outliner panel on the right (showing "Untitled" level)
+**Unreal Editor viewport shows:**
+- Empty 3D viewport in the center with grid floor
+- Main toolbar at the top (File, Edit, Window, etc.)
+- Outliner panel on the right showing "Untitled" level actors
+- Details panel on the right side (currently empty)
+- Content Drawer button at bottom (click it or press `Ctrl+Space` to open)
+
+**VS Code (your IDE) shows:**
+- BulletHellGame project folder open
+- Left sidebar with file explorer showing `Source/` folder
+- `STGPawn.h` and `STGPawn.cpp` or similar auto-generated files
+
+**What you should see in Unreal Editor:**
+- A flat grid representing the game world (top-down view by default in new projects)
+- No errors in the Output Log
+- The word "Ready" or compilation success message in bottom-right corner
+
+> **NOTE:** If you see a 3D perspective view instead of top-down, don't worry - we'll fix that in Step 1.3.
### Troubleshooting
-IDE didn't open?
+IDE didn't open? (Visual Studio Code on Linux/Arch)
-- Check if Visual Studio or Rider is installed
-- Go to `Edit → Editor Preferences → Source Code`
-- Set "Source Code Editor" to your preferred IDE
-- Right-click the `.uproject` file → "Generate Visual Studio project files"
-- Open the `.sln` file in your IDE
+On Arch Linux with VS Code:
+- Install VS Code if not present: `sudo pacman -S code`
+- Install Unreal Engine extension for VS Code
+- In Unreal Editor: `Edit → Editor Preferences → Source Code`
+- Set "Source Code Editor" to "Visual Studio Code"
+- Right-click the `.uproject` file in file manager → "Generate VSCode project files"
+- Open the project folder in VS Code
-Compilation failed?
+Compilation failed? (Linux/Arch)
-- Check the Output Log (Window → Developer Tools → Output Log)
-- Common issue: Missing Visual Studio C++ tools
- - Install "Desktop Development with C++" workload in Visual Studio Installer
-- Try: `File → Refresh Visual Studio Project`
+On Arch Linux:
+- Ensure you have the required build tools:
+ - `sudo pacman -S base-devel clang lld`
+- Check the Output Log (Window → Developer Tools → Output Log) for specific errors
+- If missing libraries, install them via pacman
+- Try regenerating project files: Right-click `.uproject` → "Generate VSCode project files"
@@ -107,6 +128,25 @@ BulletHellGame/
The `Source/` folder is what makes this a C++ project! This is where we'll add our game classes.
+### Expected Result
+
+**In File Explorer (your Linux file manager):**
+```
+BulletHellGame/
+├── BulletHellGame.uproject # Double-click to open project
+├── Source/ # ✅ C++ source code folder
+│ └── BulletHellGame/
+│ ├── BulletHellGame.h
+│ ├── BulletHellGame.cpp
+│ └── BulletHellGame.Build.cs
+├── Content/ # Assets and Blueprints
+├── Config/ # Project configuration
+├── Binaries/ # Compiled game (gitignore this)
+└── Intermediate/ # Build files (gitignore this)
+```
+
+**Verify the Source folder exists** - this confirms C++ is enabled!
+
---
## Step 1.3: Set Up 2D Game View
@@ -117,6 +157,18 @@ Same as Blueprint tutorial:
2. Click the dropdown that says "Perspective"
3. Select "Top" from the dropdown menu (`Alt + J`)
+### Expected Result
+
+**Viewport changes:**
+- Camera now looks straight down at the grid
+- You see the game world from a bird's-eye view (perfect for bullet-hell)
+- Grid appears as horizontal lines (X and Y axes visible)
+- Objects will appear flat when placed in this view
+
+**Visual confirmation:**
+- Top-left corner now shows "Top" instead of "Perspective"
+- The viewport manipulation gizmo (3D arrows) now shows only X and Y axes prominently
+
---
## Step 1.4: Create Folder Structure
diff --git a/games/unreal/tutorial/part-2-cpp-create-player.md b/games/unreal/tutorial/part-2-cpp-create-player.md
index f697f98..64061b9 100644
--- a/games/unreal/tutorial/part-2-cpp-create-player.md
+++ b/games/unreal/tutorial/part-2-cpp-create-player.md
@@ -435,18 +435,42 @@ Now we create a **minimal Blueprint** that inherits from our C++ class. This Blu
## Step 2.7: Test the Player
-1. Drag `BP_Player` from Content Browser into the level
-2. Press **Play** (`Alt+P`)
-3. Press WASD keys - player should move!
-4. Press Z or Space - you should see "FIRE!" in Output Log
-5. Press X - you should see "SPECIAL ABILITY ACTIVATED!" once
+1. Drag `BP_Player` from Content Browser into the level viewport
+2. Position it near the center (coordinates around X=0, Y=0, Z=0)
+3. Press **Play** (`Alt+P`)
-### Expected Result:
+### Expected Result
-- ✅ Player moves with WASD
-- ✅ Movement is clamped to bounds
-- ✅ Fire input detected (logs message)
-- ✅ Special ability works once
+**In Play Mode Window:**
+- You see the cone/cube player ship from above (top-down view)
+- Ship is positioned at center of screen
+- Background is the default gray/blue Unreal grid
+- Camera follows the player from above
+
+**When pressing WASD keys:**
+- **W** - Ship moves upward on screen (toward top)
+- **S** - Ship moves downward on screen (toward bottom)
+- **A** - Ship moves left
+- **D** - Ship moves right
+- Movement stops immediately when you release keys (no sliding)
+- Ship stops at screen edges (cannot move outside bounds)
+
+**When pressing Z or Space:**
+- You see "FIRE!" message appear in top-left corner of screen (yellow text)
+- Message appears repeatedly while holding the button
+- No bullets yet (we'll add those after creating bullet class)
+
+**When pressing X:**
+- "SPECIAL ABILITY ACTIVATED!" appears once in top-left corner
+- Pressing X again does nothing (ability used up)
+
+**Visual Check:**
+- Ship model is visible (cone or cube shape)
+- Ship rotates/faces the direction of movement
+- No errors in Output Log
+- Frame rate counter shows stable FPS (if enabled)
+
+**To exit Play mode:** Press `Esc` or click the "Stop" button in the toolbar
---
diff --git a/games/unreal/tutorial/part-4-9-cpp-summary.md b/games/unreal/tutorial/part-4-9-cpp-summary.md
deleted file mode 100644
index 821a07b..0000000
--- a/games/unreal/tutorial/part-4-9-cpp-summary.md
+++ /dev/null
@@ -1,210 +0,0 @@
-# Parts 4-9 (C++): Complete Game Implementation
-
-[← Previous: Part 3 (C++) - Create the Bullet](part-3-cpp-create-bullet.md) | [Back to Index](README.md)
-
----
-
-## Overview
-
-Parts 4-9 follow the same pattern: create C++ classes, copy-paste code, create minimal Blueprint children for visuals.
-
-Due to length constraints, this document summarizes Parts 4-9. Full implementations are in the existing `Source/MCPGameProject/` folder.
-
----
-
-## Part 4: Create the Enemy (C++)
-
-### Quick Summary:
-
-1. **Tools → New C++ Class** → Actor → Name: `STGEnemy`
-2. Copy variables block (15 enemy stats with defaults)
-3. Implement movement (sinusoidal wave pattern)
-4. Implement firing (radial bullet burst)
-5. Compile
-6. Create `BP_Enemy` Blueprint child
-
-### Key Code (STGEnemy.h excerpt):
-
-```cpp
-// 15 variables in one copy-paste!
-UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
-int32 MaxHealth = 12;
-
-UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
-float VerticalSpeed = 220.0f;
-
-UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
-float HorizontalAmplitude = 250.0f;
-
-UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
-float FireInterval = 0.35f;
-
-UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
-int32 BulletsPerBurst = 20;
-// ... etc
-```
-
-**Time saved:** Blueprint (90 min) vs C++ (25 min) = **65 min** ⚡
-
-Full implementation: See `Source/MCPGameProject/STGEnemy.h/cpp`
-
----
-
-## Part 5: Create Enemy Spawner (C++)
-
-### Quick Summary:
-
-1. **Tools → New C++ Class** → Actor → Name: `STGEnemySpawner`
-2. Copy spawner variables (spawn rate, area, max enemies)
-3. Implement difficulty curve (spawn rate increases over time)
-4. Compile
-5. Place spawner in level
-
-### Key Code:
-
-```cpp
-UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawning")
-float SpawnAreaHalfWidth = 900.0f;
-
-UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawning")
-float BaseSpawnRate = 2.0f;
-
-UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawning")
-int32 MaxSimultaneousEnemies = 120;
-```
-
-**Time: ~8 minutes**
-
----
-
-## Part 6: Create Game Director (C++)
-
-### Quick Summary:
-
-1. **Tools → New C++ Class** → Actor → Name: `STGGameDirector`
-2. Manage game timer (300 seconds)
-3. Handle victory/defeat conditions
-4. Compile
-5. Place in level
-
-### Key Code:
-
-```cpp
-UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Game")
-float GameDuration = 300.0f;
-
-UPROPERTY(BlueprintReadOnly, Category = "Game")
-float ElapsedTime = 0.0f;
-
-UPROPERTY(BlueprintReadOnly, Category = "Game")
-bool bGameActive = true;
-```
-
-**Time: ~10 minutes**
-
----
-
-## Part 7: Create UI (C++)
-
-### Quick Summary:
-
-For UI, we still use **Widget Blueprints** (visual layout) but bind to C++ for data.
-
-1. Create Widget Blueprint `WBP_HUD` in UI folder
-2. Add Text blocks for Score, Lives, Timer
-3. Bind to C++ properties via Blueprint events
-4. Create in Player's BeginPlay
-
-**Time: ~15 minutes**
-
----
-
-## Part 8: Create Game Mode (C++)
-
-### Quick Summary:
-
-1. **Tools → New C++ Class** → Game Mode Base → Name: `STGGameMode`
-2. Set default pawn class to STGPawn
-3. Handle player death/respawn
-4. Compile
-5. Set in Project Settings → Maps & Modes
-
-### Key Code:
-
-```cpp
-ASTGGameMode::ASTGGameMode()
-{
- // Set default pawn
- DefaultPawnClass = ASTGPawn::StaticClass();
-}
-```
-
-**Time: ~5 minutes**
-
----
-
-## Part 9: Final Setup (C++)
-
-### Quick Summary:
-
-1. Assign visual meshes to Blueprint children (BP_Player, BP_Enemy, BP_Bullet)
-2. Set materials and colors
-3. Create background plane
-4. Test complete game
-5. Build for standalone
-
-**Time: ~15 minutes**
-
----
-
-## Total Time Comparison
-
-| Part | Blueprint Time | C++ Time | Saved |
-|------|---------------|----------|-------|
-| 1. Project Setup | 5 min | 10 min | -5 min (one-time) |
-| 2. Player | 60 min | 15 min | 45 min ⚡ |
-| 3. Bullet | 30 min | 10 min | 20 min ⚡ |
-| 4. Enemy | 90 min | 25 min | 65 min ⚡ |
-| 5. Spawner | 40 min | 8 min | 32 min ⚡ |
-| 6. Game Director | 45 min | 10 min | 35 min ⚡ |
-| 7. UI | 30 min | 15 min | 15 min ⚡ |
-| 8. Game Mode | 20 min | 5 min | 15 min ⚡ |
-| 9. Final Setup | 40 min | 15 min | 25 min ⚡ |
-| **TOTAL** | **~6-8 hours** | **~2-3 hours** | **~4-5 hours** ⚡⚡⚡ |
-
----
-
-## Full Reference Implementations
-
-All complete C++ files are available in:
-
-```
-Source/MCPGameProject/
-├── STGPawn.h/cpp (Player)
-├── STGProjectile.h/cpp (Bullets)
-├── STGEnemy.h/cpp (Enemies)
-├── STGGameMode.h/cpp (Game rules)
-├── STGHUD.h/cpp (UI binding)
-└── STGEffects.h/cpp (Visual effects)
-```
-
-You can:
-1. Copy these files directly to your project
-2. Modify as needed
-3. Compile and use
-
----
-
-## Key Takeaway
-
-**The C++ approach saves 60% development time** by:
-
-✅ Copy-pasting variable blocks (seconds vs minutes)
-✅ Using IDE tools (autocomplete, refactoring)
-✅ Version control friendly (readable diffs)
-✅ Type-safe (compiler catches errors)
-✅ Easier to maintain (code is documentation)
-
----
-
-[← Previous: Part 3 (C++) - Create the Bullet](part-3-cpp-create-bullet.md) | [Back to Index](README.md)
diff --git a/games/unreal/tutorial/part-4-cpp-create-enemy.md b/games/unreal/tutorial/part-4-cpp-create-enemy.md
new file mode 100644
index 0000000..a120e82
--- /dev/null
+++ b/games/unreal/tutorial/part-4-cpp-create-enemy.md
@@ -0,0 +1,548 @@
+# Part 4 (C++): Create the Enemy
+
+[← Previous: Part 3 (C++) - Create the Bullet](part-3-cpp-create-bullet.md) | [Back to Index](README.md) | [Next: Part 5 (C++) - Create Enemy Spawner →](part-5-cpp-create-spawner.md)
+
+---
+
+## Overview
+
+Create enemy ships in C++. Again, we'll copy-paste all 15 enemy variables instead of clicking UI 75+ times.
+
+**Time comparison:**
+- Blueprint approach (Part 4): ~90 minutes (16 variables + complex Blueprint nodes)
+- C++ approach (this part): ~25 minutes (copy-paste code)
+
+---
+
+## Step 4.1: Create STGEnemy C++ Class
+
+### In Unreal Editor:
+
+1. Go to **Tools → New C++ Class** (top menu bar)
+2. In the "Choose Parent Class" window:
+ - Click **"Actor"** (enemies are independent game objects)
+ - Click **"Next"**
+
+3. In the "Name Your New Actor" window:
+ - **Name:** `STGEnemy`
+ - **Path:** Should be `Source/BulletHellGame/` (default)
+ - Click **"Create Class"**
+
+### What Happens Next:
+
+1. Unreal generates `STGEnemy.h` and `STGEnemy.cpp`
+2. VS Code opens with the new files
+3. Project compiles automatically (~30-60 seconds)
+4. Unreal Editor refreshes
+
+---
+
+## Step 4.2: Define Enemy Variables in STGEnemy.h
+
+**This is where the magic happens!** Instead of clicking UI 75+ times (16 variables × ~5 clicks each), we'll **copy-paste** all variables at once.
+
+### Open STGEnemy.h in VS Code
+
+Replace the entire file content with:
+
+```cpp
+#pragma once
+
+#include "CoreMinimal.h"
+#include "GameFramework/Actor.h"
+#include "STGEnemy.generated.h"
+
+class UStaticMeshComponent;
+class UBoxComponent;
+
+UCLASS()
+class BULLETHELLGAME_API ASTGEnemy : public AActor
+{
+ GENERATED_BODY()
+
+public:
+ ASTGEnemy();
+
+protected:
+ virtual void BeginPlay() override;
+
+public:
+ virtual void Tick(float DeltaTime) override;
+
+ // ===== COMPONENTS =====
+ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
+ UStaticMeshComponent* MeshComp;
+
+ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components")
+ UBoxComponent* CollisionComp;
+
+ // ===== HEALTH & SCORE (copy-paste all 15 variables!) =====
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
+ int32 MaxHealth = 12;
+
+ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Stats")
+ int32 CurrentHealth = 12;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
+ int32 ScoreValue = 50;
+
+ // ===== MOVEMENT =====
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
+ float VerticalSpeed = 220.0f;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
+ float HorizontalAmplitude = 250.0f;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
+ float HorizontalFrequency = 1.8f;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
+ float DespawnY = -750.0f;
+
+ // ===== FIRING =====
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
+ float FireInterval = 0.35f;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
+ int32 BulletsPerBurst = 20;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
+ float BurstSpread = 360.0f;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
+ float EnemyBulletSpeed = 1000.0f;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Stats")
+ float EnemyBulletLifetime = 6.0f;
+
+ // ===== FUNCTIONS =====
+ void Fire();
+ void HandleDamage(float DamageAmount);
+
+ UFUNCTION()
+ void OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor,
+ UPrimitiveComponent* OtherComp, int32 OtherBodyIndex,
+ bool bFromSweep, const FHitResult& SweepResult);
+
+private:
+ FTimerHandle TimerHandle_Fire;
+ float BaseX = 0.0f;
+ float WaveSeed = 0.0f;
+ float ElapsedTime = 0.0f;
+};
+```
+
+### What Just Happened?
+
+You just defined **15 gameplay variables + 2 components** with default values in ~30 seconds!
+
+In the Blueprint tutorial, this would require:
+- 16 variables × 5 clicks each = **80 clicks**
+- **~20 minutes** of manual work
+- High chance of typos or wrong types
+
+**Time saved: 19.5 minutes** ⚡
+
+---
+
+## Step 4.3: Implement STGEnemy Logic
+
+### Open STGEnemy.cpp in VS Code
+
+Replace the file content with:
+
+```cpp
+#include "STGEnemy.h"
+#include "Components/StaticMeshComponent.h"
+#include "Components/BoxComponent.h"
+#include "Kismet/GameplayStatics.h"
+#include "STGProjectile.h"
+#include "STGPawn.h"
+
+ASTGEnemy::ASTGEnemy()
+{
+ PrimaryActorTick.bCanEverTick = true;
+
+ // Root component
+ RootComponent = CreateDefaultSubobject(TEXT("Root"));
+
+ // Mesh component
+ MeshComp = CreateDefaultSubobject(TEXT("MeshComp"));
+ MeshComp->SetupAttachment(RootComponent);
+ MeshComp->SetCollisionProfileName("NoCollision");
+
+ // Load cube mesh
+ static ConstructorHelpers::FObjectFinder CubeMesh(TEXT("/Engine/BasicShapes/Cube"));
+ if (CubeMesh.Succeeded())
+ {
+ MeshComp->SetStaticMesh(CubeMesh.Object);
+ MeshComp->SetRelativeScale3D(FVector(0.6f, 0.6f, 0.1f));
+ }
+
+ // Collision component
+ CollisionComp = CreateDefaultSubobject(TEXT("CollisionComp"));
+ CollisionComp->SetupAttachment(RootComponent);
+ CollisionComp->SetBoxExtent(FVector(30.f, 30.f, 10.f));
+ CollisionComp->SetCollisionProfileName("OverlapAllDynamic");
+ CollisionComp->SetGenerateOverlapEvents(true);
+ CollisionComp->OnComponentBeginOverlap.AddDynamic(this, &ASTGEnemy::OnOverlapBegin);
+}
+
+void ASTGEnemy::BeginPlay()
+{
+ Super::BeginPlay();
+
+ CurrentHealth = MaxHealth;
+ BaseX = GetActorLocation().X;
+ WaveSeed = FMath::FRand() * 1000.0f;
+ ElapsedTime = 0.0f;
+
+ // Start firing timer
+ GetWorldTimerManager().SetTimer(TimerHandle_Fire, this, &ASTGEnemy::Fire,
+ FireInterval, true, FireInterval);
+}
+
+void ASTGEnemy::Tick(float DeltaTime)
+{
+ Super::Tick(DeltaTime);
+
+ ElapsedTime += DeltaTime;
+
+ // Sinusoidal movement (wave pattern)
+ FVector NewLocation = GetActorLocation();
+
+ // Move downward
+ NewLocation.X -= VerticalSpeed * DeltaTime;
+
+ // Horizontal sine wave
+ float HorizontalOffset = HorizontalAmplitude * FMath::Sin(
+ HorizontalFrequency * (ElapsedTime + WaveSeed)
+ );
+ NewLocation.Y = BaseX + HorizontalOffset;
+
+ SetActorLocation(NewLocation);
+
+ // Check if enemy should despawn (moved off screen)
+ if (NewLocation.X < DespawnY)
+ {
+ Destroy();
+ }
+}
+
+void ASTGEnemy::Fire()
+{
+ // Fire radial burst of bullets
+ for (int32 i = 0; i < BulletsPerBurst; i++)
+ {
+ // Calculate angle for this bullet in the burst
+ float AngleDeg = (BurstSpread / BulletsPerBurst) * i;
+ float AngleRad = FMath::DegreesToRadians(AngleDeg);
+
+ // Calculate direction vector
+ FVector Direction = FVector(
+ FMath::Cos(AngleRad),
+ FMath::Sin(AngleRad),
+ 0.0f
+ );
+
+ // Spawn location slightly below enemy
+ FVector SpawnLocation = GetActorLocation() + FVector(0.f, 0.f, -30.f);
+
+ // Spawn bullet
+ ASTGProjectile* Bullet = GetWorld()->SpawnActor(
+ ASTGProjectile::StaticClass(),
+ SpawnLocation,
+ Direction.Rotation()
+ );
+
+ if (Bullet)
+ {
+ Bullet->bIsPlayerBullet = false;
+ Bullet->SetSpeed(EnemyBulletSpeed);
+ Bullet->SetBulletColor(FLinearColor::Red);
+ Bullet->Lifetime = EnemyBulletLifetime;
+ }
+ }
+}
+
+void ASTGEnemy::HandleDamage(float DamageAmount)
+{
+ CurrentHealth -= DamageAmount;
+
+ if (CurrentHealth <= 0)
+ {
+ // Award score to player
+ ASTGPawn* Player = Cast(UGameplayStatics::GetPlayerPawn(GetWorld(), 0));
+ if (Player)
+ {
+ Player->AddScore(ScoreValue);
+ }
+
+ // Destroy enemy
+ Destroy();
+ }
+}
+
+void ASTGEnemy::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor,
+ UPrimitiveComponent* OtherComp, int32 OtherBodyIndex,
+ bool bFromSweep, const FHitResult& SweepResult)
+{
+ // Enemy collides with player - damage player
+ if (OtherActor && OtherActor != this)
+ {
+ ASTGPawn* Player = Cast(OtherActor);
+ if (Player)
+ {
+ Player->TakeHit(1);
+ Destroy(); // Enemy dies on collision with player
+ }
+ }
+}
+```
+
+---
+
+## Step 4.4: Update Bullet Collision Logic
+
+Now that enemies exist, we can complete the bullet collision logic.
+
+### Open STGProjectile.cpp
+
+Find the `OnOverlapBegin` function and update the player bullet section:
+
+```cpp
+void ASTGProjectile::OnOverlapBegin(UPrimitiveComponent* OverlappedComp, AActor* OtherActor,
+ UPrimitiveComponent* OtherComp, int32 OtherBodyIndex,
+ bool bFromSweep, const FHitResult& SweepResult)
+{
+ if (OtherActor && OtherActor != this)
+ {
+ if (bIsPlayerBullet)
+ {
+ // Player bullet hits enemy
+ ASTGEnemy* Enemy = Cast(OtherActor);
+ if (Enemy)
+ {
+ Enemy->HandleDamage(Damage);
+ Destroy();
+ }
+ }
+ else
+ {
+ // Enemy bullet hits player
+ ASTGPawn* Player = Cast(OtherActor);
+ if (Player)
+ {
+ Player->TakeHit(1);
+ Destroy();
+ }
+ }
+ }
+}
+```
+
+### Add include at top of STGProjectile.cpp:
+
+```cpp
+#include "STGEnemy.h" // Add this line
+```
+
+---
+
+## Step 4.5: Compile the Code
+
+### In Unreal Editor:
+
+1. Click **"Compile"** button (bottom right)
+2. Wait for compilation (~30-60 seconds)
+3. Check for errors in Output Log
+
+OR
+
+### In VS Code:
+
+1. Open terminal in VS Code (`Ctrl+` `)
+2. Run build command (project-specific)
+3. Wait for build to finish
+
+### Expected Result:
+
+- ✅ Compilation succeeds
+- ✅ "C++ Classes" folder in Content Browser shows `STGEnemy`
+- ✅ No errors in Output Log
+
+---
+
+## Step 4.6: Create Blueprint Child
+
+Create a **minimal Blueprint** that inherits from STGEnemy. This Blueprint is ONLY for visual assets!
+
+1. In Content Browser, navigate to `Content → Blueprints`
+2. Right-click → **Blueprint Class**
+3. In "Pick Parent Class" window:
+ - Click "All Classes" dropdown
+ - Search for `STGEnemy`
+ - Select it
+ - Click "Select"
+4. Name it: `BP_Enemy`
+5. Double-click to open
+
+### In the Blueprint Editor:
+
+**Components (Left Panel):**
+- You'll see `MeshComp` and `CollisionComp` from C++
+- NO NEED to add them manually!
+
+**Variables (My Blueprint Panel):**
+- You'll see all 15 variables from C++ (MaxHealth, VerticalSpeed, etc.)
+- NO NEED to create them!
+- All default values are already set from C++!
+
+**What to do:**
+- NOTHING for now! All logic is in C++
+- Compile and Save
+
+---
+
+## Step 4.7: Test Enemy Spawning
+
+1. Drag `BP_Enemy` from Content Browser into the level
+2. Position it above the player (Y = 0, X = 500 or so)
+3. Press **Play** (`Alt+P`)
+
+### Expected Result
+
+**In Play Mode Window:**
+
+**Enemy behavior:**
+- ✅ Enemy appears above player
+- ✅ Enemy moves downward smoothly
+- ✅ Enemy moves in sine wave pattern (left-right oscillation)
+- ✅ Enemy fires red bullet bursts in circular pattern
+- ✅ Bullets spread out in all directions (360-degree burst)
+
+**Player vs Enemy:**
+- ✅ Player bullets (green) destroy enemy when they hit
+- ✅ Enemy bullets (red) damage player when they hit
+- ✅ Player takes damage and loses life when hit
+- ✅ Touching enemy directly damages player and destroys enemy
+
+**Visual confirmation:**
+- Enemy is a cube/box shape (red-ish by default)
+- Enemy fires 20 red bullets in a circular burst every 0.35 seconds
+- Player can shoot enemy with green bullets
+- Score increases when enemy is destroyed (check Output Log or will see in UI later)
+
+**To test collision:**
+- Fly player into enemy - both should take damage
+- Let enemy bullets hit player - player should take damage
+- Shoot enemy with player bullets - enemy health should decrease
+
+**Despawning:**
+- After ~10 seconds, enemy moves off bottom of screen and disappears (auto-destroy)
+
+---
+
+## Step 4.8: Update Player Special Ability
+
+Now that enemies exist, we can complete the special ability to destroy all enemies on screen.
+
+### Open STGPawn.cpp
+
+Find the `UseSpecial()` function and replace it with:
+
+```cpp
+void ASTGPawn::UseSpecial()
+{
+ if (!bSpecialUsed)
+ {
+ bSpecialUsed = true;
+
+ // Destroy all enemies on screen
+ TArray FoundEnemies;
+ UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASTGEnemy::StaticClass(), FoundEnemies);
+ for (AActor* Enemy : FoundEnemies)
+ {
+ Enemy->Destroy();
+ }
+
+ // Destroy all enemy bullets (not player bullets)
+ TArray FoundBullets;
+ UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASTGProjectile::StaticClass(), FoundBullets);
+ for (AActor* Bullet : FoundBullets)
+ {
+ ASTGProjectile* Projectile = Cast(Bullet);
+ if (Projectile && !Projectile->bIsPlayerBullet)
+ {
+ Projectile->Destroy();
+ }
+ }
+
+ UE_LOG(LogTemp, Warning, TEXT("SPECIAL ABILITY - Screen Cleared!"));
+ }
+}
+```
+
+### Add include at top of STGPawn.cpp:
+
+```cpp
+#include "STGEnemy.h" // Add this line
+```
+
+### Compile again!
+
+---
+
+## Step 4.9: Test Special Ability
+
+1. Place several `BP_Enemy` instances in the level (or duplicate the existing one)
+2. Press **Play**
+3. Let enemies spawn and fire bullets
+4. Press **X** to activate special ability
+
+### Expected Result in Play Mode:
+
+- ✅ All enemies disappear instantly when X is pressed
+- ✅ All red enemy bullets disappear instantly
+- ✅ Player's green bullets remain (not destroyed)
+- ✅ Message "SPECIAL ABILITY - Screen Cleared!" appears in Output Log
+- ✅ Pressing X again does nothing (ability can only be used once per game)
+
+---
+
+## Comparison Summary
+
+### Blueprint Approach (Part 4):
+
+1. Create BP_Enemy Blueprint ✅
+2. Add 2 components manually
+3. Add 16 variables one-by-one = **~20 minutes of clicking**
+4. Create Blueprint nodes for movement (~40 nodes with sine wave math)
+5. Create Blueprint nodes for firing (~30 nodes for radial burst)
+6. Create Blueprint nodes for collision detection
+7. Create Blueprint nodes for health/damage system
+8. Update BP_Player special ability nodes
+9. **Total: ~90 minutes**
+
+### C++ Approach (This Part):
+
+1. Create STGEnemy C++ class ✅
+2. Copy-paste header file with 15 variables **30 seconds**
+3. Copy-paste implementation file with all logic
+4. Update bullet collision (5 lines)
+5. Update player special ability (10 lines)
+6. Compile
+7. Create BP_Enemy (inherits everything from C++)
+8. **Total: ~25 minutes**
+
+**Time saved: 65 minutes** ⚡⚡⚡
+
+---
+
+## What's Next?
+
+In Part 5, we'll create the enemy spawner in C++. You'll see how easy it is to manage spawn rates and difficulty curves with code!
+
+---
+
+[← Previous: Part 3 (C++) - Create the Bullet](part-3-cpp-create-bullet.md) | [Back to Index](README.md) | [Next: Part 5 (C++) - Create Enemy Spawner →](part-5-cpp-create-spawner.md)
diff --git a/games/unreal/tutorial/part-5-cpp-create-spawner.md b/games/unreal/tutorial/part-5-cpp-create-spawner.md
new file mode 100644
index 0000000..8f8f1ef
--- /dev/null
+++ b/games/unreal/tutorial/part-5-cpp-create-spawner.md
@@ -0,0 +1,247 @@
+# Part 5 (C++): Create Enemy Spawner
+
+[← Previous: Part 4 (C++) - Create the Enemy](part-4-cpp-create-enemy.md) | [Back to Index](README.md) | [Next: Part 6 (C++) - Create Game Director →](part-6-cpp-create-game-director.md)
+
+---
+
+## Overview
+
+Create an enemy spawner that gradually increases difficulty over time. Copy-paste variables instead of manual UI configuration.
+
+**Time comparison:**
+- Blueprint: ~40 minutes (variables + curve setup + Blueprint nodes)
+- C++ (this part): ~10 minutes (copy-paste code)
+
+---
+
+## Step 5.1: Create STGEnemySpawner C++ Class
+
+1. **Tools → New C++ Class** → Actor → Name: `STGEnemySpawner`
+2. Wait for compilation
+
+---
+
+## Step 5.2: Define Spawner Variables
+
+### Open STGEnemySpawner.h in VS Code
+
+Replace content with:
+
+```cpp
+#pragma once
+
+#include "CoreMinimal.h"
+#include "GameFramework/Actor.h"
+#include "STGEnemySpawner.generated.h"
+
+UCLASS()
+class BULLETHELLGAME_API ASTGEnemySpawner : public AActor
+{
+ GENERATED_BODY()
+
+public:
+ ASTGEnemySpawner();
+
+protected:
+ virtual void BeginPlay() override;
+
+public:
+ virtual void Tick(float DeltaTime) override;
+
+ // ===== SPAWNING VARIABLES =====
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawning")
+ float SpawnAreaHalfWidth = 900.0f;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawning")
+ float GameDuration = 300.0f; // 5 minutes
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawning")
+ int32 MaxSimultaneousEnemies = 120;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Spawning")
+ float BaseSpawnInterval = 2.0f;
+
+ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Spawning")
+ float ElapsedTime = 0.0f;
+
+ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Spawning")
+ bool bSpawningActive = true;
+
+private:
+ float SpawnTimer = 0.0f;
+ float CurrentSpawnInterval = 2.0f;
+
+ void SpawnEnemy();
+ float CalculateSpawnInterval();
+ FVector GetRandomSpawnLocation();
+};
+```
+
+---
+
+## Step 5.3: Implement Spawner Logic
+
+### Open STGEnemySpawner.cpp
+
+Replace with:
+
+```cpp
+#include "STGEnemySpawner.h"
+#include "STGEnemy.h"
+#include "Kismet/GameplayStatics.h"
+
+ASTGEnemySpawner::ASTGEnemySpawner()
+{
+ PrimaryActorTick.bCanEverTick = true;
+}
+
+void ASTGEnemySpawner::BeginPlay()
+{
+ Super::BeginPlay();
+
+ ElapsedTime = 0.0f;
+ SpawnTimer = 0.0f;
+ CurrentSpawnInterval = BaseSpawnInterval;
+}
+
+void ASTGEnemySpawner::Tick(float DeltaTime)
+{
+ Super::Tick(DeltaTime);
+
+ if (!bSpawningActive)
+ return;
+
+ ElapsedTime += DeltaTime;
+
+ // Stop spawning after game duration
+ if (ElapsedTime >= GameDuration)
+ {
+ bSpawningActive = false;
+ return;
+ }
+
+ // Update spawn interval based on difficulty curve
+ CurrentSpawnInterval = CalculateSpawnInterval();
+
+ // Spawn timer
+ SpawnTimer -= DeltaTime;
+ if (SpawnTimer <= 0.0f)
+ {
+ // Check enemy count
+ TArray FoundEnemies;
+ UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASTGEnemy::StaticClass(), FoundEnemies);
+
+ if (FoundEnemies.Num() < MaxSimultaneousEnemies)
+ {
+ SpawnEnemy();
+ }
+
+ SpawnTimer = CurrentSpawnInterval;
+ }
+}
+
+void ASTGEnemySpawner::SpawnEnemy()
+{
+ FVector SpawnLocation = GetRandomSpawnLocation();
+ FRotator SpawnRotation = FRotator::ZeroRotator;
+
+ ASTGEnemy* NewEnemy = GetWorld()->SpawnActor(
+ ASTGEnemy::StaticClass(),
+ SpawnLocation,
+ SpawnRotation
+ );
+}
+
+float ASTGEnemySpawner::CalculateSpawnInterval()
+{
+ // Difficulty curve: spawn faster as time progresses
+ float GameProgress = ElapsedTime / GameDuration; // 0.0 to 1.0
+
+ // Start at BaseSpawnInterval, reduce to 0.5 seconds at end
+ float MinInterval = 0.5f;
+ float Interval = FMath::Lerp(BaseSpawnInterval, MinInterval, GameProgress);
+
+ return FMath::Max(Interval, MinInterval);
+}
+
+FVector ASTGEnemySpawner::GetRandomSpawnLocation()
+{
+ // Spawn at top of screen, random X position
+ FVector SpawnLoc = GetActorLocation();
+ SpawnLoc.Y = FMath::FRandRange(-SpawnAreaHalfWidth, SpawnAreaHalfWidth);
+ SpawnLoc.X = 800.0f; // Top of play area
+ SpawnLoc.Z = 0.0f;
+
+ return SpawnLoc;
+}
+```
+
+---
+
+## Step 5.4: Compile
+
+1. Click **Compile** in Unreal Editor
+2. Wait for compilation
+3. Check for errors
+
+---
+
+## Step 5.5: Place Spawner in Level
+
+1. From Content Browser "C++ Classes" folder, find `STGEnemySpawner`
+2. Can either:
+ - **Option A**: Drag directly into level (no Blueprint needed!)
+ - **Option B**: Create `BP_EnemySpawner` Blueprint child for tweaking values in editor
+
+3. Position spawner at origin (0, 0, 0) or anywhere - location doesn't matter for spawning
+
+---
+
+## Step 5.6: Test Spawning
+
+1. Remove any manually-placed enemies from level
+2. Make sure spawner is placed
+3. Press **Play**
+
+### Expected Result in Play Mode:
+
+**Spawning behavior:**
+- ✅ Enemies spawn at top of screen every ~2 seconds initially
+- ✅ Spawn rate gradually increases (gets faster over time)
+- ✅ Enemies spawn at random horizontal positions
+- ✅ Maximum of 120 enemies on screen at once
+- ✅ After 5 minutes (300 seconds), spawning stops
+
+**Visual confirmation:**
+- Enemies appear from top edge of screen
+- Each spawns at a different Y position (left-right spread)
+- As time passes, enemies spawn more frequently
+- Game becomes progressively harder
+
+**Performance:**
+- Even with many enemies, game maintains 60 FPS
+- No lag or stuttering when many enemies/bullets on screen
+
+---
+
+## Comparison Summary
+
+### Blueprint: ~40 minutes
+- Create spawner Blueprint
+- Add 6 variables manually
+- Create spawn rate curve asset
+- Complex Blueprint nodes for curve sampling
+- Random position calculation nodes
+- Enemy counting logic
+
+### C++: ~10 minutes
+- Create C++ class
+- Copy-paste variables and logic
+- Compile
+- Place in level
+
+**Time saved: 30 minutes** ⚡
+
+---
+
+[← Previous: Part 4 (C++) - Create the Enemy](part-4-cpp-create-enemy.md) | [Back to Index](README.md) | [Next: Part 6 (C++) - Create Game Director →](part-6-cpp-create-game-director.md)
diff --git a/games/unreal/tutorial/part-6-cpp-create-game-director.md b/games/unreal/tutorial/part-6-cpp-create-game-director.md
new file mode 100644
index 0000000..56f0e91
--- /dev/null
+++ b/games/unreal/tutorial/part-6-cpp-create-game-director.md
@@ -0,0 +1,167 @@
+# Part 6 (C++): Create Game Director
+
+[← Previous: Part 5 (C++) - Create Enemy Spawner](part-5-cpp-create-spawner.md) | [Back to Index](README.md) | [Next: Part 7 (C++) - Create UI →](part-7-cpp-create-ui.md)
+
+---
+
+## Overview
+
+Create a Game Director to manage the game timer, victory/defeat conditions, and overall game state.
+
+**Time:** ~10 minutes
+
+---
+
+## Step 6.1: Create STGGameDirector C++ Class
+
+1. **Tools → New C++ Class** → Actor → Name: `STGGameDirector`
+2. Wait for compilation
+
+---
+
+## Step 6.2: Define Game Director Variables
+
+### STGGameDirector.h:
+
+```cpp
+#pragma once
+
+#include "CoreMinimal.h"
+#include "GameFramework/Actor.h"
+#include "STGGameDirector.generated.h"
+
+UCLASS()
+class BULLETHELLGAME_API ASTGGameDirector : public AActor
+{
+ GENERATED_BODY()
+
+public:
+ ASTGGameDirector();
+
+protected:
+ virtual void BeginPlay() override;
+
+public:
+ virtual void Tick(float DeltaTime) override;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Game")
+ float GameDuration = 300.0f;
+
+ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Game")
+ float ElapsedTime = 0.0f;
+
+ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Game")
+ bool bGameActive = true;
+
+ void OnPlayerDied();
+ void OnVictory();
+ void OnGameOver();
+};
+```
+
+---
+
+## Step 6.3: Implement Game Director
+
+### STGGameDirector.cpp:
+
+```cpp
+#include "STGGameDirector.h"
+#include "Kismet/GameplayStatics.h"
+
+ASTGGameDirector::ASTGGameDirector()
+{
+ PrimaryActorTick.bCanEverTick = true;
+}
+
+void ASTGGameDirector::BeginPlay()
+{
+ Super::BeginPlay();
+ ElapsedTime = 0.0f;
+ bGameActive = true;
+}
+
+void ASTGGameDirector::Tick(float DeltaTime)
+{
+ Super::Tick(DeltaTime);
+
+ if (!bGameActive)
+ return;
+
+ ElapsedTime += DeltaTime;
+
+ // Check for victory (survived full duration)
+ if (ElapsedTime >= GameDuration)
+ {
+ OnVictory();
+ }
+}
+
+void ASTGGameDirector::OnPlayerDied()
+{
+ OnGameOver();
+}
+
+void ASTGGameDirector::OnVictory()
+{
+ bGameActive = false;
+ UE_LOG(LogTemp, Warning, TEXT("VICTORY! You survived %f seconds!"), ElapsedTime);
+
+ // Pause game
+ UGameplayStatics::SetGamePaused(GetWorld(), true);
+}
+
+void ASTGGameDirector::OnGameOver()
+{
+ bGameActive = false;
+ UE_LOG(LogTemp, Warning, TEXT("GAME OVER! Survived %f seconds"), ElapsedTime);
+
+ // Pause game
+ UGameplayStatics::SetGamePaused(GetWorld(), true);
+}
+```
+
+---
+
+## Step 6.4: Update Player Death to Notify Director
+
+### In STGPawn.cpp, update HandleDeath():
+
+```cpp
+void ASTGPawn::HandleDeath()
+{
+ SetActorHiddenInGame(true);
+
+ // Find and notify Game Director
+ TArray FoundDirectors;
+ UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASTGGameDirector::StaticClass(), FoundDirectors);
+ if (FoundDirectors.Num() > 0)
+ {
+ ASTGGameDirector* Director = Cast(FoundDirectors[0]);
+ if (Director)
+ {
+ Director->OnPlayerDied();
+ }
+ }
+}
+```
+
+Add include: `#include "STGGameDirector.h"`
+
+---
+
+## Step 6.5: Place Director in Level and Test
+
+1. Drag `STGGameDirector` from C++ Classes into level
+2. Press Play
+3. Wait 5 minutes OR let player die
+
+### Expected Result:
+
+- ✅ Timer counts up from 0
+- ✅ After 300 seconds: "VICTORY!" message, game pauses
+- ✅ If player dies: "GAME OVER!" message, game pauses
+
+---
+
+[← Previous: Part 5 (C++) - Create Enemy Spawner](part-5-cpp-create-spawner.md) | [Back to Index](README.md) | [Next: Part 7 (C++) - Create UI →](part-7-cpp-create-ui.md)
diff --git a/games/unreal/tutorial/part-7-cpp-create-ui.md b/games/unreal/tutorial/part-7-cpp-create-ui.md
new file mode 100644
index 0000000..415d5c2
--- /dev/null
+++ b/games/unreal/tutorial/part-7-cpp-create-ui.md
@@ -0,0 +1,209 @@
+# Part 7 (C++): Create UI
+
+[← Previous: Part 6 (C++) - Create Game Director](part-6-cpp-create-game-director.md) | [Back to Index](README.md) | [Next: Part 8 (C++) - Create Game Mode →](part-8-cpp-create-game-mode.md)
+
+---
+
+## Overview
+
+For UI, we use **Widget Blueprints** for visual layout (drag-and-drop is better for UI design), but bind to C++ properties for data.
+
+**Time:** ~15 minutes
+
+---
+
+## Step 7.1: Create Widget Blueprint
+
+1. Content Browser → UI folder
+2. Right-click → **User Interface → Widget Blueprint**
+3. Name: `WBP_HUD`
+4. Double-click to open Widget Designer
+
+---
+
+## Step 7.2: Design HUD Layout
+
+In Widget Designer:
+
+1. **Add Text blocks** (from Palette → Common):
+ - `txt_Score` - Display score
+ - `txt_Lives` - Display lives
+ - `txt_Timer` - Display time remaining
+
+2. **Position them** (top-left corner):
+ - Score: Top-left (0, 0)
+ - Lives: Below score (0, 30)
+ - Timer: Below lives (0, 60)
+
+3. **Style text:**
+ - Font Size: 24
+ - Color: White
+ - Set default text: "Score: 0", "Lives: 3", "Time: 300"
+
+4. **Compile and Save**
+
+---
+
+## Step 7.3: Create HUD Manager C++ Class
+
+We'll create a simple C++ class to update the UI.
+
+### Create STGHUDManager.h:
+
+```cpp
+#pragma once
+
+#include "CoreMinimal.h"
+#include "GameFramework/Actor.h"
+#include "STGHUDManager.generated.h"
+
+UCLASS()
+class BULLETHELLGAME_API ASTGHUDManager : public AActor
+{
+ GENERATED_BODY()
+
+public:
+ ASTGHUDManager();
+
+protected:
+ virtual void BeginPlay() override;
+
+public:
+ virtual void Tick(float DeltaTime) override;
+
+ UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "UI")
+ TSubclassOf HUDWidgetClass;
+
+ UFUNCTION(BlueprintCallable, Category = "UI")
+ void UpdateScore(int32 NewScore);
+
+ UFUNCTION(BlueprintCallable, Category = "UI")
+ void UpdateLives(int32 NewLives);
+
+ UFUNCTION(BlueprintCallable, Category = "UI")
+ void UpdateTimer(float TimeRemaining);
+
+private:
+ class UUserWidget* HUDWidget;
+};
+```
+
+### STGHUDManager.cpp:
+
+```cpp
+#include "STGHUDManager.h"
+#include "Blueprint/UserWidget.h"
+#include "Components/TextBlock.h"
+
+ASTGHUDManager::ASTGHUDManager()
+{
+ PrimaryActorTick.bCanEverTick = true;
+}
+
+void ASTGHUDManager::BeginPlay()
+{
+ Super::BeginPlay();
+
+ if (HUDWidgetClass)
+ {
+ HUDWidget = CreateWidget(GetWorld(), HUDWidgetClass);
+ if (HUDWidget)
+ {
+ HUDWidget->AddToViewport();
+ }
+ }
+}
+
+void ASTGHUDManager::Tick(float DeltaTime)
+{
+ Super::Tick(DeltaTime);
+}
+
+void ASTGHUDManager::UpdateScore(int32 NewScore)
+{
+ if (HUDWidget)
+ {
+ UTextBlock* ScoreText = Cast(HUDWidget->GetWidgetFromName(TEXT("txt_Score")));
+ if (ScoreText)
+ {
+ ScoreText->SetText(FText::Format(FText::FromString("Score: {0}"), NewScore));
+ }
+ }
+}
+
+void ASTGHUDManager::UpdateLives(int32 NewLives)
+{
+ if (HUDWidget)
+ {
+ UTextBlock* LivesText = Cast(HUDWidget->GetWidgetFromName(TEXT("txt_Lives")));
+ if (LivesText)
+ {
+ LivesText->SetText(FText::Format(FText::FromString("Lives: {0}"), NewLives));
+ }
+ }
+}
+
+void ASTGHUDManager::UpdateTimer(float TimeRemaining)
+{
+ if (HUDWidget)
+ {
+ UTextBlock* TimerText = Cast(HUDWidget->GetWidgetFromName(TEXT("txt_Timer")));
+ if (TimerText)
+ {
+ int32 Seconds = FMath::CeilToInt(TimeRemaining);
+ TimerText->SetText(FText::Format(FText::FromString("Time: {0}s"), Seconds));
+ }
+ }
+}
+```
+
+---
+
+## Step 7.4: Integrate HUD with Game
+
+1. Place `STGHUDManager` in level
+2. Select it, in Details panel:
+ - Set **HUD Widget Class** → `WBP_HUD`
+
+3. Update `STGGameDirector` to update timer:
+
+```cpp
+void ASTGGameDirector::Tick(float DeltaTime)
+{
+ // ... existing code ...
+
+ // Update HUD
+ TArray FoundManagers;
+ UGameplayStatics::GetAllActorsOfClass(GetWorld(), ASTGHUDManager::StaticClass(), FoundManagers);
+ if (FoundManagers.Num() > 0)
+ {
+ ASTGHUDManager* HUDMgr = Cast(FoundManagers[0]);
+ if (HUDMgr)
+ {
+ HUDMgr->UpdateTimer(GameDuration - ElapsedTime);
+ }
+ }
+}
+```
+
+4. Update `STGPawn` to update score/lives when they change
+
+---
+
+## Step 7.5: Test UI
+
+Press Play
+
+### Expected Result:
+
+**In Play Mode:**
+- ✅ UI appears in top-left corner
+- ✅ "Score: 0", "Lives: 3", "Time: 300" displayed
+- ✅ Timer counts down from 300
+- ✅ Score increases when enemies are destroyed
+- ✅ Lives decrease when player is hit
+- ✅ Text is readable (white on dark background)
+
+---
+
+[← Previous: Part 6 (C++) - Create Game Director](part-6-cpp-create-game-director.md) | [Back to Index](README.md) | [Next: Part 8 (C++) - Create Game Mode →](part-8-cpp-create-game-mode.md)
diff --git a/games/unreal/tutorial/part-8-cpp-create-game-mode.md b/games/unreal/tutorial/part-8-cpp-create-game-mode.md
new file mode 100644
index 0000000..d67919f
--- /dev/null
+++ b/games/unreal/tutorial/part-8-cpp-create-game-mode.md
@@ -0,0 +1,96 @@
+# Part 8 (C++): Create Game Mode
+
+[← Previous: Part 7 (C++) - Create UI](part-7-cpp-create-ui.md) | [Back to Index](README.md) | [Next: Part 9 (C++) - Final Setup →](part-9-cpp-final-setup.md)
+
+---
+
+## Overview
+
+Create a custom Game Mode to set the default pawn class and manage game rules.
+
+**Time:** ~5 minutes
+
+---
+
+## Step 8.1: Create STGGameMode C++ Class
+
+1. **Tools → New C++ Class**
+2. Choose **"Game Mode Base"** as parent
+3. Name: `STGGameMode`
+4. Create Class
+
+---
+
+## Step 8.2: Define Game Mode
+
+### STGGameMode.h:
+
+```cpp
+#pragma once
+
+#include "CoreMinimal.h"
+#include "GameFramework/GameModeBase.h"
+#include "STGGameMode.generated.h"
+
+UCLASS()
+class BULLETHELLGAME_API ASTGGameMode : public AGameModeBase
+{
+ GENERATED_BODY()
+
+public:
+ ASTGGameMode();
+};
+```
+
+### STGGameMode.cpp:
+
+```cpp
+#include "STGGameMode.h"
+#include "STGPawn.h"
+
+ASTGGameMode::ASTGGameMode()
+{
+ // Set default pawn class to our player
+ DefaultPawnClass = ASTGPawn::StaticClass();
+
+ // Disable auto-possess (we'll handle spawning ourselves)
+ bStartPlayersAsSpectators = false;
+}
+```
+
+---
+
+## Step 8.3: Set Game Mode in Project Settings
+
+1. **Edit → Project Settings**
+2. **Project → Maps & Modes**
+3. Under "Default Modes":
+ - **Default GameMode** → Select `STGGameMode`
+4. Close Project Settings
+
+---
+
+## Step 8.4: Test
+
+Create a new level or use existing one:
+
+1. **File → New Level** → Empty Level
+2. Save as `BulletHellLevel`
+3. Add:
+ - Player Start (from Place Actors panel)
+ - STGEnemySpawner
+ - STGGameDirector
+ - STGHUDManager
+ - Directional Light (for visibility)
+
+4. Press Play
+
+### Expected Result:
+
+- ✅ Player automatically spawns at Player Start location
+- ✅ No need to manually drag BP_Player into level
+- ✅ All game systems work together
+
+---
+
+[← Previous: Part 7 (C++) - Create UI](part-7-cpp-create-ui.md) | [Back to Index](README.md) | [Next: Part 9 (C++) - Final Setup →](part-9-cpp-final-setup.md)
diff --git a/games/unreal/tutorial/part-9-cpp-final-setup.md b/games/unreal/tutorial/part-9-cpp-final-setup.md
new file mode 100644
index 0000000..b09c5c0
--- /dev/null
+++ b/games/unreal/tutorial/part-9-cpp-final-setup.md
@@ -0,0 +1,160 @@
+# Part 9 (C++): Final Setup
+
+[← Previous: Part 8 (C++) - Create Game Mode](part-8-cpp-create-game-mode.md) | [Back to Index](README.md)
+
+---
+
+## Overview
+
+Polish the game with visual assets, materials, and final tweaks.
+
+**Time:** ~15 minutes
+
+---
+
+## Step 9.1: Assign Better Visuals to Blueprints
+
+Now we use Blueprints for what they're good at: assigning visual assets!
+
+### BP_Player:
+
+1. Open `BP_Player`
+2. Select `ShipMesh` component
+3. In Details:
+ - **Static Mesh** → Keep Cone or choose a spaceship model
+ - **Material** → Create or assign a green emissive material
+4. Compile and Save
+
+### BP_Enemy:
+
+1. Open `BP_Enemy`
+2. Select `MeshComp` component
+3. In Details:
+ - **Static Mesh** → Keep Cube or choose enemy model
+ - **Material** → Create or assign a red emissive material
+4. Compile and Save
+
+### BP_Bullet (if you created one):
+
+1. Same process - assign materials for player (green) vs enemy (red) bullets
+
+---
+
+## Step 9.2: Create Background
+
+1. In level, add **Plane** (from Place Actors → Basic → Plane)
+2. Scale it large (Scale: 50, 50, 1)
+3. Position below player (Z: -100)
+4. Assign dark material (black or dark blue)
+5. This provides contrast for bullets and enemies
+
+---
+
+## Step 9.3: Adjust Camera
+
+If camera needs adjustment:
+
+1. Select BP_Player in level
+2. Find `SpringArm` component
+3. Adjust:
+ - **Target Arm Length** - Higher = further away camera
+ - **Socket Offset** - Adjust view position
+
+---
+
+## Step 9.4: Final Testing
+
+Press Play and verify:
+
+**Gameplay:**
+- ✅ Player moves smoothly with WASD
+- ✅ Player fires green bullets in spread pattern
+- ✅ Enemies spawn from top
+- ✅ Enemies move in sine wave pattern
+- ✅ Enemies fire red bullet bursts
+- ✅ Collision detection works (bullets hit enemies, enemies hit player)
+- ✅ Score increases when enemies destroyed
+- ✅ Lives decrease when hit
+- ✅ Special ability clears screen (X key)
+- ✅ Timer counts down
+- ✅ Victory after 300 seconds
+- ✅ Game over if lives reach 0
+
+**Visual Polish:**
+- ✅ Player and enemies have distinct colors
+- ✅ Bullets are visible and distinguishable
+- ✅ UI is readable
+- ✅ Background provides good contrast
+
+**Performance:**
+- ✅ 60 FPS with 100+ bullets on screen
+- ✅ No lag or stuttering
+
+---
+
+## Step 9.5: Build Standalone Game (Optional)
+
+To build a playable executable:
+
+1. **File → Package Project → Windows** (or Linux)
+2. Choose output folder
+3. Wait for build (5-10 minutes)
+4. Run the `.exe` file from output folder
+
+---
+
+## Completion Summary
+
+### Total Time Comparison
+
+| Part | Blueprint | C++ | Time Saved |
+|------|-----------|-----|------------|
+| 1. Project Setup | 5 min | 10 min | -5 min |
+| 2. Player | 60 min | 15 min | 45 min ⚡ |
+| 3. Bullet | 30 min | 10 min | 20 min ⚡ |
+| 4. Enemy | 90 min | 25 min | 65 min ⚡ |
+| 5. Spawner | 40 min | 10 min | 30 min ⚡ |
+| 6. Game Director | 45 min | 10 min | 35 min ⚡ |
+| 7. UI | 30 min | 15 min | 15 min ⚡ |
+| 8. Game Mode | 20 min | 5 min | 15 min ⚡ |
+| 9. Final Setup | 40 min | 15 min | 25 min ⚡ |
+| **TOTAL** | **6-8 hours** | **2-3 hours** | **4-5 hours saved!** ⚡⚡⚡ |
+
+### Key Benefits Achieved
+
+✅ **90% faster variable definition** - copy-paste vs clicking
+✅ **Version control friendly** - readable C++ diffs instead of binary Blueprints
+✅ **Type-safe** - compiler catches errors before runtime
+✅ **IDE support** - autocomplete, refactoring, debugging
+✅ **Easier to maintain** - code is documentation
+✅ **Reusable** - copy C++ files to new projects instantly
+
+### Hybrid Approach Used
+
+- **C++ for logic** - All game mechanics, variables, algorithms
+- **Blueprints for visuals** - Meshes, materials, colors
+- **Best of both worlds** - Fast development + visual asset management
+
+---
+
+## What's Next?
+
+**Extend the game:**
+- Add power-ups
+- Multiple enemy types
+- Boss battles
+- Sound effects and music
+- Particle effects
+- Leaderboard system
+
+**All easily done in C++** with the same copy-paste efficiency!
+
+---
+
+## Congratulations! 🎉
+
+You've built a complete bullet-hell game in Unreal Engine using C++ in 2-3 hours instead of 6-8 hours with Blueprints!
+
+---
+
+[← Previous: Part 8 (C++) - Create Game Mode](part-8-cpp-create-game-mode.md) | [Back to Index](README.md)