How to make it to where the ball doesn't fall through the floor if player is gone

I made it to where if you go by a soccer ball and you touch the hitbox it’ll stick to the player but i don’t really know how to check if the player is still there when it’s welded to them in case they disconnect or reset due to being stuck.

local PS = game:GetService("PhysicsService")
local RS = game:GetService("RunService")
local Players = game:GetService("Players")
local Player = Players.PlayerAdded:Wait()
local Character = Player.Character or Player.CharacterAdded:Wait()
local HRP = Character:FindFirstChild("HumanoidRootPart")
local RP = game:GetService("ReplicatedStorage")

local Ball = script.Parent
local BallHitBox = Ball.BallHitBox
local WeldToPlayer = Ball.WeldToPlayer

local Owner = nil



BallHitBox.Touched:Connect(function()
	if Owner ~= nil then return end
	
	for i,v in pairs(BallHitBox:GetTouchingParts()) do
		if v:IsDescendantOf(Character) then
			if not HRP then return end
			Owner = Player.Name
			Ball:SetNetworkOwner(Player)
			Ball.Massless = true
			Ball.CanCollide = false
			WeldToPlayer.Part0 = HRP
			WeldToPlayer.C0 = CFrame.new(0,-2.5,-2)
		end
	end
end)




You could try listening to the Destroying event of the player’s HRP.

e.g:

local PS = game:GetService("PhysicsService")
local RS = game:GetService("RunService")
local Players = game:GetService("Players")
local Player = Players.PlayerAdded:Wait()
local Character = Player.Character or Player.CharacterAdded:Wait()
local HRP = Character:FindFirstChild("HumanoidRootPart")
local RP = game:GetService("ReplicatedStorage")
local Ball = script.Parent
local BallHitBox = Ball.BallHitBox
local WeldToPlayer = Ball.WeldToPlayer
local Owner = nil

local RemoveConn = nil
BallHitBox.Touched:Connect(function()
	if Owner ~= nil then return end
	
	for i,v in pairs(BallHitBox:GetTouchingParts()) do
		if v:IsDescendantOf(Character) then
			if not HRP then return end
			if RemoveConn then RemoveConn:Disconnect() end -- prevent memory leaks

			Owner = Player.Name
			Ball:SetNetworkOwner(Player)
			Ball.Massless = true
			Ball.CanCollide = false
			WeldToPlayer.Part0 = HRP
			WeldToPlayer.C0 = CFrame.new(0,-2.5,-2)
			RemoveConn = HRP.Destroying:Once(function()
				-- Whatever processing you want here
				Ball.CanCollide = true
				Ball.Massless = false
			end)
		end
	end
end)

If you want to detect when the player leaves or when they reset then you should probably just use the player leave and join events. This is something that could work:

local PS = game:GetService("PhysicsService")
local RS = game:GetService("RunService")
local Players = game:GetService("Players")
local Player = Players.PlayerAdded:Wait()
local Character = Player.Character or Player.CharacterAdded:Wait()
local HRP = Character:FindFirstChild("HumanoidRootPart")
local RP = game:GetService("ReplicatedStorage")

local Ball = script.Parent
local BallHitBox = Ball.BallHitBox
local WeldToPlayer = Ball.WeldToPlayer

local Owner = nil

BallHitBox.Touched:Connect(function()
	if Owner ~= nil then return end

	for i,v in pairs(BallHitBox:GetTouchingParts()) do
		if v:IsDescendantOf(Character) then
			if not HRP then return end
			Owner = Player.Name
			Ball:SetNetworkOwner(Player)
			Ball.Massless = true
			Ball.CanCollide = false
			WeldToPlayer.Part0 = HRP
			WeldToPlayer.C0 = CFrame.new(0,-2.5,-2)
		end
	end
end)


local function ResetOwnership(PossibleOwner:Player)
	if not PossibleOwner or PossibleOwner.Name ~= Owner then return end
	
	--Do ball reset stuff here
end

Players.PlayerAdded:Connect(function(player: Player) 
	player.CharacterAppearanceLoaded:Connect(function(character: Model) 
		local Humanoid = character:FindFirstChildOfClass("Humanoid")
		
		Humanoid.Died:Once(function() 
			ResetOwnership(player)
		end)
	end)	
end)
Players.PlayerRemoving:Connect(ResetOwnership)

@SeargentAUS It’s probably not a good idea to use the destroying event of the player’s HRP because after the player resets, their dead body parts may lie there for a couple of seconds before getting destroyed. This might also cause weird behaviour with the ball anchored on them, so you want it to be immediate

1 Like

Didn’t seem to work it still falls through the floor whenever they reset. the only one that works is when they leave

local Players = game:GetService("Players")
local Player = Players.PlayerAdded:Wait()
local Character = Player.Character or Player.CharacterAdded:Wait()
local HRP = Character:WaitForChild("HumanoidRootPart")
local RP = game:GetService("ReplicatedStorage")

local Ball = script.Parent

local WeldToPlayer = nil
local Owner = nil

local function HasBall(Player)
	local Attribute = Player:GetAttribute("HasBall")
	return Attribute == true
end

local function GetDistance(Part1, Part2)
	local GrabDistance = (Part1.Position - Part2.Position).Magnitude 
	return GrabDistance
end


