How to continuously add stats to a player while they are touching a part

What? Thats the point, for the loop to break. You then restart it when the player touches the button again.

You could use Region3 also, good point.

TouchEnded is unreliable, as if any part of the character stops touching the button it’ll think the user fully left the button.

if script.Parent.Part.Touched then
	while player do
		task.wait(1/4)
		game.Players.LocalPlayer.leaderstats["Your Currency Here"].Value = game.Players.LocalPlayer.leaderstats["Your Currency Here"].Value + ("Your Value Gain Here")
	end
end

(Some unlisted things will be added and modified to the script that I’m gonna post.)
(Also this is not what I mean tho to the script that I posted earlier before I edited it.)

So your script should be this:

local buttons = game.Workspace.Buttons.MultiplierButtons
local debounce = false
local Players = game.Players 
local player = Players.LocalPlayer

--[[Button variables]]
local button1 = buttons.Button1

local function createButton(button)
	while player do
		if player.leaderstats.Cash.Value >= button.Config.Price.Value then
			if debounce == false then
				debounce = true
				player.leaderstats.Cash.Value -= button.Config.Price.Value -- subtracts cash from player
				player.multiplier.Value += button.Config.MultiToAdd.Value * (1 + player.rebirths.Value) -- adds multiplier
				task.wait(0.25)
				debounce = false
			end
		else
			print("The player that pressed this button has broke, we're sorry")
		end
	end
end

button1.Button.Touched:Connect(function(hit)
	local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
	createButton(player, button1)
end)
1 Like

I’m stuck. I’ve tried almost everything you guys have suggested including TouchEnded, :GetPartsInPart(), :GetTouchingParts(), :Disconnect() and nothing seems to work. Or at least, I have no idea how to make it work. I tried doing the Region3 but since :FindPartsInRegion3() is deprecated, and I have no idea how to use :GetPartBoundsInBox(), I gave up on that path. Any help would be appreciated.

Try the script that I posted just for you.

I tried it and it didn’t work at all.

Do you mind showing us what your doing for these new scripts?

I tried something like this

local buttons = game.Workspace.Buttons.MultiplierButtons
local touching = false



--[[Button variables]]
local button1 = buttons.Button1


local touchingParts = button1.Button:GetTouchingParts()

local function createButton(touchedPart, button)
	if touchedPart:IsA("BasePart") then
		if touchedPart:FindFirstChildOfClass("Humanoid") then
			local player = game.Players:GetPlayerFromCharacter(touchedPart.Parent)
			if player then
				if player.leaderstats.Cash.Value >= button.Config.Price.Value then
					touching = true
					repeat task.wait(0.25)
						player.leaderstats.Cash.Value -= button.Config.Price.Value
						player.multiplier.Value += button.Config.MultiToAdd.Value * (1 + player.rebirths.Value)
						task.wait(0.25)
						touching = false
					until not touching
				else
					print("person is broke, sorry")
				end
			end
		end
	end
end


button1.Button.Touched:Connect(function(hit)
	local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
	createButton(hit, button1)
end)

button1.Button.TouchEnded:Connect(function(hit)
	touching = false
end)

I have tried this as well

local buttons = game.Workspace.Buttons.MultiplierButtons
local touching = false



--[[Button variables]]
local button1 = buttons.Button1


local touchingParts = button1.Button:GetTouchingParts()

local function createButton(button)
	for i,v in pairs(touchingParts) do
		if v:IsA("BasePart") then
			if v.Parent:FindFirstChild("Humanoid") then
				local player = game.Players:GetPlayerFromCharacter(v.Parent)
				if player ~= nil then
					if player.leaderstats.Cash.Value >= button.Config.Price.Value then
						touching = true
						repeat task.wait(0.25)
							player.leaderstats.Cash.Value -= button.Config.Price.Value
							player.multiplier.Value += button.Config.MultiToAdd.Value * (1 + player.rebirths.Value)
							task.wait(0.25)
						until not touching
					end
				end
			end
		end
	end
