14 KiB
Part 9 (C++): Polish & Debug Features
← Previous: Part 8 (C++) - Create Game Mode | Back to Index | Next: Part 10 (C++) - Final Setup →
Overview
Add debug cheats, visual polish, enemy variety, and optimization for a complete game experience.
Time: ~30 minutes
Step 9.1: Add Debug Cheat (Invincibility Toggle)
Create Input Action
- Content Browser → Right-click → Input → Input Action
- Name:
IA_CheatInvincible - Save
Add to Input Mapping Context
- Open
IMC_Player - Click + to add new mapping
- Select
IA_CheatInvincible - Key: Click dropdown → Select I key
- Save
Configure BP_Player
- Open BP_Player
- In Class Defaults → Input section:
- Cheat Invincible Action → Select
IA_CheatInvincible
- Cheat Invincible Action → Select
- Compile and Save
Test
Press I during gameplay → Should see "[CHEAT] INVINCIBILITY ON/OFF" message.
Step 9.2: Fixed Camera Setup
The player-attached camera moves with the player. For a bullet-hell game, we want a fixed camera showing the entire play area.
New STGFixedCamera Class
The camera has been removed from STGPawn. A new STGFixedCamera actor handles the view.
Key Feature: The camera automatically calculates the correct height to show exactly the play area defined in STGGameDirector. No manual tweaking needed!
Key Properties:
bAutoFitPlayArea- When true (default), camera auto-sizes to fit the play areaPlayAreaMargin- Extra margin around play area (default: 5%)FieldOfView- Camera FOV (default: 60°)bUseOrthographic- Enable for 2D-style flat projection
Play Area Bounds (STGGameDirector)
The play area is now centrally defined in STGGameDirector:
PlayAreaMin- Bottom-left corner (default: -850, -450)PlayAreaMax- Top-right corner (default: 850, 450)
Changing the play area in Game Director automatically updates the camera view!
Level Setup
- Open your game level in the editor
- Open the Place Actors panel:
- Menu: Window → Place Actors
- In the Place Actors panel, click the Search field
- Type
STGFixedCamera - Drag the
STGFixedCameraclass from the panel into your level viewport - The camera will automatically position itself to show the play area on BeginPlay
Optional adjustments (in Details panel):
- Play Area Margin - Increase for more space around edges
- Field of View - Higher values = wider angle, lower camera height
- bAutoFitPlayArea - Disable to use manual
CameraHeightinstead
The camera automatically activates on BeginPlay and displays a debug message showing the calculated height.
Step 9.3: Enemy Variety
Four enemy types with incremental difficulty - enemies start completely harmless and gradually become more threatening:
| Type | Shape | Color | HP | Speed | Bullets | Difficulty |
|---|---|---|---|---|---|---|
| Fodder | Tiny square | Green | 1 | Very slow | None | ⭐ Easiest |
| Runner | Diamond ◇ | Cyan | 3 | Medium | None | ⭐⭐ Easy |
| Turret | Square ■ | Orange | 15 | Slow | 4 (360°) | ⭐⭐⭐ Medium |
| Tank | Rectangle ▬ | Red | 50 | Crawling | 20 (360°) | ⭐⭐⭐⭐ Hard |
Incremental Design Philosophy
- Fodder: Training targets - dies in 1 hit, no threat, SPAM these!
- Runner: Adds speed challenge - still no bullets, but harder to hit
- Turret: Introduces bullets GENTLY - slow, few bullets (first shooter)
- Tank: Full challenge - tanky HP + bullet hell (rapid fire)
Visual Distinction (Top-Down)
All shapes are flat cubes with different scales/rotations:
- Fodder - Tiny green square (easy to spot, easy to kill)
- Runner - Cyan diamond (rotated 45°, quick movement)
- Turret - Orange square (medium size, first to shoot)
- Tank - Red wide rectangle (large, intimidating)
Difficulty Progression (Fodder Spam!)
- 0-25%: All Fodder - endless targets!
- 25-50%: Fodder (85%) + Runner (15%) - almost all fodder
- 50-75%: Fodder (70%) + Runner (20%) + Turret (10%) - mostly fodder
- 75-100%: Fodder (55%) + Runner (20%) + Turret (15%) + Tank (10%)
Step 9.4: Player Upgrade System
Player starts WEAK and gets stronger with score! Classic arcade progression.
Starting Stats (Level 0)
- Volley: 1 bullet (single shot)
- Fire Rate: 0.5 seconds (slow)
- Spread: 0° (straight ahead)
Upgrade Thresholds
| Level | Score | Bullets | Fire Rate | Spread |
|---|---|---|---|---|
| 0 | 0 | 1 | 0.50s | 0° |
| 1 | 100 | 2 | 0.35s | 8° |
| 2 | 300 | 3 | 0.20s | 12° |
| 3 | 600 | 4 | 0.12s | 16° |
| 4 | 1000 | 5 | 0.08s | 20° |
How It Works
void ASTGPawn::CheckUpgrades()
{
// Called every time score changes
// Compares score against STG::Player::UpgradeScore1-4 thresholds
// Increases VolleySize, VolleySpread, decreases FireInterval
// Shows "POWER UP!" message on screen
}
Step 9.4: Distinct Bullet Visuals
Bullets now have different sizes, brightness, and grazing support:
Player Bullets:
- Scale: 0.06 (small)
- Emissive Intensity: 2.0 (dim)
- Color: Soft green (0.2, 0.8, 0.3)
Enemy Bullets (with Grazing!):
- Visual Scale: 0.25 (LARGE - easy to see)
- Collision Radius: 3.0 (TINY hitbox)
- Emissive Intensity: 8.0 (bright glow)
- Color: Orange-red (1.0, 0.3, 0.1)
Grazing Mechanic: Enemy bullets appear large but have tiny hitboxes. Players can "touch" bullets visually without dying - a classic bullet-hell feature!
Step 9.5: Centralized Game Settings
All game constants are now defined in STGGameSettings.h - one file to rule them all!
What's Centralized
| Category | Examples |
|---|---|
| Play Area | MinX/MaxX, MinY/MaxY, Width/Height |
| Game Timing | DefaultDuration (60s), DebugQuickDuration (10s) |
| Player | MoveSpeed, FireInterval, BulletSpeed, MaxLives |
| Enemy Types | Health, ScoreValue, Speed, BurstSpread for each type |
| Spawner | BaseSpawnInterval, MaxSimultaneousEnemies |
| Camera | DefaultFOV, DefaultHeight, DefaultMargin |
| VFX | DeathParticleCount |
Usage in Code
#include "STGGameSettings.h"
// Access via namespaces
float speed = STG::Player::MoveSpeed;
float width = STG::PlayArea::Width;
int32 health = STG::Enemy::Tank::Health;
Changing Values
- Open
Source/BulletHellCPP/STGGameSettings.h - Find the value you want to change
- Modify it once - all systems update automatically!
Example: To change play area size:
namespace PlayArea
{
constexpr float MinX = -1000.0f; // Was -850
constexpr float MaxX = 1000.0f; // Was 850
// ... camera, player bounds, spawner all update automatically
}
Step 9.6: 60-Second Game Duration
Game duration is now set in STGGameSettings.h:
STG::Game::DefaultDuration= 60.0f (1 minute)STG::Spawner::BaseSpawnInterval= 1.0fSTG::Spawner::MinSpawnInterval= 0.5f (end-game intensity)
Step 9.7: Hit/Death Visual Effects (Niagara)
VFX properties added to enemies and player for GPU-intensive particle effects.
Create Niagara Systems
- Content Browser → Right-click → FX → Niagara System
- Select "New system from selected emitter(s)"
- Search and add "Fountain" emitter as base
- Create two systems:
NS_HitEffect- Small burst (50-100 particles)NS_DeathExplosion- Large explosion (500+ particles)
Configure Hit Effect
- Open
NS_HitEffect(double-click in Content Browser) - You'll see the System Overview panel in the center with the emitter graph
- Click on the Fountain emitter (right panel) to select it
Emitter Update Section:
- Find Emitter State → Click on it
- Change Life Cycle Mode from
Selfto System - IMPORTANT: Set Loop Behavior to Once (not Infinite!)
- This makes the emitter play once and then mark itself as complete
- Without this, the particles stay forever!
Configure Spawn Rate for Burst:
- Keep the existing Spawn Rate module in Emitter Update (don't delete it)
- Click on Spawn Rate to select it
- If you see a warning "The module has unmet dependencies":
- Click "Fix issue" to move SpawnRate after EmitterState (required order)
- In the Selection panel (right side), set:
- Spawn Rate =
500(high value to spawn many particles quickly)
- Spawn Rate =
- The particles will burst once because Life Cycle Mode = System (set in step 5) makes the emitter fire only when the system is triggered, not continuously
Particle Spawn Section:
-
Click Initialize Particle module
-
Find Lifetime → Set Lifetime Min =
0.3, Lifetime Max =0.5 -
Find Sprite Size → Set Sprite Size Min =
3, Sprite Size Max =8 -
Click Add Velocity (or Add Velocity in Cone) module
-
Set Velocity Strength Min =
200, Velocity Strength Max =400
Particle Update Section:
- Click Scale Color module (in Particle Update)
- The module scales color/alpha over the particle's lifetime using curves:
- Scale Mode =
RGB and Alpha Separately(default is fine) - Scale Alpha → Check the box, set to Float from Curve
- In the FloatCurve graph below, the curve should go from 1.0 (left/start) to 0.0 (right/end)
- This makes particles fade out over their lifetime
- Scale Mode =
- To edit the curve: click on the curve line, drag points, or use the Templates buttons (the curve icons) to pick a preset fade shape
Render Section:
-
Ensure Sprite Renderer is enabled (checked)
-
Click Compile (top toolbar) → Then Save
Configure Death Explosion
- Open
NS_DeathExplosion - Click the Fountain emitter to select it
Emitter Update:
- Click on Spawn Rate module
- If you see a dependency warning, click "Fix issue"
- Set Spawn Rate =
1000(high value for big explosion) - Click Emitter State:
- Change Life Cycle Mode to
System - IMPORTANT: Set Loop Behavior to Once (prevents particles staying forever)
- Change Life Cycle Mode to
Particle Spawn:
-
In Initialize Particle:
- Lifetime Min =
0.5, Lifetime Max =1.0 - Sprite Size Min =
5, Sprite Size Max =15
- Lifetime Min =
-
In Shape Location → Set Shape Primitive =
Sphere -
In Add Velocity → Set Velocity Strength Min =
500, Max =800
Particle Update:
-
Click + next to Particle Update → Search and add
Drag -
Set Drag =
2.0(particles slow down naturally) -
In Scale Color:
- Start: Red (1.0, 0.2, 0.0) with alpha 1.0
- End: Yellow (1.0, 0.8, 0.0) with alpha 0.0
-
Compile and Save
Assign in Blueprints
Create BP_Enemy:
- Content Browser → Right-click → Blueprint Class
- In the popup, expand All Classes and search for
STGEnemy - Select STGEnemy as the parent class → Click Select
- Name it
BP_Enemy - Open
BP_Enemy(double-click) - Click Class Defaults (top toolbar)
- In the Details panel, search for
vfx - Under VFX section:
- Hit Effect → Select
NS_HitEffectfrom dropdown - Death Effect → Select
NS_DeathExplosionfrom dropdown - Death Particle Count →
500
- Hit Effect → Select
- Compile and Save
Configure Spawner to use BP_Enemy:
- Rebuild the project (the C++ code was updated to add Enemy Class property)
- Find
STGEnemySpawnerin your level (World Outliner) - Select it → Look at Details panel
- Under Spawning section, find Enemy Class
- Click the dropdown → Select
BP_Enemy - Save level
Note: If you don't see "Enemy Class", rebuild the C++ project. The property was just added to STGEnemySpawner.
For Player:
- Open
BP_Player - In Class Defaults → VFX:
- Hit Effect →
NS_HitEffect
- Hit Effect →
Step 9.8: Fix HUD Visibility
The HUD won't display unless WBP_HUD is assigned to the HUD Manager.
Configure STGHUDManager in Level
- Select
STGHUDManagerin your level - In Details panel → UI section:
- HUD Widget Class → Select
WBP_HUD
- HUD Widget Class → Select
- Save level
Update WBP_HUD for Victory/Game Over
Add a result text block:
- Open
WBP_HUD - Add Text widget
- Name:
txt_Result - Position: Center of screen
- Font Size: 72+
- Set Visibility to Hidden (initially)
- Save
The code will show/hide this text and set appropriate color for Victory (green) or Game Over (red).
Step 9.9: Test All Features
- Press Play
- Verify:
- ✅ Camera is fixed, shows entire play area
- ✅ Different enemy types spawn as game progresses
- ✅ Player bullets small/dim, enemy bullets large/bright
- ✅ Hit effects appear when enemies are damaged
- ✅ Death explosions are visually impressive
- ✅ HUD shows Score, Lives, Timer
- ✅ Press I to toggle invincibility
- ✅ Victory/Game Over text appears at end
Summary
Added:
- ✅ Invincibility cheat (I key)
- ✅ Fixed camera showing entire play area (auto-fits to play bounds)
- ✅ Centralized game settings (
STGGameSettings.h) - ✅ 4 enemy types with different behaviors
- ✅ Distinct bullet visuals (size/brightness)
- ✅ 60-second game duration
- ✅ Niagara particle effects (GPU-intensive)
- ✅ HUD configuration instructions
- ✅ Victory/Game Over display in HUD
← Previous: Part 8 (C++) - Create Game Mode | Back to Index | Next: Part 10 (C++) - Final Setup →