local function ResetOwnerShip(PossibleOwner: Player)
	if not PossibleOwner or PossibleOwner.Name ~= Owner then return end

	Owner = nil

	if PossibleOwner  then
		PossibleOwner:SetAttribute("HasBall", false)
	end

	if WeldToPlayer then
		WeldToPlayer:Destroy()
		WeldToPlayer = nil
	end

	Ball:SetNetworkOwner(nil)
	Ball.Massless = false
	Ball.CanCollide = true 
	Ball.CFrame = Ball.CFrame * CFrame.new(0,5,5)
end

task.spawn(function()
	while true do
		task.wait(0.2)
		for i,v in pairs(Players:GetPlayers()) do
			if Owner ~= nil then return end
			if GetDistance(Ball, HRP) <= 8 then
				Owner = Player.Name
				Player:SetAttribute("HasBall", true)
				Ball:SetNetworkOwner(Player)
				Ball.Massless = true
				Ball.CanCollide = false

				if WeldToPlayer then
					WeldToPlayer:Destroy()
				end

				WeldToPlayer = Instance.new("Motor6D",Ball)
				WeldToPlayer.Name = "BallMotor"
				WeldToPlayer.Part0 = HRP
				WeldToPlayer.Part1 = Ball
				WeldToPlayer.C0 = CFrame.new(0,-2.5,-2)
			end
		end
	end
end)

Players.PlayerAdded:Connect(function(player: Player)
	Player.CharacterAppearanceLoaded:Connect(function(Character)
		local Humanoid = Character:WaitForChild("Humanoid")

		Humanoid.Died:Connect(function()
			ResetOwnerShip(player)
		end)
	end)
end)

Players.PlayerRemoving:Connect(ResetOwnerShip)

I also tried to change up the code since i noticed that whenever another player joins they can’t get the ball only the first one who joined can

Okay i think i fixed the last part whenever someone else joins they can get the ball now i just need to fix the falling through still issue

Is the ball actually CanCollide true?
If not and it’s not welded to the player then it’ll just fall through the baseplate.
A simple colour change of the ball when it’s CanCollide true (green) or false (red) would give you a visual indication.

Try adding a print statement in the reset function to make sure it’s working properly… When the players humanoid dies, the event fires then it calls the function so it should be working. Also, why are you getting your player, player character, and HRP on the top of your script?

Used printing it works but it still doesn’t change can collide to true. Also to answer your question i forgot to get rid of that after i changed out the code to instead have it to where the ball will wield to the player after a certain distance instead of touching the hitbox since it wasn’t really consistent.

Mind sending your ball so i can check it out? The code shows that its unwelded and can collide so idk whats wrong

I just figured it out. I feel like an idiot right now. The problem was the fact that whenever the player died they could still get the ball so it kept on welding to them until they disappeared

local Players = game:GetService("Players")
local Ball = script.Parent

local WeldToPlayer = nil
local Owner = nil

local function HasBall(Baller: Player)
	local Attribute = Baller:GetAttribute("HasBall")
	return Attribute == true
end

local function GetDistance(Part1, Part2)
	local GrabDistance = (Part1.Position - Part2.Position).Magnitude 
	return GrabDistance
end


local function ResetOwnerShip(PossibleOwner: Player)
	if not PossibleOwner or PossibleOwner.Name ~= Owner then return 
	else
		print("It works", Owner, WeldToPlayer)

		Ball.Massless = false
		Ball.CanCollide = true
		Ball.CFrame = Ball.CFrame * CFrame.new(0,-2.5,-2)
		Ball:SetNetworkOwner(nil)

		Owner = nil

		if WeldToPlayer then
			WeldToPlayer:Destroy()
			WeldToPlayer = nil
		end

		if PossibleOwner then
			PossibleOwner:SetAttribute("HasBall", false)
		end
	end
end


task.spawn(function()
	while true do
		task.wait(0.1)
		for i,v in pairs(Players:GetPlayers()) do
			if v:IsA("Player") then
				local VC = v.Character or v.CharacterAdded:Wait()
				
				local VHRP = VC:FindFirstChild("HumanoidRootPart")
				
				if VC:FindFirstChildOfClass("Humanoid").Health == 0 then continue end
				
				if Owner ~= nil then continue end

				if GetDistance(Ball, VHRP) <= 10 then
					Owner = v.Name
					v:SetAttribute("HasBall", true)
					Ball:SetNetworkOwner(v)
					Ball.Massless = true
					Ball.CanCollide = false

					if WeldToPlayer then
						WeldToPlayer:Destroy()
					end

					WeldToPlayer = Instance.new("Motor6D",Ball)
					WeldToPlayer.Name = "BallMotor"
					WeldToPlayer.Part0 = VHRP
					WeldToPlayer.Part1 = Ball
					WeldToPlayer.C0 = CFrame.new(0,-2.5,-2)
				end
			end
		end
	end
end)

Players.PlayerAdded:Connect(function(player: Player)
	player.CharacterAppearanceLoaded:Connect(function(character: Model)
		local Humanoid = character:FindFirstChildOfClass("Humanoid")

		Humanoid.Died:Once(function()
			ResetOwnerShip(player)
		end)
	end)
end)

Players.PlayerRemoving:Connect(ResetOwnerShip)

That’s on me sorry.

2 Likes

It’s solved but there’s little comments I’ll make…

You don’t really need this check because you’re looping through a table of players

Don’t do this because you want to only consider players who have fully loaded in. Also, if a player is taking time loading their character it’ll yield your code

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.