end


button1.Button.Touched:Connect(function(hit)
	local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
	createButton(button1)
end)

button1.Button.TouchEnded:Connect(function(hit)
	touching = false
end)

Also just going to add this here in case you had any questions on the hierarchy.
https://gyazo.com/7a9a85753454ca26428283048cdff34d

Few things im noticing here.
First off, and this could even be one of your main bugs, your using touchedpart:FindFirstChildOfClass("Humanoid") buuuuut thats gonna display nil. I went into studio and tested it myself. Instead you should do touchedpart.Parent:FindFirstChildOfClass("Humanoid")

Second, GetTouchingParts only works with parts that overlap with it. The player would have to be inside the part, this is why I recommended Region3 as it can almost be like a second part without being there. Also, GetTouchingParts doesnt update, you would have to call it each time if you were trying to use it to get the player.

Third, I don’t completely understand these lines

repeat task.wait(0.25)
	player.leaderstats.Cash.Value -= button.Config.Price.Value	
	player.multiplier.Value += button.Config.MultiToAdd.Value * (1 + player.rebirths.Value)
	task.wait(0.25)
	touching = false
until not touching 

As this seems contradictory, but im not sure how you have this working.
Id also like to note that part.TouchEnded (to my knowledge) only fires when the touching part leaves stops being next to the part. This seemed to work for me, maybe could you just try some like this?

local touched = false
local counter = 0

script.Parent.Touched:Connect(function(w)
touched = true
while touched == true do
counter += 1
wait(0.5)
end
end)

script.Parent.TouchEnded:Connect(function(part)
touched = false
print(counter)
end)

I’m not sure why this wouldn’t work.

And about what was said about .TouchEnded being unreliable, I disagree. The main argument being that it could think that the character is NOT touching the part. I dont believe this to be true, nor did it happen when I tested it out.

So this is what I have revised it to and now it’s working if the player is touching the button, but it only works while the player is moving around. There’s still a problem with the player standing still and not receiving any stats which would probably be fixed with a Region3.

local buttons = game.Workspace.Buttons.MultiplierButtons
local debounce = false

--[[Button variables]]
local button1 = buttons.Button1


local function createButton(player, button)
	if player then
		if player.leaderstats.Cash.Value >= button.Config.Price.Value then
			debounce = true
			while debounce == true do
				player.leaderstats.Cash.Value -= button.Config.Price.Value -- subtracts cash from player
				player.multiplier.Value += button.Config.MultiToAdd.Value * (1 + player.rebirths.Value) -- adds multiplier
				task.wait(1)
			end
		else
			print("person is broke, sorry")
		end
	end
end



button1.Button.Touched:Connect(function(hit)
	local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
	createButton(player, button1)
end)

button1.Button.TouchEnded:Connect(function(hit)
	debounce = false
end)

I tried using a Region3 but have never used it before. Hopefully you can point me in the right direction. I was looking at this post to try to figure it out: :GetPartBoundsInBox Help

Here’s my current attempt:

local buttons = game.Workspace.Buttons.MultiplierButtons
local debounce = false


--[[Button variables]]
local button1 = buttons.Button1

	
local filterObjects = {button1.Button, game.Workspace.Baseplate}
local boxPosition = button1.Button.CFrame
local boxSize = button1.Button.Size + Vector3.new(0,1,0)
local maxObjectsAllowed = 10
local params = OverlapParams.new(filterObjects,Enum.RaycastFilterType.Blacklist,maxObjectsAllowed,"Default")
local objectsInSpace = workspace:GetPartBoundsInBox(boxPosition,boxSize,params)

local function createButton(player, button)
	for i, v in pairs(objectsInSpace) do
		if v.Parent:FindFirstChild("Humanoid") then
			if player.leaderstats.Cash.Value >= button.Config.Price.Value then
				debounce = true
				while debounce == true do
					player.leaderstats.Cash.Value -= button.Config.Price.Value -- subtracts cash from player
					player.multiplier.Value += button.Config.MultiToAdd.Value * (1 + player.rebirths.Value) -- adds multiplier
					task.wait(1)
				end
			else
				print("person is broke, sorry")
			end
		end
	end
