mirror of
https://github.com/kuhyx/praca_magisterska.git
synced 2026-07-04 15:23:10 +02:00
588 lines
26 KiB
Markdown
588 lines
26 KiB
Markdown
# Part 3: Create the Bullet
|
|
|
|
[← Previous: Part 2 - Create the Player](part-2-create-player.md) | [Back to Index](README.md) | [Next: Part 4 - Create the Enemy →](part-4-create-enemy.md)
|
|
|
|
---
|
|
|
|
## Step 3.1: Create Bullet Blueprint
|
|
|
|
1. In Content Browser → Blueprints folder
|
|
2. Right-click → **Blueprint Class** → **Actor**
|
|
3. Name it: `BP_Bullet`
|
|
4. Double-click to open
|
|
|
|
5. **Add Components:**
|
|
- Paper Sprite → name `BulletSprite`
|
|
- Sphere Collision → name `BulletCollision`
|
|
- Radius: `8`
|
|
- Generate Overlap Events: **CHECKED**
|
|
- Collision Preset: Custom → Query Only
|
|
- Cube (Static Mesh) → name `TempVisual`
|
|
- Scale: `(0.1, 0.1, 0.05)` - small bullet-sized cube
|
|
- This provides visibility until proper visuals in [Part 9](part-9-final-setup.md)
|
|
|
|
6. **Create Variables:**
|
|
|
|
| Variable Name | Type | Default Value |
|
|
|---------------|------|---------------|
|
|
| `TravelDirection` | Vector | (0, 1, 0) |
|
|
| `TravelSpeed` | Float | 1200.0 |
|
|
| `RemainingLifetime` | Float | 4.0 |
|
|
| `IsEnemyProjectile` | Boolean | false |
|
|
| `Damage` | Integer | 1 |
|
|
|
|
### Expected Result after Compile:
|
|
- Compile button shows GREEN checkmark
|
|
- Components panel shows: DefaultSceneRoot → BulletSprite, BulletCollision, TempVisual
|
|
- Variables panel shows all 5 variables with correct types
|
|
|
|
### Expected Result in Viewport (Blueprint Editor):
|
|
- Small cube visible (the TempVisual placeholder)
|
|
- Sphere collision visible (radius 8)
|
|
|
|
---
|
|
|
|
## Step 3.2: Bullet Movement Logic
|
|
|
|
1. In Event Graph, from **Event Tick:**
|
|
|
|
#### a) Calculate movement:
|
|
|
|
1. Right-click → `Get TravelDirection`
|
|
2. Right-click → `Get TravelSpeed`
|
|
3. Right-click → search `Multiply (Vector * Float)` → add it
|
|
- Connect TravelDirection to the Vector input
|
|
- Connect TravelSpeed to the Float input
|
|
- Result: a vector representing full speed in travel direction
|
|
|
|
4. Right-click → `Get World Delta Seconds`
|
|
5. Right-click → search `Multiply (Vector * Float)` → add another one
|
|
- Connect the RESULT from step 3 to the Vector input
|
|
- Connect World Delta Seconds to the Float input
|
|
- Result: movement delta for this frame (frame-rate independent)
|
|
|
|
6. Right-click → `Get Actor Location`
|
|
7. Right-click → search `Add (Vector + Vector)` → add it
|
|
- Connect Actor Location to first input
|
|
- Connect the movement delta (from step 5) to second input
|
|
|
|
8. Right-click → `Set Actor Location`
|
|
- Connect the Add result to "New Location"
|
|
- Connect execution wire from Event Tick to Set Actor Location
|
|
|
|
#### b) Check lifetime and destroy when expired:
|
|
|
|
9. Right-click → `Get RemainingLifetime`
|
|
|
|
10. Right-click → `Get World Delta Seconds`
|
|
|
|
11. Right-click → search `Subtract (Float)` → add it
|
|
- Connect RemainingLifetime to the TOP input (A)
|
|
- Connect World Delta Seconds to the BOTTOM input (B)
|
|
- Result: RemainingLifetime minus DeltaSeconds
|
|
|
|
12. Right-click → `Set RemainingLifetime`
|
|
- Connect the Subtract result to it
|
|
- This ALWAYS stores the new decreased lifetime value
|
|
|
|
13. Connect execution wire:
|
|
- From `Set Actor Location` (from step 8) → `Set RemainingLifetime`
|
|
|
|
14. Right-click → search `<= (Float)` (less than or equal) → add it
|
|
- Connect RemainingLifetime (from Set node output, or Get again) to TOP input
|
|
- Type `0` in BOTTOM input
|
|
- Result: true if lifetime has expired
|
|
|
|
15. From `Set RemainingLifetime`, drag execution → `Branch`
|
|
- Connect the `<=` result to Branch's "Condition" input
|
|
|
|
16. **On TRUE (lifetime expired):**
|
|
- From Branch's "True" pin, drag → `Destroy Actor`
|
|
- Target: leave as "Self" (destroys this bullet)
|
|
|
|
17. **On FALSE (still alive):**
|
|
- Leave unconnected (bullet continues to exist, will check again next frame)
|
|
|
|
**Visual:**
|
|
|
|
```
|
|
Event Tick ──► Set Actor Location ──► Set RemainingLifetime ──► Branch
|
|
(movement) = Remaining - Delta (Remaining <= 0?)
|
|
│
|
|
TRUE ──────┴────── FALSE
|
|
│ │
|
|
▼ ▼
|
|
Destroy Actor (nothing)
|
|
```
|
|
|
|
### 2. CREATE "Initialize" FUNCTION:
|
|
|
|
#### a) Add input parameters:
|
|
| Parameter | Type | Default |
|
|
|-----------|------|---------|
|
|
| `Direction` | Vector | - |
|
|
| `Speed` | Float | - |
|
|
| `bIsEnemy` | Boolean | - |
|
|
| `Lifetime` | Float | - |
|
|
| `DamageValue` | Integer | 1 |
|
|
|
|
#### b) Inside:
|
|
- Normalize Direction → Set TravelDirection
|
|
- Set TravelSpeed = Speed
|
|
- Set IsEnemyProjectile = bIsEnemy
|
|
- Set RemainingLifetime = Lifetime
|
|
- Set Damage = DamageValue
|
|
|
|
### 3. Compile and Save
|
|
|
|
### Expected Result after Compile:
|
|
- Compile button shows GREEN checkmark
|
|
- "Initialize" function appears under Functions with 5 input parameters
|
|
|
|
> **NOTE:** Bullet testing is possible after completing [Step 3.4](#step-34-complete-player-firing-logic-bp_player).
|
|
|
|
---
|
|
|
|
## Step 3.3: Bullet Collision Logic
|
|
|
|
### 1. ADD THE OVERLAP EVENT:
|
|
|
|
1. In the Components panel (top-left), click on **"BulletCollision"** to select it
|
|
|
|
2. In the Details panel (right side), scroll down to find the **"Events"** section
|
|
- Look for "On Component Begin Overlap"
|
|
- Click the green **"+"** button next to it
|
|
- This creates an event node in the Event Graph
|
|
|
|
3. The Event Graph now shows a red node: **"On Component Begin Overlap (BulletCollision)"**
|
|
- This fires whenever another actor overlaps with the bullet's collision sphere
|
|
|
|
### 2. CHECK IF THIS IS AN ENEMY PROJECTILE:
|
|
|
|
4. Right-click → `Get IsEnemyProjectile`
|
|
- This gets your boolean variable
|
|
|
|
5. From "On Component Begin Overlap", drag execution → `Branch`
|
|
- Connect IsEnemyProjectile to Branch's "Condition" input
|
|
- TRUE = this is an enemy bullet (should damage player)
|
|
- FALSE = this is a player bullet (should damage enemies)
|
|
|
|
### 3. TRUE BRANCH - Enemy Bullet Hits Player:
|
|
|
|
6. From the **"On Component Begin Overlap"** node, look for the **"Other Actor"** output pin
|
|
- This is the actor that overlapped with the bullet
|
|
- Drag from "Other Actor" → search `Cast to BP_Player`
|
|
|
|
7. Connect execution wire:
|
|
- From Branch **TRUE** pin → `Cast to BP_Player`
|
|
|
|
8. The cast has two execution outputs:
|
|
- **"Cast Succeeded"** (top) - the other actor IS a player
|
|
- **"Cast Failed"** (bottom) - the other actor is NOT a player
|
|
|
|
9. From "Cast Succeeded", we need to damage the player:
|
|
- From the cast's **"As BP Player"** output pin, drag → search `TakeHit`
|
|
- This calls the TakeHit function you created in [Part 2](part-2-create-player.md)
|
|
- **IMPORTANT:** The "Target" pin on TakeHit should now be connected to "As BP Player" (this happened automatically when you dragged from that pin)
|
|
- If Target shows "self", you must manually connect "As BP Player" to the "Target" pin - TakeHit must be called ON the player, not on the bullet!
|
|
|
|
10. Connect the Damage parameter:
|
|
- Right-click → `Get Damage` (your bullet's damage variable)
|
|
- Connect to TakeHit's "DamageAmount" input
|
|
|
|
11. After damaging the player, destroy the bullet:
|
|
- From TakeHit, drag execution → `Destroy Actor`
|
|
- Leave "Target" as "Self" (destroys this bullet)
|
|
|
|
12. Connect execution wire:
|
|
- Cast to BP_Player → TakeHit → Destroy Actor
|
|
|
|
### 4. FALSE BRANCH - Player Bullet Hits Enemy (PLACEHOLDER):
|
|
|
|
> **NOTE:** BP_Enemy doesn't exist yet, so we'll add a placeholder. You'll complete this logic in [Part 4, Step 4.7](part-4-create-enemy.md#step-47-complete-bullet-collision-logic-bp_bullet).
|
|
|
|
13. From Branch **FALSE** pin, drag execution → `Print String`
|
|
- In the "In String" field, type: `TODO: Damage enemy`
|
|
- This is temporary - we'll replace it with real enemy damage logic in Part 4
|
|
|
|
**Visual:**
|
|
|
|
```
|
|
┌──────────────────────────────────────┐
|
|
│ On Component Begin Overlap │
|
|
│ (BulletCollision) │
|
|
│ Other Actor ○─────────────────────┐
|
|
└──────────────┬───────────────────────┘ │
|
|
│ │
|
|
▼ ▼
|
|
┌─────────────────┐ ┌──────────────────┐
|
|
│ Branch │ │ Cast to BP_Player│
|
|
│ IsEnemyProjectile └────────┬─────────┘
|
|
└───────┬───┬─────┘ │
|
|
│ │ Cast Succeeded
|
|
TRUE ─┘ └─ FALSE │
|
|
│ │ ▼
|
|
▼ │ ┌──────────────────┐
|
|
Cast to BP_Player │ │ TakeHit │
|
|
(see above) │ │ Damage: Damage │
|
|
│ └────────┬─────────┘
|
|
▼ │
|
|
┌──────────────────┐ ▼
|
|
│ Print String │ ┌──────────────────┐
|
|
│ "TODO: Damage │ │ Destroy Actor │
|
|
│ enemy" │ │ (Self) │
|
|
└──────────────────┘ └──────────────────┘
|
|
```
|
|
|
|
### 4. Compile and Save
|
|
|
|
### Expected Result after Compile:
|
|
- Compile button shows GREEN checkmark
|
|
- Event Graph shows "On Component Begin Overlap" event connected to Branch
|
|
|
|
> **NOTE:** Collision testing requires player firing (Step 3.4) and enemies (Part 4). Full collision behavior is testable after completing [Part 4](part-4-create-enemy.md).
|
|
|
|
---
|
|
|
|
## Step 3.4: Complete Player Firing Logic (BP_Player)
|
|
|
|
Now that BP_Bullet exists, we can complete the player's firing functions.
|
|
|
|
### 1. Open BP_Player Blueprint:
|
|
- In Content Drawer, navigate to Content → Blueprints
|
|
- Double-click "BP_Player" to open the Blueprint Editor
|
|
|
|
### 2. SET THE BULLET CLASS VARIABLE:
|
|
|
|
1. In My Blueprint panel, find the `BulletClass` variable
|
|
2. Click on it to select it
|
|
3. In Details panel, find "Default Value"
|
|
4. Click the dropdown and select `BP_Bullet`
|
|
5. Compile to save the change
|
|
|
|
### 3. CREATE SPAWN BULLET FUNCTION:
|
|
|
|
#### a) In "My Blueprint" panel, under "Functions", click "+"
|
|
#### b) Name the function `SpawnBullet`
|
|
#### c) Double-click to open function graph
|
|
|
|
#### d) Add input parameters to the function:
|
|
- In the function graph, look at the purple "SpawnBullet" entry node
|
|
- In Details panel (right side), find "Inputs" section
|
|
- Click "+" to add a new input parameter
|
|
|
|
| Parameter | Type |
|
|
|-----------|------|
|
|
| `SpawnLocation` | Vector |
|
|
| `Direction` | Vector |
|
|
|
|
The entry node should now show two input pins: SpawnLocation and Direction
|
|
|
|
#### e) Build the spawning logic:
|
|
|
|
1. Right-click → search `Spawn Actor from Class` → add it
|
|
|
|
2. For the "Class" input:
|
|
- Right-click → `Get BulletClass` (your variable)
|
|
- Connect BulletClass output (blue pin) to SpawnActor's "Class" input (purple pin)
|
|
|
|
3. For the "Spawn Transform Location" input:
|
|
- On the SpawnActor node, look for "Spawn Transform Location" (orange pin)
|
|
- If you only see "Spawn Transform", right-click on it → "Split Struct Pin" to expand it
|
|
- Drag a wire from the **SpawnLocation** parameter (on the SpawnBullet entry node) to **"Spawn Transform Location"**
|
|
- Leave Rotation and Scale at defaults (0,0,0 and 1,1,1)
|
|
|
|
4. Connect execution wire:
|
|
- Drag from SpawnBullet entry node (white triangle) → SpawnActor (white triangle)
|
|
|
|
#### f) Initialize the spawned bullet:
|
|
|
|
5. Add the Cast node:
|
|
- From SpawnActor's **"Return Value"** output (blue pin on right side), drag → search `Cast to BP_Bullet`
|
|
- Connect "Return Value" to the Cast's "Object" input
|
|
|
|
6. Connect execution wire:
|
|
- From SpawnActor (white triangle output) → Cast to BP_Bullet (white triangle input)
|
|
|
|
7. Add the Initialize call:
|
|
- From the Cast's **"As BP Bullet"** output (blue pin), drag → search `Initialize`
|
|
- This calls the Initialize function you created in Step 3.2
|
|
- **IMPORTANT:** The "Target" pin should automatically connect to "As BP Bullet"
|
|
|
|
8. Connect Initialize parameters:
|
|
- **Direction**: Drag from the **Direction** parameter (on SpawnBullet entry node, yellow pin) → Initialize's "Direction" input
|
|
- **Speed**: Right-click → `Get BulletSpeed` → connect to Initialize's "Speed" input
|
|
- **bIsEnemy**: Leave unchecked (false) - player bullets aren't enemy projectiles
|
|
- **Lifetime**: Type `4.0` in the input field (or leave default)
|
|
- **DamageValue**: Leave at default `1`
|
|
|
|
9. Connect execution wire:
|
|
- From Cast to BP_Bullet → Initialize
|
|
|
|
**Visual:**
|
|
|
|
```
|
|
┌───────────────────────┐ ┌─────────────────────────────────┐
|
|
│ SpawnBullet │─────►│ Spawn Actor from Class │
|
|
│ SpawnLocation ○───────┼─────►│ Class: BulletClass │
|
|
│ Direction ○ │ │ Spawn Transform Location ○◄───┘
|
|
└───────────────────────┘ │ Return Value ○────────────────┐
|
|
└─────────────────────────────────┘
|
|
│
|
|
┌─────────────────────┘
|
|
▼
|
|
┌─────────────────────────┐
|
|
│ Cast to BP_Bullet │
|
|
│ Object ○◄─────────────┘
|
|
│ As BP Bullet ○────────┐
|
|
└─────────────────────────┘
|
|
│
|
|
┌─────────────┘
|
|
▼
|
|
┌─────────────────────────┐
|
|
│ Initialize │
|
|
│ Target ○◄─────────────┘
|
|
│ Direction ○◄──────────── (from entry node)
|
|
│ Speed ○◄────────────── BulletSpeed
|
|
│ bIsEnemy: false │
|
|
│ Lifetime: 4.0 │
|
|
└─────────────────────────┘
|
|
```
|
|
|
|
#### g) Compile (should have no errors now)
|
|
|
|
### 4. CREATE FIRE VOLLEY FUNCTION:
|
|
|
|
#### a) In "My Blueprint" panel, under "Functions", click "+"
|
|
#### b) Name the function `FireVolley`
|
|
#### c) Double-click to open function graph
|
|
|
|
#### d) Inside FireVolley function graph, build this logic step by step:
|
|
|
|
---
|
|
|
|
**STEP 1 - Get the volley size and check for single bullet case:**
|
|
|
|
1. You should see a purple "FireVolley" entry node on the left
|
|
- This is where execution starts when the function is called
|
|
|
|
2. Right-click → search `Get VolleySize` → add it
|
|
- This gets your variable value (default 3)
|
|
|
|
3. Right-click → search `Equal (Integer)` or `==` → add it
|
|
- Connect VolleySize output to the TOP input (A)
|
|
- Type `1` in the BOTTOM input (B)
|
|
- This checks: is VolleySize exactly 1?
|
|
|
|
4. From FireVolley entry node, drag execution → `Branch`
|
|
- Connect the == result to Branch's "Condition" input
|
|
- TRUE = single bullet, FALSE = multiple bullets in spread
|
|
|
|
---
|
|
|
|
**STEP 2 - TRUE branch: Fire single bullet straight up:**
|
|
|
|
5. From Branch TRUE pin, drag execution → right-click → search `SpawnBullet` (the function you created in step 3 above)
|
|
|
|
6. For SpawnBullet's "Spawn Location" input:
|
|
- Right-click → `Get Actor Location`
|
|
- Connect the output to Spawn Location
|
|
|
|
7. For SpawnBullet's "Direction" input (fire straight UP):
|
|
- Right-click → `Make Vector`
|
|
- Set X = 1 (up in top-down view)
|
|
- Set Y = 0
|
|
- Set Z = 0
|
|
- Connect to Direction input
|
|
|
|
8. After SpawnBullet, drag execution → `Return Node`
|
|
- This exits the function early (don't continue to the loop)
|
|
|
|
**Visual so far:**
|
|
|
|
```
|
|
┌─────────────┐ ┌────────────────────┐
|
|
│ FireVolley │─────►│ Branch │
|
|
│ (entry) │ │ VolleySize == 1 │
|
|
└─────────────┘ └─────────┬──────────┘
|
|
│ TRUE
|
|
▼
|
|
┌─────────────────────┐
|
|
│ SpawnBullet │
|
|
│ Location: ActorLoc │───► Return
|
|
│ Direction: (1,0,0) │
|
|
└─────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
**STEP 3 - FALSE branch: Fire multiple bullets in a spread pattern:**
|
|
|
|
9. From Branch FALSE pin, we need to loop through each bullet.
|
|
First, calculate the starting angle:
|
|
|
|
The spread is CENTERED on "straight up". For 3 bullets with 12° spread:
|
|
- Bullet 0: -12° (left of center)
|
|
- Bullet 1: 0° (center, straight up)
|
|
- Bullet 2: +12° (right of center)
|
|
|
|
**Formula:** `StartAngle = -(VolleySpread * (VolleySize - 1)) / 2`
|
|
|
|
10. **Calculate StartAngle:**
|
|
- Right-click → `Get VolleySize`
|
|
- Right-click → `Subtract (Integer)` → connect VolleySize, type `1`
|
|
- Result: (VolleySize - 1) = 2 for default
|
|
|
|
- Right-click → `Get VolleySpread`
|
|
- Right-click → `Multiply (float)` → connect VolleySpread and (VolleySize-1)
|
|
- NOTE: The integer will auto-convert to float
|
|
- Result: VolleySpread * (VolleySize - 1) = 12 * 2 = 24
|
|
|
|
- Right-click → `Divide (float)` → connect the multiply result, type `2`
|
|
- Result: 24 / 2 = 12
|
|
|
|
- Right-click → `Negate (float)` or "Multiply by -1"
|
|
- Result: -12 (this is StartAngle)
|
|
|
|
- Right-click → `Set` → create a LOCAL variable "StartAngle" (Float)
|
|
- OR just keep the wire connected (we'll use it in the loop)
|
|
|
|
11. **Set up the FOR loop:**
|
|
- From Branch FALSE pin, drag → right-click → search `For Loop`
|
|
- "First Index": type `0`
|
|
- "Last Index": connect (VolleySize - 1)
|
|
- You already calculated this in step 10, reuse it or calculate again:
|
|
- Get VolleySize → Subtract 1 → connect to Last Index
|
|
|
|
The loop will run with Index = 0, 1, 2 for VolleySize=3
|
|
|
|
12. **Inside the loop (from "Loop Body" execution pin):**
|
|
|
|
Calculate angle for THIS bullet:
|
|
- Right-click → `Multiply (float)`
|
|
- Connect loop "Index" to first input (auto-converts int to float)
|
|
- Connect VolleySpread to second input
|
|
- Result: Index * VolleySpread (0, 12, 24 for indices 0, 1, 2)
|
|
|
|
- Right-click → `Add (float)`
|
|
- Connect StartAngle (the -12 from step 10) to first input
|
|
- Connect (Index * VolleySpread) to second input
|
|
- Result: StartAngle + (Index * VolleySpread) = -12, 0, +12 degrees
|
|
|
|
This is the angle in DEGREES. Store or continue with this value.
|
|
|
|
13. **Convert angle from degrees to a direction vector:**
|
|
|
|
In Unreal's top-down view (looking down Z axis):
|
|
- X axis = up/down on screen (vertical)
|
|
- Y axis = left/right on screen (horizontal)
|
|
- Angle 0° = straight up = direction (1, 0, 0)
|
|
- Angle 90° = right = direction (0, 1, 0)
|
|
|
|
```
|
|
Direction.X = Cos(angle) // Cos for vertical (forward/up)
|
|
Direction.Y = Sin(angle) // Sin for horizontal offset
|
|
Direction.Z = 0
|
|
```
|
|
|
|
BUT Unreal's Sin/Cos use RADIANS, not degrees!
|
|
|
|
**a) Convert degrees to radians:**
|
|
- Right-click → search `Degrees To Radians` → add it
|
|
- Connect your angle (from step 12) to the input
|
|
- Output is angle in radians
|
|
|
|
**b) Calculate X component (Cos - forward/up direction):**
|
|
- Right-click → `Cos (Radians)` → add it
|
|
- Connect the Degrees To Radians output to Cos input
|
|
|
|
**c) Calculate Y component (Sin - horizontal offset):**
|
|
- Right-click → `Sin (Radians)` → add it
|
|
- To connect the SAME radians value to Sin (without losing the Cos connection):
|
|
- **Option 1:** Ctrl+drag from "Degrees To Radians" output to Sin input (creates second wire)
|
|
- **Option 2:** Drag directly from "Degrees To Radians" output again - UE5 allows multiple wires from one output pin
|
|
- Both Cos and Sin should now be connected to the same radians value
|
|
|
|
**d) Make the direction vector:**
|
|
- Right-click → `Make Vector`
|
|
- Connect Cos result to X (forward/up direction)
|
|
- Connect Sin result to Y (horizontal spread)
|
|
- Set Z = 0
|
|
|
|
14. **Spawn the bullet:**
|
|
- From the loop body execution, drag → `SpawnBullet` (from step 3)
|
|
- Spawn Location: `Get Actor Location`
|
|
- Direction: Connect the Make Vector from step 13
|
|
|
|
15. **Connect loop completion:**
|
|
- The For Loop has a "Completed" execution pin
|
|
- This fires AFTER all iterations are done
|
|
- Drag from "Completed" → `Return Node` (or leave unconnected)
|
|
|
|
**Complete Visual:**
|
|
|
|
```
|
|
┌─────────────┐ ┌────────────────────┐
|
|
│ FireVolley │─────►│ Branch │
|
|
│ (entry) │ │ VolleySize == 1 │
|
|
└─────────────┘ └──────┬───────┬─────┘
|
|
│TRUE │FALSE
|
|
▼ ▼
|
|
┌──────────┐ ┌─────────────────────────────┐
|
|
│SpawnBullet│ │ Calculate StartAngle │
|
|
│Dir:(1,0,0)│ │ = -(Spread*(Size-1))/2 │
|
|
└─────┬────┘ └──────────────┬──────────────┘
|
|
│ ▼
|
|
▼ ┌─────────────────┐
|
|
Return │ For Loop │
|
|
│ 0 to Size-1 │
|
|
└───────┬─────────┘
|
|
│ Loop Body
|
|
▼
|
|
┌──────────────────────────────┐
|
|
│ Angle = Start + (i * Spread) │
|
|
│ Radians = DegreesToRadians │
|
|
│ Dir.X = Cos(Radians) │
|
|
│ Dir.Y = Sin(Radians) │
|
|
│ SpawnBullet(Location, Dir) │
|
|
└──────────────────────────────┘
|
|
```
|
|
|
|
**Test Values (VolleySize=3, VolleySpread=12):**
|
|
- StartAngle = -(12 * 2) / 2 = -12°
|
|
- Bullet 0: -12 + (0 * 12) = -12° → slightly left
|
|
- Bullet 1: -12 + (1 * 12) = 0° → straight up
|
|
- Bullet 2: -12 + (2 * 12) = +12° → slightly right
|
|
|
|
### 5. CONNECT FIREVOLLEY TO THE FIRE RATE LIMITER:
|
|
|
|
1. Go back to the Event Graph tab
|
|
2. Find your IA_Fire logic from [Step 2.5](part-2-create-player.md#step-25-create-player-firing-logic)
|
|
3. Delete the Print String "FIRE!" placeholder
|
|
4. From the "Set FireTimer = FireInterval" node, drag execution → `FireVolley`
|
|
|
|
**Updated Visual:**
|
|
|
|
```
|
|
┌─────────────────┐ TRUE ┌─────────────────────┐
|
|
│ Branch │───────────►│ Set FireTimer │──► FireVolley
|
|
│ FireTimer <= 0 │ │ = FireInterval │
|
|
└─────────────────┘ └─────────────────────┘
|
|
```
|
|
|
|
### 6. Compile and Save
|
|
|
|
### Expected Result after Compile:
|
|
- Compile button shows GREEN checkmark
|
|
- "FireVolley" and "SpawnBullet" functions appear under Functions in My Blueprint panel
|
|
|
|
### Expected Result in Play mode:
|
|
- Pressing Z or Left Mouse Button spawns 3 bullets in a spread pattern
|
|
- Bullets travel upward from player position
|
|
- Rapid fire when holding the button (every 0.08 seconds)
|
|
- Bullets disappear after 4 seconds (RemainingLifetime)
|
|
|
|
---
|
|
|
|
[← Previous: Part 2 - Create the Player](part-2-create-player.md) | [Back to Index](README.md) | [Next: Part 4 - Create the Enemy →](part-4-create-enemy.md)
|