Alright, this isn’t the only way to do this, but given what you’ve said this is what I’d likely try. I keep meaning to go build this in BP and post screenshots, but I just haven’t had the time, so you’ll have to deal with my notes. Hopefully you’ll get the idea. Please bear with me if I have some node names or arguments wrong.
For the purposes of this example I’m going to make the following assumptions:
- Z is up/down
- Y is into the screen
- X is left and right
- You know the screen edge positions and can retrieve them each frame
- You know how to determine which direction your character is facing (plus or minus X)
- You have your Player Character already setup and it has an animation you want to use for “Throw”
- You have a Boomerang Actor that you can spawn, animate, etc.
- The Boomerang is a permanent part of the player’s inventory
- You want the Boomerang to be able to retrieve pickup items
- The Boomerang has a looping “Flying” animation
- Your character has a function that allows it to collect pickup items
- You have one “Enemy” class that all your enemy characters derive from
- You have one “Item” class that all your pickup items derive from
You should have the Boomerang Actor spawned in the level, but hidden, not ticking, and collisions disabled. The Boomerang collision should be set to Overlap the Player Character, Overlap Enemies, and Overlap Items. It should be set to Ignore everything else.
First, we’ll look at the Character.
CHARACTER
You’ll need to have a few variables set:
- bHasBoomerang (bool) - TRUE when the character has the boomerang
- ThrowHeight (float) - the height above the ground the boomerang should move along when thrown
- ThrowOffset (float) - the distance from the player the boomerang should begin when thrown (this allows for the player’s arm length or other animation so the boomerang doesn’t start inside the player)
- ThrowMaximumDistance (float) - the maximum distance the boomerang can travel before turning around
- Boomerang (obj reference) - pointer to the Boomerang Actor you’ve spawned in the level and associated with this character
Create a function on your character called “ThrowBoomerang”
The ThrowBoomerang function needs two local variables:
- NewStartLocation
- NewTargetLocation
When called, ThrowBoomerang function should first check if bHasBoomerang is TRUE
If it is FALSE, the method should just end.
If it is TRUE, then the function should:
- Set bHasBoomerang to FALSE
- Get the current world location of the player
- Add ThrowHeight to that location’s Z
- Add/Subtract ThrowOffset from that location’s X value based on facing direction
- Set the result to the StartLocation
- Add the ThrowMaximumDistance to StartLocation.X
- Set the result to TargetLocation
- Call “BeginThrow” on the Boomerang object, sending it NewStartLocation and NewTargetLocation
- Begin the character’s “Throw” animation
Create a function on your character called “CatchBoomerang”
When called, CatchBoomerang function should first check if bHasBoomerang is FALSE
If it is TRUE, the method should just end.
If it is FALSE, then the function should:
-
Set bHasBoomerang to TRUE.
-
Loop through the Boomerang->CarriedItems array
- Call your Item Pickup function for each entry
-
Empty the Boomerang->CarriedItems array
Next, we’ll look at the Boomerang.
BOOMERANG
You’ll need to have a few variables set:
- bIsReturning (bool) - flag telling the boomerang which behavior to use, make the default FALSE
- TargetLocation (vector) - the location the boomerang is currently flying to, make the default 0,0,0
- MinDistanceFromEdge (float) - the minimum distance from the edge of the screen the boomerang has to stay
- ThrowVelocity (float) - the speed the boomerang moves when thrown away from the character, in units/second
- ReturnVelocity (float) - the speed the boomerang moves when returning to the character, in units/second
- CarriedItems (array - Items) - array of pickup items currently held by this boomerang
- Character (obj reference) - pointer to the Character associated with this boomerang
Create a function on the Boomerang called “BeginThrow”
- It should accept two vectors: StartLocation and NewTargetLocation
When called, the BeginThrow function should:
- Set bIsReturning to FALSE
- Set SetActorLocation with StartLocation and set Sweep to FALSE and Teleport to TRUE
- Set TargetLocation to passed in NewTargetLocation
- Set a Delay for the duration of the Character’s “Throw” animation - it shouldn’t be more than a couple frames or there will be too much lag after the player presses the throw boomerang button
After the Delay:
- Call SetActorHiddenInGame with FALSE
- Call SetActorEnableCollision with TRUE
- Call SetActorTickEnabled with TRUE
- Begin the “Flying” animation
Create a function on the Boomerang called “UpdateThrow”
- It should accept a float: DeltaTime
The UpdateThrow function needs three local variables:
- TravelDistance (float)
- TraceMod (float)
- NewLocation (vector)
When called, the UpdateThrow function should:
-
Multiply input DeltaTime by ThrowVelocity
-
Set the result to TravelDistance
-
Set HalfWidth to TraceMod
-
Call GetActorLocation
-
Subtract ActorLocation.X from TargetLocation.X
-
Get the Abs of the result:
If it is GREATER than or EQUAL to TravelDistance
- Set TravelDistance to original (not absolute) result
- Set bIsReturning to TRUE
- If TravelDistance is Negative, NEGATE TraceMod
- If TravelDistance is 0, set TraceMod to 0
If it is LESS, then:
- If ActorLocation.X is GREATER than TargetLocation.X, NEGATE TravelDistance
-
Add TravelDistance to the ActorLocation.X
-
Set the result to NewLocation
-
If NewLocation.X is GREATER than RightScreenEdge
-
Set NewLocation.X to RightScreenEdge - MinDistanceFromEdge
If NewLocation.X is **LESS** than LeftScreenEdge
1. Set NewLocation.X to LeftScreenEdge + MinDistanceFromEdge
-
Call LineTraceForObjects
- Set ActorLocation to Start
- Add TraceMod to NewLocation.X and set the result to End
- Make an array holding the the Enemy class and set it to Object Types
-
If Return Value is TRUE:
- Break the Hit Result
- Get the Impact Point, set its X to NewLocation.X
-
Call SetActorLocation, pass it NewLocation and set Sweep to TRUE
Create a function on the Boomerang called “UpdateReturn”
- It should accept a float: DeltaTime
The UpdateReturn function needs three local variables:
- TravelDistance (float)
- NewLocation (vector)
- TravelVector (vector)
When called, the UpdateThrow function should:
- Multiply input DeltaTime by ThrowVelocity
- Set the result to TravelDistance
- Call Character->GetActorLocation
- Set the result to TargetLocation
- Call GetActorLocation
- Subtract ActorLocation from TargetLocation
- Set the result to TravelVector
- Call VectorLength on TravelVector
- Get the Abs of the result
- If the Abs is GREATER or EQUAL to TravelDistance:
1. Set TargetLocation to NewLocation
If it is **LESS**:
1. Call Normalize on the TravelVector
2. Multiply the result by TravelDistance
3. Add the result to ActorLocation
4. Set the result to NewLocation
5. If NewLocation.X is **GREATER** than RightScreenEdge
1. Set NewLocation.X to RightScreenEdge.X - MinDistanceFromEdge
If NewLocation.X is **LESS** than LeftScreenEdge
1) Set NewLocation.X to LeftScreenEdge.X + MinDistanceFromEdge
6. If NewLocation.Z is **GREATER** than TopScreenEdge
1. Set NewLocation.Z to TopScreenEdge - MinDistanceFromEdge
If NewLocation.Z is **LESS** than BottomScreenEdge
1. Set NewLocation.Z to BottomScreenEdge + MinDistanceFromEdge
- Call SetActorLocation, pass it NewLocation and set Sweep to TRUE
Add a Tick event
- If you already have one, add to the end
- If bIsReturning is TRUE
- Call “UpdateReturn”, passing in DeltaTime
If it’s FALSE
- Call “UpdateThrow”, passing in DeltaTime
Add an ActorBeginOverlap event
- If you already have one, add to the end:
-
Cast OtherActor to the Enemy class
Success Branch:
- Get the AsEnemy actor and do whatever damage you want to do
- Set bIsReturning to TRUE
Fail Branch:
- Cast OtherActor to Item class
Success Branch:
- Get the AsItem actor
- Add AsItem to the CarriedItems array
- Call SetActorHiddenInGame with AsItem and TRUE
- Call SetActorEnableCollision with AsItem and FALSE
- Call SetActorTickEnabled with AsItem and FALSE
Fail Branch:
- Cast OtherActor to Character class
**Success Branch:**
1. If AsCharacter is EQUAL to Boomerang's Character
1. Call SetActorHiddenInGame with FALSE
2. Call SetActorEnableCollision with TRUE
3. Call SetActorTickEnabled with TRUE
4. Stop the "Flying" animation
5. Call Character->CatchBoomerang
That should at least get you started.