Hey @YourCooked how are you?
I’ve been tinkering all day with UEFn in order to find a way to make something like you want and, sadly, I didn’t come to anything really usefull.
The problem here is that you need to use the { /Verse.org/SpatialMath } API to apply inpulse to custom props with physics, but you can only get the player’s forward vector from { /UnrealEngine.com/Temporary/SpatialMath } API, which is incompatible with the one from Verse.
I managed to reach a point where I’m able to apply impulse to a custom prop, but it won’t work as espected as it will be throw in the same direction always. Let me share the code with you, so you can check it ad maybe find anything usefull!
I’m using two different devices so I don’t mix the two APIs:
Device 1: Attach prop to Player
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Added APIs
using { /Fortnite.com/Characters }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /UnrealEngine.com/ControlInput }
using { /Fortnite.com/Input/Character }
# Device that allows a player to automatically attach to a beach ball
# and throw it using short or long input triggers
AttachPlayer := class(creative_device):
# Reference to the beach ball prop in the level
@editable BeachBall : creative_prop = creative_prop{}
# Input trigger used for a short pass
@editable ShortInputTrigger : input_trigger_device = input_trigger_device{}
# Input trigger used for a long pass
@editable LongInputTrigger : input_trigger_device = input_trigger_device{}
# Class responsible for applying throw forces to the beach ball
@editable ThrowClass : Throw_BeachBall = Throw_BeachBall{}
# Time (in seconds) between proximity checks
@editable CheckInterval : float = 0.1
# Maximum distance at which a player can grab the ball
@editable ProximityRadius : float = 100.0
# Agent currently holding the ball (optional)
var Holder : ?agent = false
# Whether the ball is currently attached to a player
var IsAttached : logic = false
# Called when the device starts
OnBegin<override>()<suspends>:void=
# Get all players currently in the playspace
Players := GetPlayspace().GetPlayers()
# Register all players to both input triggers
for (Player : Players):
ShortInputTrigger.Register(Player)
LongInputTrigger.Register(Player)
# Listen for players joining later
GetPlayspace().PlayerAddedEvent().Subscribe(OnPlayerAdded)
# Start the continuous distance check loop
spawn {StartDetectionLoop()}
# Subscribe input events for short and long passes
ShortInputTrigger.PressedEvent.Subscribe(ShortPass)
LongInputTrigger.PressedEvent.Subscribe(LongPass)
# Called whenever a new player joins the playspace
OnPlayerAdded(Player:player):void=
# Register the new player to the input triggers
ShortInputTrigger.Register(Player)
LongInputTrigger.Register(Player)
# Loop that periodically checks player distance to the ball
StartDetectionLoop()<suspends>:void =
loop:
CheckAllPlayerDistances()
Sleep(CheckInterval)
# Checks all players to see if any can grab the ball
CheckAllPlayerDistances():void =
Players := GetPlayspace().GetPlayers()
for (Player : Players):
# Ignore the current holder
if(Player <> Holder):
if(FortChar := Player.GetFortCharacter[]):
CanGrab := IsPlayerInRange(FortChar)
if(CanGrab = true):
# Assign the new holder
set Holder = option{Player}
set IsAttached = true
AttachToPlayer(Player)
# Checks if a player is within grabbing range of the ball
IsPlayerInRange(FortChar:fort_character) : logic =
PlayerPos := FortChar.GetTransform().Translation
BallPos := BeachBall.GetTransform().Translation
var IsInRange : logic = false
# Compare distance between player and ball
if (Distance(PlayerPos, BallPos) <= ProximityRadius):
set IsInRange = true
else:
set IsInRange = false
return IsInRange
# Attaches the ball to a player and disables physics
AttachToPlayer(Agent:agent):void=
BeachBall.SetDynamic(false)
spawn:
FollowPlayer(Agent)
# Continuously moves the ball to follow the player
FollowPlayer(Agent:agent)<suspends>:void=
if(FortChar := Agent.GetFortCharacter[]):
loop:
# Stop following if the ball is no longer attached
if(IsAttached = false):
break
Sleep(0.0)
# Match the ball position and rotation to the player
PlayerPos := FortChar.GetTransform().Translation
PlayerRot := FortChar.GetTransform().Rotation
BeachBall.MoveTo(PlayerPos, PlayerRot, 0.1)
# Handles short pass input
ShortPass(Agent:agent):void=
# Only allow the current holder to throw
if(IsAttached = true):
if(Agent = Holder?):
if(FortChar := Agent.GetFortCharacter[]):
spawn{DelayedShortPass(FortChar)}
set Holder = false
set IsAttached = false
# Executes the short pass after releasing the ball
DelayedShortPass(HolderChar:fort_character)<suspends>:void=
Sleep(0.0)
BeachBall.SetDynamic(true)
ThrowClass.ShortPass(BeachBall)
# Handles long pass input
LongPass(Agent:agent):void=
# Only allow the current holder to throw
if(IsAttached = true):
if(Agent = Holder?):
if(FortChar := Agent.GetFortCharacter[]):
spawn{DelayedLongPass(FortChar)}
set Holder = false
set IsAttached = false
# Executes the long pass after releasing the ball
DelayedLongPass(HolderChar:fort_character)<suspends>:void=
Sleep(0.0)
BeachBall.SetDynamic(true)
ThrowClass.LongPass(BeachBall)
With this values on editor:
Device 2: Throw the ball
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Added APIs
using { /Verse.org/SpatialMath }
using { /Fortnite.com/Characters }
# Device responsible for applying impulse forces to a beach ball
# Used by other devices to perform short or long throws
Throw_BeachBall := class(creative_device):
# Impulse applied for a short pass
@editable ShortImpulse : vector3 = vector3{}
# Impulse applied for a long pass
@editable LongImpulse : vector3 = vector3{}
# Applies a short impulse to the given prop
ShortPass(Prop:creative_prop):void=
# Debug message to confirm the short pass was triggered
Print("Short Pass")
# Apply a linear impulse to the prop using the short pass force
Prop.ApplyLinearImpulse(ShortImpulse)
# Applies a long impulse to the given prop
LongPass(Prop:creative_prop):void=
# Debug message to confirm the long pass was triggered
Print("Long Pass")
# Apply a linear impulse to the prop using the long pass force
Prop.ApplyLinearImpulse(LongImpulse)
With this values on editor:
As @Abrizzer said, I recommend you to check this documentation to understand how physics work.
Hope this helps you to figure out how to make it work! And sorry for not being more usefull! Let me know if you don’t understand anything!