Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
✓ ANSWER ACCEPTED

Touched not firing?

I'm trying to execute the code in the while loop in correspondence with the value of "active". However, it isn't running. The script is indeed enabled, and script.Parent is indeed a BasePart..

local active, author = false

script.Parent.Touched:connect(function(hit)
  if pcall(function() return hit.Parent.Humanoid end) then
    local player = game.Players:playerFromCharacter(hit.Parent)
    active, author = true, player
  end
end)

script.Parent.TouchEnded:connect(function()
  active, author = false
end) -- edit

while active and wait() do
  warn(author, '\n')
end

Probably a silly error, but i can't seem to figure out what it is.

2 comments

0

You're missing a closing parenthesis in this snippit. Where is it supposed to be?

0

right before the while loop, TouchEnded connection.

1 answer

✓ Accepted answer

There's no reason to have separate author and active variables, since active will always be the same as author ~= nil.

You shouldn't use pcall to do work for you. It's slow, complicated, and confusing. Write code that doesn't error instead of trying to cover it up. In this case, it's really, really easy to avoid that code:

local touching = nil

script.Parent.Touched:connect(function(hit)
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	if player then
		touching = player
	end
end)

Your code was missing a closing paren after the end on line 12.

script.Parent.TouchEnded:connect(function()
	touching = nil
end

The final while loop has a problem. Whenever touching became false, the loop would stop -- and not resume. If you want to something "whenever active is true" you have to loop forever and check if touching then:

while wait() do
	if touching then
		print(touching, "is touching me")
	else
		print("no one is touching me")
	end
end

There are a few caveats to this overall design:

  • Two players can't be touching it at the same time
  • If any part, not just the touching player stops touching the button, this stops

Both of these are a little difficult to solve.

You can more or less solve them using dictionaries:

local touching = {}

script.Parent.Touched:connect(function(hit)
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	if player then
		touching[player] = true
	end
end

script.Parent.TouchEnded:connect(function(hit)
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	if player then
		touching[player] = nil
	end
end

Instead of having a single "touching", we save the state more or less for all players using a dictionary.

You can get all of the players currently touching with a generic for loop:

while wait() do
	for player in pairs(touching) do
		print(player, "is touching")
	end
end

One problem with this is if the TouchEnded event doesn't fire. I believe this will happen if, for instance, the player leaves or despawns. It would be safest to also ensure that the original part survived. Thus, instead of using true, we'll save hit:

script.Parent.Touched:connect(function(hit)
	local player = game.Players:GetPlayerFromCharacter(hit.Parent)
	if player then
		touching[player] = hit
	end
end

and we'll delete "dead" touches in the loop:

	for player, part in pairs(touching) do
		print("player is touching")
		if not part.Parent then
			-- The part no longer exists, so forget about this player
			touching[player] = nil
		end
	end

This is still a little lacking -- if you stand on the button with one leg, and the other brushes against it, that TouchEnded will say you are no longer pressing the button. Ideally, we would only worry about the final touch.

We could use a dictionary, or just keep track of a count, adding 1 for a touch and subtracting for a touch ended.

1 comment

0

makes, sense. Thanks.

This discussion is preserved as it was. New answers, comments, and votes are closed.