What “Objective” Means in a Small Level
A clear objective gives your level a purpose and a finish line. For a first playable level, keep the win condition simple and readable: collect one item, then reach an exit zone. This creates a short gameplay loop you can build and test quickly.
We will implement this with two gameplay pieces:
- Collectible: a Blueprint Actor that rotates, detects overlap with the player, plays feedback (sound/visual), and marks the objective as completed (or increments a count).
- Exit Trigger: a trigger volume that checks whether the collectible was obtained; if yes, it shows a win message.
Plan the Win Condition (Minimal, Beginner-Friendly)
Choose one of these patterns:
- Boolean objective (simplest):
bHasKey = trueafter pickup. - Count objective (slightly more flexible):
CollectedCountincreases; win requiresCollectedCount >= RequiredCount.
This chapter uses the boolean approach for the core path, and shows the count approach as an optional upgrade.
Build Step 1: Create the Collectible Blueprint
1) Create the Blueprint Actor
- In the Content Browser, create a new Blueprint Class: Actor.
- Name it
BP_Collectible. - Open it and add components:
- Scene (Root) if not already present.
- Static Mesh (name it
Mesh) and assign any simple mesh (coin, gem, cube, etc.). - Sphere Collision (name it
PickupSphere) and set it as a child of the root.
2) Configure collision for overlap pickup
Select PickupSphere:
Continue in our app.
You can listen to the audiobook with the screen off, receive a free certificate for this course, and also have access to 5,000 other free online courses.
Or continue reading below...Download the app
- Set Collision Enabled to
Query Only. - Set Generate Overlap Events to enabled.
- Set collision preset to something like
OverlapAllDynamic, then refine if needed.
Goal: the player should trigger OnComponentBeginOverlap when entering the sphere.
3) Add rotation (simple visual motion)
In BP_Collectible, add a variable:
RotationSpeed(Float), default e.g.90(degrees per second).
In the Event Graph, implement rotation using Tick:
Event Tick (Delta Seconds) -> AddActorLocalRotation (Yaw = RotationSpeed * Delta Seconds)If you prefer, rotate only the mesh:
Event Tick -> Mesh: AddLocalRotation (Yaw = RotationSpeed * Delta Seconds)4) Add pickup feedback (sound + visual)
Create two optional variables on the collectible so you can reuse it with different effects:
PickupSound(Sound Base / Sound Cue)PickupVFX(Niagara System) or use a simple particle system if available
Also add a variable:
bDestroyOnPickup(Boolean), defaulttrue
On overlap, you will:
- Play a sound at the collectible location.
- Spawn a VFX at the collectible location.
- Disable collision immediately to prevent double pickups.
- Hide or destroy the actor.
5) Update the objective state (core: boolean)
You need a place to store “the player has collected the item.” For a beginner-friendly setup, store it on the player character (or a player-related object you already use). Create a boolean variable on your player character Blueprint:
bHasCollectible(Boolean), defaultfalse
Now implement the overlap logic in BP_Collectible:
- Add event:
PickupSphere -> OnComponentBeginOverlap - From
Other Actor, cast to your player character Blueprint. - If cast succeeds:
- Set
bHasCollectibleon the player totrue. - Play feedback (sound/VFX).
- Disable collision and remove the collectible.
OnComponentBeginOverlap (PickupSphere) -> Cast to BP_PlayerCharacter (Other Actor) -> Set bHasCollectible = true -> (If PickupSound valid) PlaySoundAtLocation -> (If PickupVFX valid) SpawnSystemAtLocation -> PickupSphere: SetCollisionEnabled(NoCollision) -> Mesh: SetVisibility(false) -> (Optional) DestroyActorTip: Hiding first and destroying after a short delay can make VFX easier to see. You can use a short delay (e.g. 0.2–0.5s) before DestroyActor.
6) Place the collectible in the level
- Drag
BP_Collectibleinto the level. - Scale it and position it somewhere obvious on the main path.
- Adjust
PickupSphereradius so it feels forgiving.
Test Step 1: Verify Pickup Works
Run the level and confirm:
- The collectible rotates.
- Walking into it triggers pickup once (no repeated sounds).
- The collectible disappears.
- The player variable
bHasCollectiblebecomes true (you can temporarily print it to screen for debugging).
If you need a quick debug print inside the collectible:
After setting bHasCollectible = true -> Print String("Picked up!")Add Feedback Step 2: Make the Objective Clear to the Player
Even in a simple level, players need confirmation. Add at least one of these:
- Audio: a short pickup sound.
- Visual: a sparkle burst, glow, or quick flash.
- Text: a small on-screen message like “Item collected!”
For a minimal text message, you can use Print String on pickup. Later, you can replace it with UI.
Build Step 3: Create the Exit Trigger (Win Zone)
1) Create the exit Blueprint Actor
- Create a new Blueprint Class: Actor.
- Name it
BP_ExitZone. - Add components:
- Scene (Root)
- Box Collision (name it
ExitBox) - (Optional) Static Mesh or a visible marker (like a doorway mesh) so players can see the exit.
2) Configure overlap on the exit
Select ExitBox:
- Collision Enabled:
Query Only - Generate Overlap Events: enabled
3) Check the condition and show a win message
In BP_ExitZone Event Graph:
- Add event:
ExitBox -> OnComponentBeginOverlap - Cast
Other Actorto your player character. - Branch on
bHasCollectible:
- If
true: show win message. - If
false: show “You need the item first.”
OnComponentBeginOverlap (ExitBox) -> Cast to BP_PlayerCharacter -> Branch (bHasCollectible) True: Print String("You Win!") False: Print String("Find the collectible first.")Prevent repeated triggering: After winning, disable the exit collision so the message doesn’t spam:
On Win -> ExitBox: SetCollisionEnabled(NoCollision)Optional: If you want the player to stop moving after winning, you can disable input on the player controller, but keep the core path minimal: a win message is enough.
4) Place the exit zone in the level
- Drag
BP_ExitZoneinto the level. - Scale the
ExitBoxto cover the doorway/finish area. - Make sure it’s reachable and clearly visible from the main path.
Test Step 2: Full Objective Loop
Run two tests:
- Test A (fail case): go to the exit without collecting. You should see “Find the collectible first.”
- Test B (success case): collect the item, then go to the exit. You should see “You Win!” and the exit should stop triggering repeatedly.
Retest Step 3: Common Fixes if Something Doesn’t Work
| Problem | Likely cause | Fix |
|---|---|---|
| Pickup doesn’t trigger | Collision not overlapping | Ensure PickupSphere has overlap enabled and the player collision responds to overlaps |
| Pickup triggers multiple times | Overlap fires again before destroy | Disable collision immediately on pickup (NoCollision) |
| Exit always says “need item” | Variable not set on the correct player instance | Confirm you set bHasCollectible on the casted player character, not on the collectible |
| Exit triggers but cast fails | Overlapping actor isn’t the player character | Verify the player pawn class used in play is the one you cast to |
Optional Enhancement: Switch to a Count-Based Objective
If you want multiple collectibles, replace the boolean with a count:
- On the player character:
CollectedCount(Integer, default 0) - On the exit zone:
RequiredCount(Integer, default e.g. 3)
Collectible overlap becomes:
Cast to BP_PlayerCharacter -> CollectedCount = CollectedCount + 1Exit check becomes:
Branch (CollectedCount >= RequiredCount) -> Win / Not yetThis keeps the same structure while letting you place several collectibles around the level.
Optional Enhancement: Basic UI Widget for Collection Status
If you want the player to always know progress, add a simple UI widget that shows either “Collected: Yes/No” or “Collected: X/Y”. Keep it minimal:
- Create a Widget Blueprint
WBP_Objective. - Add a Text element (e.g.
ObjectiveText). - On the player (or HUD/controller), create the widget at Begin Play and add it to viewport.
- Update the text when the collectible is picked up (or bind it to the variable).
Example update approach (event-driven, simple): when pickup happens, after setting the variable, call a function on the widget like SetObjectiveText to change the displayed message.