diff --git a/games/unreal/BulletHellGame/BulletHellGame/Content/Blueprints/BP_Bullet.uasset b/games/unreal/BulletHellGame/BulletHellGame/Content/Blueprints/BP_Bullet.uasset new file mode 100644 index 0000000..2d17a59 Binary files /dev/null and b/games/unreal/BulletHellGame/BulletHellGame/Content/Blueprints/BP_Bullet.uasset differ diff --git a/games/unreal/BulletHellGame/BulletHellGame/Content/Blueprints/BP_Player.uasset b/games/unreal/BulletHellGame/BulletHellGame/Content/Blueprints/BP_Player.uasset index d9082b5..dec92f9 100644 Binary files a/games/unreal/BulletHellGame/BulletHellGame/Content/Blueprints/BP_Player.uasset and b/games/unreal/BulletHellGame/BulletHellGame/Content/Blueprints/BP_Player.uasset differ diff --git a/games/unreal/BulletHellGame/BulletHellGame/Saved/Autosaves/Game/Blueprints/BP_Bullet_Auto9.uasset b/games/unreal/BulletHellGame/BulletHellGame/Saved/Autosaves/Game/Blueprints/BP_Bullet_Auto9.uasset new file mode 100644 index 0000000..7caa426 Binary files /dev/null and b/games/unreal/BulletHellGame/BulletHellGame/Saved/Autosaves/Game/Blueprints/BP_Bullet_Auto9.uasset differ diff --git a/games/unreal/BulletHellGame/BulletHellGame/Saved/Autosaves/Game/Blueprints/BP_Player_Auto0.uasset b/games/unreal/BulletHellGame/BulletHellGame/Saved/Autosaves/Game/Blueprints/BP_Player_Auto0.uasset new file mode 100644 index 0000000..149532c Binary files /dev/null and b/games/unreal/BulletHellGame/BulletHellGame/Saved/Autosaves/Game/Blueprints/BP_Player_Auto0.uasset differ diff --git a/games/unreal/BulletHellGame/BulletHellGame/Saved/Config/LinuxEditor/EditorPerProjectUserSettings.ini b/games/unreal/BulletHellGame/BulletHellGame/Saved/Config/LinuxEditor/EditorPerProjectUserSettings.ini index f4c4bb9..73761b9 100644 --- a/games/unreal/BulletHellGame/BulletHellGame/Saved/Config/LinuxEditor/EditorPerProjectUserSettings.ini +++ b/games/unreal/BulletHellGame/BulletHellGame/Saved/Config/LinuxEditor/EditorPerProjectUserSettings.ini @@ -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 diff --git a/games/unreal/BulletHellGame/BulletHellGame/Saved/SourceControl/UncontrolledChangelists.json b/games/unreal/BulletHellGame/BulletHellGame/Saved/SourceControl/UncontrolledChangelists.json index 3a2e192..0576371 100644 --- a/games/unreal/BulletHellGame/BulletHellGame/Saved/SourceControl/UncontrolledChangelists.json +++ b/games/unreal/BulletHellGame/BulletHellGame/Saved/SourceControl/UncontrolledChangelists.json @@ -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" ] diff --git a/games/unreal/tutorial/README.md b/games/unreal/tutorial/README.md index 31ce91e..e60a339 100644 --- a/games/unreal/tutorial/README.md +++ b/games/unreal/tutorial/README.md @@ -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) diff --git a/games/unreal/tutorial/part-3-create-bullet.md b/games/unreal/tutorial/part-3-create-bullet.md index dc0efb8..bff648f 100644 --- a/games/unreal/tutorial/part-3-create-bullet.md +++ b/games/unreal/tutorial/part-3-create-bullet.md @@ -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` diff --git a/games/unreal/tutorial/part-4-create-enemy.md b/games/unreal/tutorial/part-4-create-enemy.md index c944085..b47de66 100644 --- a/games/unreal/tutorial/part-4-create-enemy.md +++ b/games/unreal/tutorial/part-4-create-enemy.md @@ -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)