shooting bullets

This commit is contained in:
Krzysztof kuhy Rudnicki 2026-01-05 18:19:20 +01:00
parent 3d732ef8d7
commit 85cd1d1c79
9 changed files with 427 additions and 91 deletions

View File

@ -187,14 +187,14 @@ MRUItem0=/Game/Untitled
[DetailCustomWidgetExpansion]
InputMappingContext=InputMappingContext.Mappings.ActionMappings,InputMappingContext.Mappings.ActionMappings./Game/Blueprints/IA_Move.IA_Move,InputMappingContext.Mappings.ActionMappings./Game/Input/IA_Move.IA_Move
InputAction=
CameraComponent=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens,CameraComponent.PostProcess.Lens
CameraComponent=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
SceneComponent=
BP_Player_C=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
BP_Player_C=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens,EdGraph.Inputs.277B5E44FBD747478CCE123CD66990D9
PlayerStart=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
CapsuleComponent=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
LandscapeStreamingProxy=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
PropertyWrapper=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
SkyLight=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens,CameraComponent.PostProcess.Lens
SkyLight=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
Landscape=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
EditorStyleSettings=EditorStyleSettings.Graphs.Preview,EditorKeyboardShortcutSettings.EditorViewport.ShowTextureResolution,EditorKeyboardShortcutSettings.EditorViewport.ShowTextureScale,EditorKeyboardShortcutSettings.MainFrame.SwitchProject
SlateThemeManager=
@ -389,12 +389,19 @@ TcpMessagingSettings=EditorStyleSettings.Graphs.Preview,EditorKeyboardShortcutSe
TemplateSequenceEditorSettings=EditorStyleSettings.Graphs.Preview,EditorKeyboardShortcutSettings.EditorViewport.ShowTextureResolution,EditorKeyboardShortcutSettings.EditorViewport.ShowTextureScale,EditorKeyboardShortcutSettings.MainFrame.SwitchProject,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierSmoothDelta,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierDeadZone,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierResponseCurveExponential,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierFOVScaling,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerDown,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerPressed,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerPulse,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerReleased,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerHold,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerHoldAndRelease,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerTap
UdpMessagingSettings=EditorStyleSettings.Graphs.Preview,EditorKeyboardShortcutSettings.EditorViewport.ShowTextureResolution,EditorKeyboardShortcutSettings.EditorViewport.ShowTextureScale,EditorKeyboardShortcutSettings.MainFrame.SwitchProject,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierSmoothDelta,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierDeadZone,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierResponseCurveExponential,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierFOVScaling,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerDown,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerPressed,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerPulse,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerReleased,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerHold,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerHoldAndRelease,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerTap
WmfMediaSettings=EditorStyleSettings.Graphs.Preview,EditorKeyboardShortcutSettings.EditorViewport.ShowTextureResolution,EditorKeyboardShortcutSettings.EditorViewport.ShowTextureScale,EditorKeyboardShortcutSettings.MainFrame.SwitchProject,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierSmoothDelta,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierDeadZone,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierResponseCurveExponential,EnhancedInputDeveloperSettings.Modifier Default Values.InputModifierFOVScaling,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerDown,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerPressed,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerPulse,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerReleased,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerHold,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerHoldAndRelease,EnhancedInputDeveloperSettings.Trigger Default Values.InputTriggerTap
K2Node_VariableGet=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
K2Node_VariableGet=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens,EdGraph.Inputs.277B5E44FBD747478CCE123CD66990D9
K2Node_EnhancedInputAction=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
K2Node_VariableSet=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
K2Node_GetInputActionValue=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
EdGraph=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
EdGraph=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens,EdGraph.Inputs.277B5E44FBD747478CCE123CD66990D9
K2Node_FunctionEntry=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
BP_Bullet_C=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
StaticMeshComponent=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
DefaultPawn=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
SphereComponent=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
GameModeBase=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
BillboardComponent=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
Initialize=CameraComponent.CameraSettings.Overscan,CameraComponent.PostProcess.Lens
[/Script/GraphEditor.GraphEditorSettings]
DataPinStyle=BPST_VariantA
@ -600,9 +607,9 @@ SceneComponent="\"Object\" "
ActorComponent="\"Object\" "
PaperSpriteComponent="\"Object\" \"Object.Collision.BodyInstance\" "
MeshComponent="\"Object\" \"Object.Collision.BodyInstance\" "
PrimitiveComponent="\"Object\" "
PrimitiveComponent="\"Object\" \"Object.Collision.BodyInstance\" "
BoxComponent="\"Object\" \"Object.Collision.BodyInstance\" "
ShapeComponent="\"Object\" "
ShapeComponent="\"Object\" \"Object.Collision.BodyInstance\" "
ArrowComponent="\"Object\" "
InputAction="\"Object\" "
DataAsset="\"Object\" "
@ -688,15 +695,18 @@ InputTriggerTap="\"Object\" "
InputTriggerPulse="\"Object\" "
EdGraphNode_Comment="\"Object\" "
EdGraphNode="\"Object\" "
SphereComponent="\"Object\" \"Object.Collision.BodyInstance\" "
BillboardComponent="\"Object\" "
DefaultPawn="\"Object\" "
[AssetEditorSubsystem]
CleanShutdown=False
DebuggerAttached=False
RecentAssetEditors=GenericAssetEditor
RecentAssetEditors=BlueprintEditor
RecentAssetEditors=GenericAssetEditor
RecentAssetEditors=GenericAssetEditor
RecentAssetEditors=GenericAssetEditor
RecentAssetEditors=GenericAssetEditor
OpenAssetsAtExit=/Game/Blueprints/BP_Player.BP_Player
[ContentBrowser]
@ -1600,6 +1610,119 @@ K2Node_CallFunction.Inputs=True
K2Node_CallFunction.Outputs=True
EdGraphNode_Comment.GraphNodeDetail=True
EdGraphNode_Comment.Comment=True
BP_Bullet_C.Tick=True
BP_Bullet_C.Replication=True
BP_Bullet_C.Rendering=True
BP_Bullet_C.Collision=True
BP_Bullet_C.Actor=True
BP_Bullet_C.Input=True
BP_Bullet_C.HLOD=True
BP_Bullet_C.Physics=True
BP_Bullet_C.Events=True
SphereComponent.Variable=False
SphereComponent.TransformCommon=False
SphereComponent.Sockets=False
SphereComponent.Shape=False
SphereComponent.Navigation=False
SphereComponent.HLOD=False
SphereComponent.ComponentTick=False
SphereComponent.Rendering=False
SphereComponent.Physics=False
SphereComponent.Collision=False
SphereComponent.Tags=False
SphereComponent.ComponentReplication=False
SphereComponent.Cooking=False
SphereComponent.Events=True
GameNetworkManager.TransformCommon=True
GameNetworkManager.Replication=True
GameNetworkManager.Physics=True
GameNetworkManager.Networking=True
GameNetworkManager.Actor=True
PlayerController.TransformCommon=True
PlayerController.PlayerController=True
PlayerController.MouseInterface=True
PlayerController.Game=True
PlayerController.Input=True
PlayerController.WorldPartition=True
PlayerController.Replication=True
PlayerController.HLOD=True
PlayerController.Physics=True
PlayerController.Networking=True
PlayerController.Actor=True
PlayerState.Replication=True
PlayerState.Physics=True
PlayerState.Networking=True
PlayerState.Actor=True
DefaultPawn.TransformCommon=True
DefaultPawn.StaticMesh=True
DefaultPawn.Pawn=True
DefaultPawn.FloatingPawnMovement=True
DefaultPawn.NavMovement=True
DefaultPawn.Velocity=True
DefaultPawn.Physics=True
DefaultPawn.Collision=True
DefaultPawn.PlanarMovement=True
DefaultPawn.Lighting=True
DefaultPawn.MovementComponent=True
DefaultPawn.Tags=True
DefaultPawn.AssetUserData=True
DefaultPawn.Rendering=True
DefaultPawn.Activation=True
DefaultPawn.Navigation=True
DefaultPawn.Cooking=True
DefaultPawn.Shape=True
DefaultPawn.HLOD=True
DefaultPawn.Mobile=True
DefaultPawn.RayTracing=True
DefaultPawn.Mesh Painting=True
DefaultPawn.VirtualTexture=True
DefaultPawn.Camera=True
DefaultPawn.Replication=True
DefaultPawn.Networking=True
DefaultPawn.Input=True
DefaultPawn.Actor=True
DefaultPawn.Materials=True
GameModeBase.Classes=True
GameModeBase.Game=True
GameModeBase.GameMode=True
GameModeBase.Physics=True
GameModeBase.Networking=True
GameSession.TransformCommon=True
GameSession.Replication=True
GameSession.Physics=True
GameSession.Networking=True
GameSession.Actor=True
SkyAtmosphere.TransformCommon=True
SkyAtmosphere.Planet=True
SkyAtmosphere.Atmosphere=True
SkyAtmosphere.Atmosphere - Rayleigh=True
SkyAtmosphere.Atmosphere - Mie=True
SkyAtmosphere.Atmosphere - Absorption=True
SkyAtmosphere.Art Direction=True
SkyAtmosphere.Rendering=True
SkyAtmosphere.Physics=True
SkyAtmosphere.Tags=True
SkyAtmosphere.Activation=True
SkyAtmosphere.Cooking=True
SkyAtmosphere.Replication=True
SkyAtmosphere.Networking=True
SkyAtmosphere.Actor=True
ExponentialHeightFog.TransformCommon=True
ExponentialHeightFog.ExponentialHeightFogComponent=True
ExponentialHeightFog.InscatteringTexture=True
ExponentialHeightFog.DirectionalInscattering=True
ExponentialHeightFog.VolumetricFog=True
ExponentialHeightFog.Rendering=True
ExponentialHeightFog.Physics=True
ExponentialHeightFog.Tags=True
ExponentialHeightFog.Activation=True
ExponentialHeightFog.Cooking=True
ExponentialHeightFog.Replication=True
ExponentialHeightFog.Networking=True
ExponentialHeightFog.Actor=True
K2Node_FunctionResult.Graph=True
K2Node_FunctionResult.Inputs=True
K2Node_FunctionResult.Outputs=True
[DetailMultiObjectNodeExpansion]
GeneralProjectSettings=True
@ -1662,11 +1785,12 @@ CrowdManager=True
CookerSettings=True
[AssetEditorSubsystemRecents]
MRUItem0=/Game/Blueprints/BP_Player
MRUItem1=/Game/Input/IMC_Default
MRUItem2=/Game/Input/IA_Move
MRUItem3=/Game/Input/IA_Special
MRUItem4=/Game/Input/IA_Fire
MRUItem0=/Game/Blueprints/BP_Bullet
MRUItem1=/Game/Blueprints/BP_Player
MRUItem2=/Game/Input/IMC_Default
MRUItem3=/Game/Input/IA_Move
MRUItem4=/Game/Input/IA_Special
MRUItem5=/Game/Input/IA_Fire
[SelectionDetails]
PreserveScaleRatio=True
@ -1674,6 +1798,7 @@ PreserveScaleRatio=True
[DetailCategoriesAdvanced]
InputAction.Action=False
EdGraph.Graph=True
PropertyWrapper.Variable=False
[AssetEditorToolkitTabLocation]
/Game/Input/IA_Move.IA_Move=1

