praca_magisterska/games/unreal/tutorial/part-9-cpp-polish.md

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

  1. Content Browser → Right-click → Input → Input Action
  2. Name: IA_CheatInvincible
  3. Save

Add to Input Mapping Context

  1. Open IMC_Player
  2. Click + to add new mapping
  3. Select IA_CheatInvincible
  4. Key: Click dropdown → Select I key
  5. Save

Configure BP_Player

  1. Open BP_Player
  2. In Class DefaultsInput section:
    • Cheat Invincible Action → Select IA_CheatInvincible
  3. 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 area
  • PlayAreaMargin - 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

  1. Open your game level in the editor
  2. Open the Place Actors panel:
    • Menu: Window → Place Actors
  3. In the Place Actors panel, click the Search field
  4. Type STGFixedCamera
  5. Drag the STGFixedCamera class from the panel into your level viewport
  6. 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 CameraHeight instead

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
1 100 2 0.35s
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

  1. Open Source/BulletHellCPP/STGGameSettings.h
  2. Find the value you want to change
  3. 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.0f
  • STG::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

  1. Content Browser → Right-click → FX → Niagara System
  2. Select "New system from selected emitter(s)"
  3. Search and add "Fountain" emitter as base
  4. Create two systems:
    • NS_HitEffect - Small burst (50-100 particles)
    • NS_DeathExplosion - Large explosion (500+ particles)

Configure Hit Effect

  1. Open NS_HitEffect (double-click in Content Browser)
  2. You'll see the System Overview panel in the center with the emitter graph
  3. Click on the Fountain emitter (right panel) to select it

Emitter Update Section:

  1. Find Emitter State → Click on it
  2. Change Life Cycle Mode from Self to System
  3. 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:

  1. Keep the existing Spawn Rate module in Emitter Update (don't delete it)
  2. Click on Spawn Rate to select it
  3. If you see a warning "The module has unmet dependencies":
    • Click "Fix issue" to move SpawnRate after EmitterState (required order)
  4. In the Selection panel (right side), set:
    • Spawn Rate = 500 (high value to spawn many particles quickly)
  5. 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:

  1. Click Initialize Particle module

  2. Find Lifetime → Set Lifetime Min = 0.3, Lifetime Max = 0.5

  3. Find Sprite Size → Set Sprite Size Min = 3, Sprite Size Max = 8

  4. Click Add Velocity (or Add Velocity in Cone) module

  5. Set Velocity Strength Min = 200, Velocity Strength Max = 400

Particle Update Section:

  1. Click Scale Color module (in Particle Update)
  2. 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
  3. 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:

  1. Ensure Sprite Renderer is enabled (checked)

  2. Click Compile (top toolbar) → Then Save

Configure Death Explosion

  1. Open NS_DeathExplosion
  2. Click the Fountain emitter to select it

Emitter Update:

  1. Click on Spawn Rate module
  2. If you see a dependency warning, click "Fix issue"
  3. Set Spawn Rate = 1000 (high value for big explosion)
  4. Click Emitter State:
    • Change Life Cycle Mode to System
    • IMPORTANT: Set Loop Behavior to Once (prevents particles staying forever)

Particle Spawn:

  1. In Initialize Particle:

    • Lifetime Min = 0.5, Lifetime Max = 1.0
    • Sprite Size Min = 5, Sprite Size Max = 15
  2. In Shape Location → Set Shape Primitive = Sphere

  3. In Add Velocity → Set Velocity Strength Min = 500, Max = 800

Particle Update:

  1. Click + next to Particle Update → Search and add Drag

  2. Set Drag = 2.0 (particles slow down naturally)

  3. 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
  4. Compile and Save

Assign in Blueprints

Create BP_Enemy:

  1. Content Browser → Right-click → Blueprint Class
  2. In the popup, expand All Classes and search for STGEnemy
  3. Select STGEnemy as the parent class → Click Select
  4. Name it BP_Enemy
  5. Open BP_Enemy (double-click)
  6. Click Class Defaults (top toolbar)
  7. In the Details panel, search for vfx
  8. Under VFX section:
    • Hit Effect → Select NS_HitEffect from dropdown
    • Death Effect → Select NS_DeathExplosion from dropdown
    • Death Particle Count500
  9. Compile and Save

Configure Spawner to use BP_Enemy:

  1. Rebuild the project (the C++ code was updated to add Enemy Class property)
  2. Find STGEnemySpawner in your level (World Outliner)
  3. Select it → Look at Details panel
  4. Under Spawning section, find Enemy Class
  5. Click the dropdown → Select BP_Enemy
  6. Save level

Note: If you don't see "Enemy Class", rebuild the C++ project. The property was just added to STGEnemySpawner.

For Player:

  1. Open BP_Player
  2. In Class Defaults → VFX:
    • Hit EffectNS_HitEffect

Step 9.8: Fix HUD Visibility

The HUD won't display unless WBP_HUD is assigned to the HUD Manager.

Configure STGHUDManager in Level

  1. Select STGHUDManager in your level
  2. In Details panel → UI section:
    • HUD Widget Class → Select WBP_HUD
  3. Save level

Update WBP_HUD for Victory/Game Over

Add a result text block:

  1. Open WBP_HUD
  2. Add Text widget
  3. Name: txt_Result
  4. Position: Center of screen
  5. Font Size: 72+
  6. Set Visibility to Hidden (initially)
  7. 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

  1. Press Play
  2. 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 →