I created a local script that makes sure in the event a player’s character falls off the map, it will teleport to a particular place instead of respawning/dying(similar to @Haggie125’s Retail Tycoon) . I feel like I may need to do some additional steps to make my code work in all expected instances.
local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local function OnHumanoidFreeFalling(Active)
while Active == true do
if HumanoidRootPart.Position.Y < -100 then
print("Falling")
Character:SetPrimaryPartCFrame(CFrame.new(0,100,0)) --this position is not final
end
wait(0.1)
end
end
Humanoid.FreeFalling:Connect(OnHumanoidFreeFalling)
The code works as intended, but if a player finds a way to keep on falling, the velocity will keep on building up and the script won’t teleport the character in time (I’ve tested it). Can anyone suggest a proper setup?
Side Note:
My game is not reliant that if a player dies, something will break, I have covered that already, but as a feature of my game, as much as possible, I don’t want players to die.
I’m very inexperienced with characters and humanoids
This isn’t bad and properly positions the character, but rather than using the Active local you’ll need to check if the player is still falling… The local variable you have there will never update.
You could maybe do something like this to wait for their character to stop falling:
while math.abs(HumanoidRootPart.Velocity.Y) > 0 do
-- Stuff
wait(0.1)
end
local function OnHumanoidFreeFalling()
while math.abs(HumanoidRootPart.Velocity.Y) > 0 do
if HumanoidRootPart.Position.Y < -100 then
print("Falling")
Character:SetPrimaryPartCFrame(CFrame.new(0,100,0)) --this position is not final
end
wait(0.1)
end
end
Humanoid.FreeFalling:Connect(OnHumanoidFreeFalling)
That would work!
Any variables you receive through a function call are sort of just copies… If you change the passed variable it doesn’t change inside the function. And if you change the variable in the function it won’t change outsideof the function.
You can fix the speed issue pretty easily by putting a BodyForce inside the character, and giving it an upward force proportional to the characters downward velocity (in a loop). Effectively giving the character a terminal velocity.
There is one case where this can get you in trouble, which is if your character ends up getting flung towards the kill plane at a high velocity on a client’s machine that is struggling to get a perfect physics framerate. What can happen is that a small bit of lag can result in overcorrection, which goes into unstable (growing) oscillation. That is the particular peril you get when you specify a force or acceleration as a correction in a stepped physics simulation. You can’t use the time delta argument to Stepped or Heartbeat to mitigate it either, since it’s the future step’s duration that’s the problem. The safe option is to set the part Velocity or BodyVelocity, etc. When you deal with velocity, you’re safely one derivative away from the problem.
After further testing, it seems that your suggested method does not always work, however the loop will stop when necessary. There is a rare case when a player is falling, the FreeFalling event will trigger, but cannot get past this condition
while math.abs(HumanoidRootPart.Velocity.Y) > 0 do
I can conifrm that the velocity is greater than 0, but it still doesn’t work? I will look further into this, but I still don’t understand how this tends to fail.
I just tried the method you provided, however it tends to fail as well?
Code:
local Character = script.Parent
local Humanoid = Character:WaitForChild("Humanoid")
local HumanoidRootPart = Character:WaitForChild("HumanoidRootPart")
local function OnHumanoidFreeFalling()
print("Event Fired")
while HumanoidRootPart.Velocity.Y ~= 0 do
print("Active")
if HumanoidRootPart.Position.Y <= -50 then
print("Teleporting")
local Success, ErrorCode = pcall(function()
Character:SetPrimaryPartCFrame(CFrame.new(0,700,0))
end)
print(Success, ErrorCode)
end
wait(0.1)
end
end
Humanoid.FreeFalling:Connect(OnHumanoidFreeFalling)
Output:
Event Fired
Active
Teleporting
false Model:SetPrimaryCFrame() failed because no PrimaryPart has been set, or the PrimaryPart no longer exists. Please set Model.PrimaryPart before using this.
The character was already falling though, so it had maintained it’s velocity after teleporting.
It does, however since a condition does not get satisfied (or something else), the character dies instead of teleporting, hence the error gets thrown.
Edit:
I adjusted the fall height incase the velocity was an issue, however the method still tends to fail even if the character is evidently falling fast.
if HumanoidRootPart.Position.Y <= -50 then
print("Teleporting")
HumanoidRootPart.Anchored = true
In the code above, “Teleporting” is printed, but the HumanoidRootPart does not get anchored all the time? The character is not falling super fast to surpass anything.
Edit:
I was actually editing the script while the game was running (face palm), I’ll be back with updates.
After further analysis… it seems that the velocity will become 0 when a player hits a part at a certain speed and bounces up and falls down (this stops the loop) My best solution so far is to consider using an infinite loop or place parts under the map. The down side of these two alternatives is the performance.