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

I’m trying to add stats to a player whenever they are continuously touching a button. They must be touching the button otherwise they don’t get any stats. My current code works, but it only works if the player is moving on the button. I want them to be able to stand still and still receive stats.

My current code:

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
			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("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)

I’ve tried replacing the

if player then

in the createButton function with

while player do
	task.wait(0.25)

but that just constantly runs even if the player only touches the button once and steps off of it.

First off, you need to make an infinite loop. Then, you need to make parts sorrounding the button and whenever the player touches them, it’ll break the loop.

I’m gonna say what @deluc_t recommended is doesnt work. Unless you clone the script, the loop will just break and its kinda hacky if you ask me, but I can’t say I know the best way.
You could try a Region3, or Part.TouchEnded, but I haven’t tested these.

Nevermind, should have waited a minute to post what I posted. Anyways, the reason why its not consistently firing like you want it to is because the .touched event relys on physics. When the players not moving, theres no physics to be detected. Found a devforum post about this exact problem through a quick google search with the right terms (How to detect if two parts are touching without Roblox Physics)
Theres a couple things recommended, but I personally recommend Region3, than check if the player is in the region everytime the part is touched, or something like that.

Ok thanks, I’ll check it out and get back to you.

TouchEnded exists. You don’t need parts around the original 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?