View File

@ -156,8 +156,9 @@
"/home/kuhy/praca_magisterska/games/unreal/BulletHellGame/BulletHellGame/Content/__ExternalActors__/Untitled/5/OM/8IGK2V3IFN3KZLW18YOQBO.uasset",
"/home/kuhy/praca_magisterska/games/unreal/BulletHellGame/BulletHellGame/Content/__ExternalActors__/Untitled/B/6S/O5MC4CZRRB62HQ1QQK7X0J.uasset",
"/home/kuhy/praca_magisterska/games/unreal/BulletHellGame/BulletHellGame/Content/Untitled.umap",
"/home/kuhy/praca_magisterska/games/unreal/BulletHellGame/BulletHellGame/Content/__ExternalActors__/Untitled/7/HJ/X38LX50JWL2L2Y8KSQTL7D.uasset",
"/home/kuhy/praca_magisterska/games/unreal/BulletHellGame/BulletHellGame/Content/__ExternalActors__/Untitled/8/DU/ZSDVJX62HUOGBSNTE6TBHV.uasset",
"/home/kuhy/praca_magisterska/games/unreal/BulletHellGame/BulletHellGame/Content/Blueprints/BP_Bullet.uasset",
"/home/kuhy/praca_magisterska/games/unreal/BulletHellGame/BulletHellGame/Content/__ExternalActors__/Untitled/7/HJ/X38LX50JWL2L2Y8KSQTL7D.uasset",
"/home/kuhy/praca_magisterska/games/unreal/BulletHellGame/BulletHellGame/Content/__ExternalActors__/Untitled/8/NZ/GJL3NPSSBFSHGE0B2HZWC6.uasset",
"/home/kuhy/praca_magisterska/games/unreal/BulletHellGame/BulletHellGame/Content/Blueprints/IA_Move.uasset"
]

