Anti Character Void

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 :flushed:

2 Likes

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
1 Like

Something like this?

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! :smiley:
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.

1 Like

I’m actually concerned with what you’ve said here

Humanoid.FreeFalling will fire during falling and when landed, I tested jumping and it printed true then false. It also says in the wiki:

image

Or am I not getting something?

Well the event will fire twice, but the variable doesn’t update on the second time. Your loop will keep going forever.

1 Like

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.

1 Like

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.

2 Likes

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.

The velocity is negative while falling, positive velocity goes up.

Perhaps using (HumanoidRootPart.Velocity.Y) ~= 0 will do?

1 Like

@Hexcede proposed to use math.abs though which should return a positive value when the velocity is negative.

1 Like

Hang on, I’m blind. Did not see that when I was reading in broad daylight, but at least ~= 0 works.

1 Like

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.

Maybe because it was checked immediately after the signal. The case of scenario is when you start falling, the velocity is 0.

Try delaying slightly and see if it changes anything.

Wait, it does not have a PrimaryPart? Usually a character has their PrimaryPart HumanoidRootPart.

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.

I wonder if setting the velocity of all descendants to the character prevents the accelerating speeds. Try that too.

If all else fails, anchor the player after teleportation and delay their unanchoring for some time.

1 Like

Something is quite strange with this…

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.

Update:
Nope, still didn’t work.

Oh yeah, forgot to mention this is a local script. Perhaps some remote events will help?

Else you could possibly use a BodyPosition in the character which will move to a safe position in workspace.

1 Like

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.

Would Region3 be an option then? I’m not entirely sure how it affects the game in performance.