praca_magisterska/games/unreal/tutorial/part-4-create-enemy.md

466 lines
18 KiB
Markdown

# Part 4: Create the Enemy
[← Previous: Part 3 - Create the Bullet](part-3-create-bullet.md) | [Back to Index](README.md) | [Next: Part 5 - Create Enemy Spawner →](part-5-create-spawner.md)
---
## Step 4.1: Create Enemy Blueprint
1. Content Browser → Blueprints
2. Right-click → **Blueprint Class****Actor**
3. Name: `BP_Enemy`
4. Double-click to open
5. **Add Components:**
- Paper Sprite → `EnemySprite`
- Box Collision → `EnemyCollision`
- Box Extent: `X=30, Y=30, Z=10`
- Generate Overlap Events: **CHECKED**
- Cube (Static Mesh) → name `TempVisual`
- Scale: `(0.6, 0.6, 0.1)` - larger than player cube
- This provides visibility until proper visuals in [Part 9](part-9-final-setup.md)
6. **Create Variables:**
| Variable Name | Type | Default Value |
| --------------------- | ------------------------ | ------------- |
| `MaxHealth` | Integer | 12 |
| `CurrentHealth` | Integer | 12 |
| `ScoreValue` | Integer | 50 |
| `VerticalSpeed` | Float | 220.0 |
| `HorizontalAmplitude` | Float | 250.0 |
| `HorizontalFrequency` | Float | 1.8 |
| `DespawnY` | Float | -750.0 |
| `FireInterval` | Float | 0.35 |
| `BulletsPerBurst` | Integer | 20 |
| `BurstSpread` | Float | 360.0 |
| `EnemyBulletSpeed` | Float | 1000.0 |
| `EnemyBulletLifetime` | Float | 6.0 |
| `BaseX` | Float | 0.0 |
| `WaveSeed` | Float | 0.0 |
| `FireTimer` | Float | 0.0 |
| `BulletClass` | Class Reference to Actor | (set later) |
### Expected Result after Compile
- Compile button shows GREEN checkmark
- Components panel shows: DefaultSceneRoot → EnemySprite, EnemyCollision, TempVisual
- Variables panel shows all 16 variables with correct types and defaults
### Expected Result in Viewport (Blueprint Editor)
- Cube visible (the TempVisual placeholder, larger than player)
- Box collision visible (30x30x10)
---
## Step 4.2: Enemy Initialization
1. In Event Graph, from **"Event BeginPlay":**
### a) Set CurrentHealth = MaxHealth
### b) Get Actor Location → Break Vector → Set BaseX = X value
### c) Random Float in Range (0, 6.28) → Set WaveSeed
(6.28 ≈ 2π for wave randomization)
#### d) Random Float in Range (0, FireInterval) → Set FireTimer
### Expected Result after Compile
- Compile button shows GREEN checkmark
- BeginPlay event connected to variable setters
### Expected Result in Play mode
- Each enemy spawns with randomized WaveSeed (0 to 6.28)
- Each enemy starts with different FireTimer offset
- This creates varied, non-synchronized enemy behavior
---
## Step 4.3: Enemy Movement Logic
1. In Event Graph, from **"Event Tick":**
### a) VERTICAL MOVEMENT
- Get Actor Location → Break into X, Y, Z
- Subtract (VerticalSpeed \* DeltaSeconds) from Y
### b) HORIZONTAL SINE WAVE
- Get Game Time in Seconds
- Add WaveSeed
- Multiply by HorizontalFrequency
- Calculate Sine of result
- Multiply by HorizontalAmplitude
- Add to BaseX
- This becomes new X position
#### c) Set Actor Location with new X, Y (Z stays 0)
#### d) DESPAWN CHECK
- If Y < DespawnY: Destroy Actor
- If Abs(X) > 1400: Destroy Actor
**Visual Diagram:**
```
┌─────────────┐
│ Event Tick │
└──────┬──────┘
┌─────────────────────────────────────────────┐
│ Get Location │
│ NewY = Y - (VerticalSpeed * DeltaSeconds) │
│ NewX = BaseX + Sin(Time * Freq) * Amplitude │
│ Set Location (NewX, NewY, 0) │
└──────────────────────────────────────────────┘
```
### Expected Result after Compile
- Compile button shows GREEN checkmark
- Event Tick connected to movement and despawn logic
### Expected Result in Play mode
- Enemies drift downward at VerticalSpeed (220 units/sec)
- Enemies oscillate horizontally in sine wave pattern
- Each enemy has different horizontal phase (due to WaveSeed)
- Enemies disappear when Y < -750 or |X| > 1400
---
## Step 4.4: Enemy Firing Logic
### 1. Continue in Event Tick (after movement)
#### a) Decrease FireTimer by DeltaSeconds
#### b) Branch: if FireTimer <= 0
- Reset FireTimer to FireInterval
- Call "FireBurst" function
### 2. CREATE "FireBurst" FUNCTION
#### a) Add function "FireBurst"
#### b) Inside
- Get BulletsPerBurst
- Calculate angle step: `360 / BulletsPerBurst` (for full circle)
- OR: `BurstSpread / (BulletsPerBurst - 1)` (for partial arc)
#### c) For Loop from 0 to BulletsPerBurst - 1
- Calculate angle: `i * AngleStep`
- Convert to direction vector:
- X = Sin(angle in radians)
- Y = -Cos(angle in radians) ← negative because enemies fire DOWN
- Spawn bullet:
- Spawn Actor from Class (BP_Bullet)
- Get spawned bullet, call Initialize:
- Direction = calculated direction
- Speed = EnemyBulletSpeed
- bIsEnemy = **true**
- Lifetime = EnemyBulletLifetime
**Visual: Radial bullet pattern (20 bullets in 360°)**
```
↗ | ↖
↗ | ↖
→───────●───────←
↘ | ↙
↘ | ↙
```
### Expected Result after Compile
- Compile button shows GREEN checkmark
- "FireBurst" function appears under Functions
### Expected Result in Play mode
- Every 0.35 seconds (FireInterval), enemy fires bullet burst
- 20 bullets spawn in a full 360° circle pattern
- Bullets travel outward from enemy position
- Different enemies fire at different times (randomized FireTimer)
---
## Step 4.5: Enemy Damage and Death
### 1. CREATE "ApplyDamage" FUNCTION
#### a) Add input: `DamageAmount` (Integer)
#### b) Inside
- Subtract DamageAmount from CurrentHealth
- If CurrentHealth <= 0:
- Call HandleDeath
### 2. CREATE "HandleDeath" FUNCTION
#### a) Inside
- Get reference to ScoreManager (we'll create in [Part 7](part-7-score-manager-ui.md))
- Call AddScore, passing ScoreValue
- Spawn death effect (optional)
- Destroy Actor
### 3. COLLISION WITH PLAYER
#### a) On the EnemyCollision component overlap event
- Cast Other Actor to BP_Player
- If successful:
- Call TakeHit(1) on player
- Call HandleDeath() on self
### Expected Result after Compile
- Compile button shows GREEN checkmark
- "ApplyDamage" and "HandleDeath" functions appear under Functions
- EnemyCollision has overlap event in Event Graph
### Expected Result in Play mode
- Player bullets hitting enemy: Enemy health decreases
- After 12 hits (MaxHealth): Enemy disappears, score increases by 50
- Player colliding with enemy: Player takes 1 damage, enemy dies
---
## Step 4.6: Complete Special Ability in BP_Player
Now that BP_Enemy exists (and BP_Bullet from Part 3), we can complete the special ability that was set up as a placeholder in [Part 2, Step 2.6](part-2-create-player.md#step-26-create-player-damage-and-special-ability).
### 1. Open BP_Player Blueprint
1. Content Browser → Blueprints → double-click `BP_Player`
2. Go to **Event Graph** tab
3. Find the `EnhancedInputAction IA_Special` event node (created in Step 2.6)
4. Locate the `Print String "SPECIAL ABILITY ACTIVATED!"` node
### 2. Replace Print String with destruction logic
#### a) Delete the placeholder
- Select the `Print String` node
- Press Delete
- (Keep the TODO comment if you want, or delete it too)
#### b) Destroy all enemies
1. From `Set SpecialUsed` output execution pin, drag → search `Get All Actors of Class` → add it
2. Click the "Actor Class" dropdown → search and select `BP_Enemy`
3. The output "Out Actors" is an array of all enemies currently in the level
#### c) Loop through enemies and destroy them
1. From `Get All Actors of Class`, drag execution → search `For Each Loop` → add it
2. Connect the "Out Actors" array (blue pin) to the loop's "Array" input (blue pin)
3. From "Loop Body" execution pin, drag → search `Destroy Actor` → add it
4. Connect "Array Element" (blue pin - the current enemy in the loop) to Destroy Actor's "Target" input
#### d) Now destroy enemy bullets (after enemies are done)
1. From `For Each Loop`'s **"Completed"** execution pin (NOT "Loop Body"), drag → search `Get All Actors of Class` → add it
2. Click "Actor Class" dropdown → select `BP_Bullet`
3. From this Get All Actors, drag execution → search `For Each Loop` → add another loop
#### e) Filter to only destroy ENEMY bullets (keep player bullets)
1. From the second loop's "Loop Body" pin, drag → search `Branch` → add it
2. From "Array Element" (the current bullet), drag → search `Get IsEnemyProjectile` → add it
- This reads the IsEnemyProjectile variable from BP_Bullet
3. Connect `IsEnemyProjectile` output (boolean) to Branch's "Condition" input
#### f) Destroy only if it's an enemy bullet
1. From Branch's **"True"** pin, drag → search `Destroy Actor` → add it
2. Connect "Array Element" (the bullet) to Destroy Actor's "Target"
3. Leave Branch's "False" pin unconnected (player bullets are preserved)
### 3. Visual diagram of completed special ability
```
┌─────────────────────────────┐
│ EnhancedInputAction │
│ IA_Special - Triggered │
└───────────┬─────────────────┘
┌─────────────────────────────┐
│ Branch │
│ Condition: NOT SpecialUsed │
└───────┬─────────────┬───────┘
│ TRUE │ FALSE
▼ ▼
┌───────────────┐ (nothing - ability already used)
│Set SpecialUsed│
│ = true │
└───────┬───────┘
┌────────────────────────────┐
│ Get All Actors of Class │
│ Actor Class: BP_Enemy │
│ Out Actors ○───────────────┼──────────┐
└───────────┬────────────────┘ │
│ │
▼ ▼
┌────────────────────────────┐ ┌─────────────┐
│ For Each Loop │──►│Destroy Actor│
│ Array ○──────────────────┼───│Target: Enemy│
│ │ └─────────────┘
│ Loop Body ───────────────┼───────────┘
│ Completed ───────────────┼───┐
└────────────────────────────┘ │
┌────────────────────┘
┌────────────────────────────┐
│ Get All Actors of Class │
│ Actor Class: BP_Bullet │
│ Out Actors ○───────────────┼──────────┐
└───────────┬────────────────┘ │
│ │
▼ ▼
┌────────────────────────────┐ ┌─────────────────────────────────┐
│ For Each Loop │──►│ Get IsEnemyProjectile │
│ Array ○──────────────────┼───│ (from Array Element) │
│ │ └───────────────┬─────────────────┘
│ Loop Body ───────────────┼───────────────────┘
└────────────────────────────┘ │
┌─────────────────────────────┐
│ Branch │
│ Condition: IsEnemyProjectile│
└───────┬─────────────┬───────┘
│ TRUE │ FALSE
▼ ▼
┌───────────────┐ (skip - player bullet)
│ Destroy Actor │
│ Target: Bullet│
└───────────────┘
```
### 4. Compile and Save
### Expected Result after Compile
- Compile button shows GREEN checkmark
- No warnings about missing classes (BP_Enemy and BP_Bullet now exist)
### Expected Result in Play mode
- Press X (or Right Mouse Button) once:
- ALL enemies on screen instantly disappear
- ALL enemy bullets (red) instantly disappear
- Player bullets (yellow) remain unaffected
- "SPECIAL ABILITY ACTIVATED!" no longer prints (we deleted it)
- Press X again: Nothing happens (SpecialUsed = true, one use only)
---
## Step 4.7: Complete Bullet Collision Logic (BP_Bullet)
Now that BP_Enemy exists (and the `ApplyDamage` function from Step 4.3), we can complete the collision logic that was set up as a placeholder in [Part 3, Step 3.3](part-3-create-bullet.md#step-33-bullet-collision-logic).
### 1. Open BP_Bullet Blueprint
1. Content Browser → Blueprints → double-click `BP_Bullet`
2. Go to **Event Graph** tab
3. Find the `On Component Begin Overlap (BulletCollision)` event node
4. Locate the `Print String "TODO: Damage enemy"` node on the FALSE branch
### 2. Replace Print String with enemy damage logic
#### a) Delete the placeholder
- Select the `Print String` node
- Press Delete
#### b) Add Cast to BP_Enemy
1. Right-click → search `Cast to BP_Enemy` → add it
2. Connect execution wire:
- From Branch **FALSE** pin → `Cast to BP_Enemy`
3. Connect the "Other Actor" to the cast:
- From the **"On Component Begin Overlap"** node, drag from **"Other Actor"** to the Cast's "Object" input
- (You can Ctrl+drag to create a second wire without removing the existing one to BP_Player)
#### c) Call ApplyDamage on the enemy
4. From "Cast Succeeded" on the BP_Enemy cast:
- From the cast's **"As BP Enemy"** output pin, drag → search `ApplyDamage`
- This calls the ApplyDamage function you created in Step 4.3
5. Connect the Damage parameter:
- Right-click → `Get Damage` (the bullet's damage variable)
- Connect to ApplyDamage's "DamageAmount" input
#### d) Destroy the bullet after damaging
6. From ApplyDamage, drag execution → `Destroy Actor`
- Leave "Target" as "Self" (destroys this bullet)
**Visual:**
```
FALSE
┌──────────────────────┐
Other Actor ──────────►│ Cast to BP_Enemy │
└──────────┬───────────┘
Cast Succeeded
┌──────────────────────┐
│ ApplyDamage │
Get Damage ───────────►│ DamageAmount │
└──────────┬───────────┘
┌──────────────────────┐
│ Destroy Actor │
│ (Self) │
└──────────────────────┘
```
### 3. Compile and Save
### Expected Result after Compile
- Compile button shows GREEN checkmark
- No warnings - both BP_Player and BP_Enemy casts are valid now
### Expected Result in Play mode
- Player bullets (IsEnemyProjectile=false) hitting enemies:
- Enemy takes damage, bullet disappears
- After enough hits, enemy dies and awards score
- Enemy bullets (IsEnemyProjectile=true) hitting player:
- Player takes hit, bullet disappears
- Bullets passing through other objects: No effect (bullets ignore non-targets)
---
[← Previous: Part 3 - Create the Bullet](part-3-create-bullet.md) | [Back to Index](README.md) | [Next: Part 5 - Create Enemy Spawner →](part-5-create-spawner.md)