View File

@ -42,6 +42,7 @@ This tutorial recreates the Unity "magisterka_1" bullet-hell shooter in Unreal E
- [Step 4.4: Enemy Firing Logic](part-4-create-enemy.md#step-44-enemy-firing-logic)
- [Step 4.5: Enemy Damage and Death](part-4-create-enemy.md#step-45-enemy-damage-and-death)
- [Step 4.6: Complete Special Ability in BP_Player](part-4-create-enemy.md#step-46-complete-special-ability-in-bp_player)
- [Step 4.7: Complete Bullet Collision Logic](part-4-create-enemy.md#step-47-complete-bullet-collision-logic-bp_bullet)
### Part 5: Create Enemy Spawner
- [Step 5.1: Create Spawner Blueprint](part-5-create-spawner.md#step-51-create-spawner-blueprint)

View File

@ -47,15 +47,73 @@
1. In Event Graph, from **Event Tick:**
#### a) Calculate movement:
- Get TravelDirection
- Multiply by TravelSpeed
- Multiply by Delta Seconds
- Add to current location
- Set Actor Location
#### b) Check lifetime:
- Subtract Delta Seconds from RemainingLifetime
- If <= 0: Destroy Actor
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:
@ -81,40 +139,100 @@
- Compile button shows GREEN checkmark
- "Initialize" function appears under Functions with 5 input parameters
### Expected Result in Play mode (when spawned by player):
- Bullets move in their assigned direction at TravelSpeed
- Bullets automatically destroy after RemainingLifetime seconds (default 4s)
- Movement is smooth and frame-rate independent
> **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. Click on "BulletCollision" component in Components panel
### 1. ADD THE OVERLAP EVENT:
2. In Details panel, scroll to "Events" section
- Click "+" next to **"On Component Begin Overlap"**
- This creates event node in Event Graph
1. In the Components panel (top-left), click on **"BulletCollision"** to select it
3. In the Event Graph, from "On Component Begin Overlap":
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
#### a) First, check if this is enemy projectile:
- Get IsEnemyProjectile
- Branch
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
#### b) IF IS ENEMY PROJECTILE (True branch):
- Get Other Actor from the overlap event
- Cast to BP_Player
- If cast succeeds:
- Call TakeHit on player, passing Damage
- Destroy this bullet (Destroy Actor)
#### c) IF IS PLAYER BULLET (False branch):
- Get Other Actor
- Cast to BP_Enemy
- If cast succeeds:
- Call ApplyDamage on enemy, passing Damage
- Destroy this bullet
### 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
@ -122,12 +240,7 @@
- Compile button shows GREEN checkmark
- Event Graph shows "On Component Begin Overlap" event connected to Branch
### Expected Result in Play mode:
- Player bullets (IsEnemyProjectile=false) hitting enemies:
- Enemy takes damage, bullet disappears
- Enemy bullets (IsEnemyProjectile=true) hitting player:
- Player takes hit, bullet disappears
- Bullets passing through other objects: No effect (bullets ignore non-targets)
> **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).
---
@ -171,53 +284,68 @@ The entry node should now show two input pins: SpawnLocation and Direction
2. For the "Class" input:
- Right-click → `Get BulletClass` (your variable)
- Connect to "Class" pin
- Connect BulletClass output (blue pin) to SpawnActor's "Class" input (purple pin)
3. For the "Spawn Transform" input:
- Right-click on the "Spawn Transform" pin → "Split Struct Pin"
- This splits it into Location, Rotation, Scale
- Connect "SpawnLocation" (from entry node) to "Spawn Transform Location"
- Leave Rotation and Scale at defaults
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 → Spawn Actor from Class
- Drag from SpawnBullet entry node (white triangle) → SpawnActor (white triangle)
#### f) Initialize the spawned bullet:
5. The "Spawn Actor from Class" has a "Return Value" output (the spawned actor)
- Drag from Return Value → search `Cast to BP_Bullet`
- This works now because BP_Bullet exists!
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. From the cast's "As BP Bullet" output, drag → search `Initialize`
- This calls the Initialize function on the bullet (created in Step 3.2)
- Connect "Direction" (from entry node) to Initialize's Direction input
- Right-click → `Get BulletSpeed` → connect to Speed input
- For "bIsEnemy" input: leave unchecked (false) - player bullets aren't enemy
- For "Lifetime": type `4.0` (or leave default)
6. Connect execution wire:
- From SpawnActor (white triangle output) → Cast to BP_Bullet (white triangle input)
7. Connect execution wires:
- Spawn Actor → Cast to BP_Bullet → Initialize
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 ○ │ │ Location: SpawnLocation │
└───────────────────────┘ └───────────┬─────────────┘
┌───────────────────────┐ ┌─────────────────────────────────┐
│ SpawnBullet │─────►│ Spawn Actor from Class │
│ SpawnLocation ○───────┼─────►│ Class: BulletClass │
│ Direction ○ │ │ Spawn Transform Location ○◄───┘
└───────────────────────┘ │ Return Value ○────────────────┐
└─────────────────────────────────┘
┌─────────────────────┘
┌─────────────────────────┐
│ Cast to BP_Bullet │
└───────────┬─────────────┘
│ Object ○◄─────────────┘
│ As BP Bullet ○────────┐
└─────────────────────────┘
┌─────────────┘
┌─────────────────────────┐
│ Initialize │
│ Direction: Direction │
│ Speed: BulletSpeed │
│ bIsEnemy: false │
│ Target ○◄─────────────┘
│ Direction ○◄──────────── (from entry node)
│ Speed ○◄────────────── BulletSpeed
│ bIsEnemy: false │
│ Lifetime: 4.0 │
└─────────────────────────┘
```
@ -360,19 +488,20 @@ The entry node should now show two input pins: SpawnLocation and Direction
BUT Unreal's Sin/Cos use RADIANS, not degrees!
**a) Convert degrees to radians:**
- Right-click → search `Radians` or `Degrees to Radians`
- Connect your angle (from step 12) to input
- 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):**
- Right-click → `Cos (Radians)`
- Connect radians output
- This is the X direction component
- Right-click → `Cos (Radians)` → add it
- Connect the Degrees To Radians output to Cos input
**c) Calculate Y component (Sin):**
- Right-click → `Sin (Radians)`
- Connect radians output (same value as Cos input)
- This is the Y direction component
- 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`

View File

@ -346,4 +346,84 @@ Now that BP_Enemy exists (and BP_Bullet from Part 3), we can complete the specia
---
## 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)