end


button1.Button.Touched:Connect(function(hit)
	local player = game:GetService("Players"):GetPlayerFromCharacter(hit.Parent)
	createButton(player, button1)
end)

button1.Button.TouchEnded:Connect(function(hit)
	debounce = false
end)

I realize that it fails because local objectsInSpace is only defined once the game runs, but I’m not sure how best to solve that. I tried putting in a while loop but it didn’t seem to really work. I have also tried defining it inside of the createButton function like so

local function createButton(player, button)
	local objectsInSpace = workspace:GetPartBoundsInBox(boxPosition,boxSize,params)

and it actually does work, but only if the player is moving.

The full script that I posted.

So, what script did you used?

This?

Or This?

You can use the touched event to fire a function which then runs a loop only once by using a debounce setup and then checks with GetPartsInPart, loops through parts found and adds the players to a table which then rewards then if none found exits the loop until someone else touches the button to start it. here is example of how below but you may need to fix or change your button variables

--local buttons = game.Workspace.Buttons.MultiplierButtons
local touching = false

--[[Button variables]]
local button1 = buttons.Button1
local playersTouching = {}  -- holds table of current players touching part so can loop and award currency


local overlapParams = OverlapParams.new()
overlapParams.MaxParts = 100
local Looping  -- used to see if while loop already running
local buttonDebounce  -- used for a small delay on button debounce after a player if found

function CheckPlayer()
	if Looping then return end
	Looping = true
	while task.wait(.25) do  -- loop to check if someone in bounds
		local PartsTouching = workspace:GetPartsInPart(button1, overlapParams)
		for i, part in pairs(PartsTouching) do
			local Player = game.Players:GetPlayerFromCharacter(part.Parent) -- see if player
			if Player and not table.find(playersTouching,Player) then
				table.insert(playersTouching, Player)
			end
		end
		if #playersTouching > 0 then
			for i, player in ipairs(playersTouching) do  -- may want to wrap this in pcall and do findfirstchild on the leaderstats etc
				if player.leaderstats.Cash.Value >= button1.Config.Price.Value then  -- may need to fix this variable for button here
					player.leaderstats.Cash.Value -= button1.Config.Price.Value
					player.multiplier.Value += button1.Config.MultiToAdd.Value * (1 + player.rebirths.Value)
				end
			end
			playersTouching = {}  -- clear the table for next loop to check again 
		else
			break   -- no players touching break out of loop for now
		end
	end
	Looping = nil
end


button1.Button.Touched:Connect(function(hit)
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	if player and not buttonDebounce then
		buttonDebounce = true
		delay(.5, function()  -- reset the debounce after delay
			buttonDebounce = nil
		end)
		CheckPlayer()
	end
end)

This is probably not the most effective or efficient way to do this you might can even use overlapParams filtering etc to make it better, maybe even collection service

They should probably use if game.Players:GetPlayerFromCharacter(hit.Parent) or game.Players:FindFirstChild(hit.Parent.Name)

I used the full script you posted and it didn’t work. There are some errors that I fixed like calling the function with 2 arguments when there is only 1 parameter, but still nothing. Also I’m not sure why you grab local player since I have the script in a folder in Server Script Service.

So I tried your script and it seems like it might work, but it still has some bugs. I tried to debug it using print statements and found out that the loop in the CheckPlayer() function only runs once for some reason. I think everything else runs fine.

1 Like

Actually figured it out, just needed to change

local PartsTouching = workspace:GetPartsInPart(button1, overlapParams)

to

local PartsTouching = workspace:GetPartsInPart(button1.Button, overlapParams)

because it was getting the folder, not the base part. It works now, thanks!

2 Likes

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