With this script I’m trying to snap a prop to Player:
It compiles, no errors, it runs in game, it prints the correct values… and yet, prop doesn’t move.
If anybody has any idea WHY, I’d be super thankful!
In the meantime, I’ll look for a workaround: I hyper commented the code hoping you’ll find something useful in it.
Cheers!
using { /Fortnite.com/Devices } # Import the devices module from Fortnite for device-related classes and functions
using { /Fortnite.com/Characters } # Import the characters module from Fortnite for character-related classes and functions
using { /Verse.org/Simulation } # Import the simulation module from Verse for simulation-related classes and functions
using { /UnrealEngine.com/Temporary/SpatialMath } # Import the SpatialMath module from Unreal Engine for spatial and mathematical operations
# Define a class with editable prop and volume_device variables
snap_prop_to_player := class(creative_device): # Define a new class called snap_prop_to_player, inheriting from creative_device
@editable # Allow this property to be set from the editor
PieceOfCode:creative_prop = creative_prop{} # Define an editable property PieceOfCode of type creative_prop and initialize it
@editable # Allow this property to be set from the editor
VolumeTrigger:volume_device = volume_device{} # Define an editable property VolumeTrigger of type volume_device and initialize it
# Define an event handler for when a player enters the volume
OnBegin<override>()<suspends>:void= # Override the OnBegin method to define custom behavior when the game starts; <suspends> indicates the method can be paused
# Subscribe to the volume's EnteredEvent
VolumeTrigger.AgentEntersEvent.Subscribe(AttachToPlayer) # Subscribe the AttachToPlayer method to the AgentEntersEvent of the VolumeTrigger
AttachToPlayer(Agent : agent) : void = # Define the AttachToPlayer method, which takes an Agent of type agent and returns void
spawn: # Use the spawn keyword to start the OnPlayerEntered method asynchronously
OnPlayerEntered(Agent) # Call the OnPlayerEntered method with the Agent as a parameter
# Event handler function for when a player enters the volume
OnPlayerEntered(InPlayer:agent)<suspends> :void= # Define the OnPlayerEntered method, which takes an InPlayer of type agent and suspends its execution
if (FortniteCharacter := InPlayer.GetFortCharacter[]): # Use an if statement to attempt to get the FortniteCharacter from InPlayer; the := operator assigns the result if successful
Print("Player entered volume and attached!", ?Duration:=6.0) # Print a message indicating the player has entered the volume, with the message displayed for 6 seconds
loop: # Start a loop block, which runs indefinitely until explicitly broken or interrupted
Sleep(0.1) # Pause execution for 0.1 seconds to allow other processes to run
PlayerTransform := FortniteCharacter.GetTransform() # Get the Transform object from the FortniteCharacter and assign it to PlayerTransform
PlayerPosition := PlayerTransform.Translation # Extract the Translation (position) vector from PlayerTransform and assign it to PlayerPosition
PlayerRotation := PlayerTransform.Rotation # Extract the Rotation from PlayerTransform and assign it to PlayerRotation
# Adjust the PlayerPosition with the required offsets
AdjustedPosition := vector3{X:=PlayerPosition.X, Y:=PlayerPosition.Y - 200.0, Z:=PlayerPosition.Z + 100.0} # Create an AdjustedPosition vector with the specified offsets
# Debug print to verify position update
Print("Moving prop to position: {AdjustedPosition}, Rotation: {PlayerRotation}", ?Duration:=0.1) # Print the AdjustedPosition and PlayerRotation for debugging, with the message displayed for 0.1 seconds
# Move the PieceOfCode to the AdjustedPosition and PlayerRotation
spawn { PieceOfCode.MoveTo(AdjustedPosition, PlayerRotation, 0.1) } # Move the PieceOfCode to the AdjustedPosition and PlayerRotation with a time of 0.1 seconds using the spawn keyword to run asynchronously
FYI, I refactored the script to use TeleportTo… and it compiles, it runs, all prints show that it is working… and yet prop doesn’t move
this is the script refactored to use TeleportTo
using { /Fortnite.com/Devices } # Import the devices module from Fortnite for device-related classes and functions
using { /Fortnite.com/Characters } # Import the characters module from Fortnite for character-related classes and functions
using { /Verse.org/Simulation } # Import the simulation module from Verse for simulation-related classes and functions
using { /UnrealEngine.com/Temporary/SpatialMath } # Import the SpatialMath module from Unreal Engine for spatial and mathematical operations
# Define a class with editable prop and volume_device variables
snap_prop_to_player := class(creative_device): # Define a new class called snap_prop_to_player, inheriting from creative_device
@editable # Allow this property to be set from the editor
PieceOfCode:creative_prop = creative_prop{} # Define an editable property PieceOfCode of type creative_prop and initialize it
@editable # Allow this property to be set from the editor
VolumeTrigger:volume_device = volume_device{} # Define an editable property VolumeTrigger of type volume_device and initialize it
# Define an event handler for when a player enters the volume
OnBegin<override>()<suspends>:void= # Override the OnBegin method to define custom behavior when the game starts; <suspends> indicates the method can be paused
# Subscribe to the volume's EnteredEvent
VolumeTrigger.AgentEntersEvent.Subscribe(AttachToPlayer) # Subscribe the AttachToPlayer method to the AgentEntersEvent of the VolumeTrigger
AttachToPlayer(Agent : agent) : void = # Define the AttachToPlayer method, which takes an Agent of type agent and returns void
spawn { OnPlayerEntered(Agent) } # Use the spawn keyword to start the OnPlayerEntered method asynchronously
# Event handler function for when a player enters the volume
OnPlayerEntered(InPlayer:agent)<suspends> :void= # Define the OnPlayerEntered method, which takes an InPlayer of type agent and suspends its execution
if (FortniteCharacter := InPlayer.GetFortCharacter[]): # Use an if statement to attempt to get the FortniteCharacter from InPlayer; the := operator assigns the result if successful
Print("Player entered volume and attached!", ?Duration:=6.0) # Print a message indicating the player has entered the volume, with the message displayed for 6 seconds
loop: # Start a loop block, which runs indefinitely until explicitly broken or interrupted
Sleep(0.1) # Pause execution for 0.1 seconds to allow other processes to run
PlayerTransform := FortniteCharacter.GetTransform() # Get the Transform object from the FortniteCharacter and assign it to PlayerTransform
PlayerPosition := PlayerTransform.Translation # Extract the Translation (position) vector from PlayerTransform and assign it to PlayerPosition
PlayerRotation := PlayerTransform.Rotation # Extract the Rotation from PlayerTransform and assign it to PlayerRotation
# Adjust the PlayerPosition with the required offsets
AdjustedPosition := vector3{X:=PlayerPosition.X, Y:=PlayerPosition.Y - 200.0, Z:=PlayerPosition.Z + 100.0} # Create an AdjustedPosition vector with the specified offsets
# Debug print to verify position update
Print("Moving prop to position: {AdjustedPosition}, Rotation: {PlayerRotation}", ?Duration:=0.1) # Print the AdjustedPosition and PlayerRotation for debugging, with the message displayed for 0.1 seconds
# Create a new transform for the teleportation
NewTransform := transform{Translation:=AdjustedPosition, Rotation:=PlayerRotation} # Create a new transform with the adjusted position and rotation
# Teleport the PieceOfCode to the AdjustedPosition and PlayerRotation
if (PieceOfCode.TeleportTo[NewTransform]): # Use the TeleportTo method to teleport the PieceOfCode to the new transform
Print("Prop successfully teleported!", ?Duration:=0.1) # Print a success message
The script is not only compiiing, running and computing correctly… but it seems like it is trying to do something: it is as if prop is indeed being moved, but snaps back into place right after.
I would start by testing outside of the loop, for example see if you can call MoveTo just on the press of a button or something. I’m currently making a prop movement system and MoveTo functions correctly, so it is most likely your code structure or the reference to the prop you are moving. You can also use race: with the moveTo and put it against a Sleep() with longer duration to see if the moveto is completing in time, like this:
MoveTo indeed functions in cases like moving NPCs, but seems like there’s something, somewhere, in UEFN, not Verse, acting like an “anticheat” of sorts, snapping the Prop back to origin after the transform…
Being stubborn, I’m keeping iterating on the script, trying to make it as minimalist as possible…
for the record, this is where I am at
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
# This class defines a device that makes a cube follow the player
Draggable := class(creative_device):
@editable
Cube : creative_prop = creative_prop{}
@editable
Delay : float = 1.0 # delay between each movement in seconds
@editable
MinDistance : float = 200.0 # minimum distance to maintain from player
@editable
VolumeTrigger: volume_device = volume_device{}
# Runs when the device is started in a running game
OnBegin<override>()<suspends>:void=
Print("Device initialized and waiting for player to enter volume.", ?Duration := 6.0)
VolumeTrigger.AgentEntersEvent.Subscribe(TriggerWakeupAsync)
# Function to handle the event asynchronously
TriggerWakeupAsync(InPlayer:agent):void =
spawn{TriggerWakeup(InPlayer)}
# Async function that handles the logic when a player enters the volume
TriggerWakeup(InPlayer:agent)<suspends>:void =
if (FortCharacter := InPlayer.GetFortCharacter[]):
Print("Player entered volume and attached!", ?Duration := 6.0)
FollowPlayer(FortCharacter)
# Function to make the cube follow the player
FollowPlayer(Player:fort_character)<suspends>:void=
loop:
Sleep(Delay)
PlayerPosition := Player.GetTransform().Translation
CubePosition := Cube.GetTransform().Translation
Direction := NormalizeVector(PlayerPosition - CubePosition)
DistanceToPlayer := VectorDistance(PlayerPosition, CubePosition)
if (DistanceToPlayer > MinDistance):
TargetPosition := PlayerPosition - Direction * MinDistance
Cube.MoveTo(TargetPosition, Cube.GetTransform().Rotation, 0.1)
# Function to normalize a vector
NormalizeVector(Vector:vector3) : vector3 =
Magnitude := Vector.Length()
if (Magnitude > 0.0):
return Vector / Magnitude
else:
return Vector
# Function to calculate the distance between two vectors
VectorDistance(VectorA:vector3, VectorB:vector3) : float =
return (VectorA - VectorB).Length()
It compiles, runs in game… still, prop snaps backto original position immediately.
Odd.
I will keep working on it and report my findings here.
To keep track of my misery, this is a barebone version using TeleportTo:
Still, it seems to work but somehow prop seems to snap back to original position
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
# This class defines a device that makes a cube follow the player
FollowPlayerTeleportTo := class(creative_device):
@editable
Cube : creative_prop = creative_prop{}
@editable
VolumeTrigger: volume_device = volume_device{}
# Runs when the device is started in a running game
OnBegin<override>()<suspends>:void=
Print("Device initialized and waiting for player to enter volume.", ?Duration := 6.0)
VolumeTrigger.AgentEntersEvent.Subscribe(TriggerWakeupAsync)
# Function to handle the event asynchronously
TriggerWakeupAsync(InPlayer:agent):void =
spawn{TriggerWakeup(InPlayer)}
# Async function that handles the logic when a player enters the volume
TriggerWakeup(InPlayer:agent)<suspends>:void =
if (FortCharacter := InPlayer.GetFortCharacter[]):
Print("Player entered volume and attached!", ?Duration := 6.0)
FollowPlayer(FortCharacter)
# Function to make the cube follow the player
FollowPlayer(Player:fort_character)<suspends>:void=
loop:
PlayerPosition := Player.GetTransform().Translation
PlayerRotation := Player.GetTransform().Rotation
if (Cube.TeleportTo[PlayerPosition, PlayerRotation]):
Print("Cube teleported to player position.", ?Duration := 6.0)
else:
Print("Failed to teleport cube.", ?Duration := 6.0)
Sleep(1.0) # Adjust the delay as necessary
and this is the super simplified attempt to use MoveTo
Same results: compiles, runs in game, computes… still prop snaps back to original position.
Feels like a hardcoded limitation somewhere in UEFN. Would be nice to know if it is.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
# This class defines a device that makes a cube follow the player
FollowPlayerMoveTo := class(creative_device):
@editable
Cube : creative_prop = creative_prop{}
@editable
VolumeTrigger: volume_device = volume_device{}
# Runs when the device is started in a running game
OnBegin<override>()<suspends>:void=
Print("Device initialized and waiting for player to enter volume.", ?Duration := 6.0)
VolumeTrigger.AgentEntersEvent.Subscribe(TriggerWakeupAsync)
# Function to handle the event asynchronously
TriggerWakeupAsync(InPlayer:agent):void =
spawn{TriggerWakeup(InPlayer)}
# Async function that handles the logic when a player enters the volume
TriggerWakeup(InPlayer:agent)<suspends>:void =
if (FortCharacter := InPlayer.GetFortCharacter[]):
Print("Player entered volume and attached!", ?Duration := 6.0)
FollowPlayer(FortCharacter)
# Function to make the cube follow the player
FollowPlayer(Player:fort_character)<suspends>:void=
loop:
PlayerPosition := Player.GetTransform().Translation
PlayerRotation := Player.GetTransform().Rotation
Cube.MoveTo(PlayerPosition, PlayerRotation, 2.0)
Sleep(1.0) # Adjust the delay as necessary
Hmm I don’t think its a bug as I can get MoveTo with a creative prop to work fine, but I would suggest your next steps breaking your code down even further. Can you get a prop to moveto your player when the player just presses a button? Can you get Moveto to work in a separate project?
It works in other projects where I’m using it to move NPCs (where I trigger move to at a much slower tick, 1 or 3 seconds)
It works in the current project as long as I don’t introduce triggering it via volume (for example, this “works”)
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /Verse.org/Verse }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
# This class defines a device that makes a cube follow the player while maintaining a minimum distance
cube_follow_player_device := class(creative_device):
@editable
Cube : creative_prop = creative_prop{}
@editable
Delay : float = 0.1 # delay between each movement in seconds
@editable
MoveSpeed : float = 0.01 # movement speed
@editable
MinDistance : float = 3.0 # minimum distance to maintain from player
# Runs when the device is started in a running game
OnBegin<override>()<suspends>:void=
AllPlayers := GetPlayspace().GetPlayers()
# Check if there is at least one player
if (Player := AllPlayers[0]):
FollowPlayer(Player)
# Function to make the cube follow the player
FollowPlayer(Player:player)<suspends>:void=
loop:
Sleep(Delay)
# Get the player's character and position
if (FortniteCharacter := Player.GetFortCharacter[]):
PlayerPosition := FortniteCharacter.GetTransform().Translation
CubePosition := Cube.GetTransform().Translation
Direction := NormalizeVector(PlayerPosition - CubePosition)
DistanceToPlayer := VectorDistance(PlayerPosition, CubePosition)
Print("PlayerPosition: {PlayerPosition}, CubePosition: {CubePosition}, DistanceToPlayer: {DistanceToPlayer}")
# Check if the cube is farther than the minimum distance
if (DistanceToPlayer > MinDistance):
TargetPosition := PlayerPosition - Direction * MinDistance
Print("TargetPosition: {TargetPosition}")
InterpolateMoveCube(CubePosition, TargetPosition)
# Function to normalize a vector
NormalizeVector(Vector:vector3) : vector3 =
Magnitude := Vector.Length()
if (Magnitude > 0.0):
return Vector / Magnitude
else:
return Vector
# Function to calculate the distance between two vectors
VectorDistance(VectorA:vector3, VectorB:vector3) : float =
return (VectorA - VectorB).Length()
# Function to interpolate the cube's movement towards the target position
InterpolateMoveCube(StartPos:vector3, EndPos:vector3)<suspends>:void=
var InterpTime : float = 0.0
var Duration : float = 1.0 # Total time to interpolate based on speed
loop:
Sleep(0.1)
set InterpTime += 0.1 * MoveSpeed
if (InterpTime >= Duration):
Cube.MoveTo(EndPos, Cube.GetTransform().Rotation, 0.1)
return
var InterpPosition : vector3 = Lerp(StartPos, EndPos, InterpTime / Duration)
# Call MoveTo with a small delay to ensure movement
MoveCube(InterpPosition)
Print("InterpPosition: {InterpPosition}")
MoveCube(Position:vector3)<suspends>:void=
Cube.MoveTo(Position, Cube.GetTransform().Rotation, 0.1)```
and as soon as I introduce triggering via volume, it doesn't ! So weird!
NOT WORKING :
… NOT WORKING WHEN I introduce triggering on entering volume:
# Runs when the device is started in a running game
OnBegin<override>()<suspends>:void=
Print("Device initialized and waiting for player to enter volume.", ?Duration := 6.0)
VolumeTrigger.AgentEntersEvent.Subscribe(OnPlayerEnter)
# Function to handle the event when a player enters the volume
OnPlayerEnter(InPlayer:agent):void =
spawn{HandlePlayerEnter(InPlayer)}
HandlePlayerEnter(InPlayer:agent)<suspends>:void =
if (FortCharacter := InPlayer.GetFortCharacter[]):
Print("Player entered volume and attached!", ?Duration := 6.0)
FollowPlayer(FortCharacter)
# Function to make the cube follow the player
FollowPlayer(Player:fort_character)<suspends>:void=
loop:
Sleep(Delay)
# Get the player's character and position
PlayerPosition := Player.GetTransform().Translation
CubePosition := Cube.GetTransform().Translation
Direction := NormalizeVector(PlayerPosition - CubePosition)
DistanceToPlayer := VectorDistance(PlayerPosition, CubePosition)
Print("PlayerPosition: {PlayerPosition}, CubePosition: {CubePosition}, DistanceToPlayer: {DistanceToPlayer}")
# Check if the cube is farther than the minimum distance
if (DistanceToPlayer > MinDistance):
TargetPosition := PlayerPosition - Direction * MinDistance
Print("TargetPosition: {TargetPosition}")
InterpolateMoveCube(CubePosition, TargetPosition)
# Function to normalize a vector
NormalizeVector(Vector:vector3) : vector3 =
Magnitude := Vector.Length()
if (Magnitude > 0.0):
return Vector / Magnitude
else:
return Vector
# Function to calculate the distance between two vectors
VectorDistance(VectorA:vector3, VectorB:vector3) : float =
return (VectorA - VectorB).Length()
# Function to interpolate the cube's movement towards the target position
InterpolateMoveCube(StartPos:vector3, EndPos:vector3)<suspends>:void=
var InterpTime : float = 0.0
var Duration : float = 1.0 # Total time to interpolate based on speed
loop:
Sleep(0.1)
set InterpTime += 0.1 * MoveSpeed
if (InterpTime >= Duration):
Cube.MoveTo(EndPos, Cube.GetTransform().Rotation, 0.1)
return
var InterpPosition : vector3 = Lerp(StartPos, EndPos, InterpTime / Duration)
# Call MoveTo with a small delay to ensure movement
MoveCube(InterpPosition)
Print("InterpPosition: {InterpPosition}")
MoveCube(Position:vector3)<suspends>:void=
Cube.MoveTo(Position, Cube.GetTransform().Rotation, 0.1)
Good luck, because it breaks once the volume trigger is introduced I wonder if the problem is with the Agent reference supplied by the AgentEntersEvent