Touched Event only triggering once

  1. What do you want to achieve? I want to make my touched event fire multiple times

  2. What is the issue? The issue is, that it only fires once

  3. What solutions have you tried so far? I tried just moving the Trigger Part but that doesnt work either

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local AreasFolder = game.Workspace:WaitForChild("Areas")
local StartFolder = AreasFolder:WaitForChild("Start")

local Trigger = StartFolder:WaitForChild("Trigger")
local Foundation = StartFolder:WaitForChild("Foundation")
local Decider = StartFolder:WaitForChild("Decider")

local CurrentDecider = Decider
local CurrentTrigger = Trigger
local CurrentFoundation = Foundation

local alrhit = true

CurrentTrigger.Touched:Connect(function(hit)
	if hit.Parent.HumanoidRootPart then
		if game.Players:GetPlayerFromCharacter(hit.Parent) then
			local leaderstats = game.Players:GetPlayerFromCharacter(hit.Parent).leaderstats
			local Stage = leaderstats.Stage
			local TopStage = leaderstats:FindFirstChild("Top Stage")
			
			if CurrentTrigger:GetAttribute("AlreadyHit") == false then
				CurrentTrigger:SetAttribute("AlreadyHit", true)
				Stage.Value += 1
				if TopStage.Value < Stage.Value then
					TopStage.Value = Stage.Value
				end
				
				local NewStageFolder = Instance.new("Folder", AreasFolder)
				NewStageFolder.Name = tostring(Stage.Value)
				
				local OldFoundation = CurrentFoundation
				CurrentFoundation = OldFoundation:Clone()
				CurrentFoundation.Parent = NewStageFolder
				CurrentFoundation.Position = OldFoundation.Position + Vector3.new(0, 0, 60)
				
				local OldTrigger = CurrentTrigger
				CurrentTrigger = OldTrigger:Clone()
				OldTrigger:Destroy()
				CurrentTrigger.Parent = NewStageFolder
				CurrentTrigger.Position = OldTrigger.Position + Vector3.new(0, 0, 60)

				local OldDecider = CurrentDecider
				CurrentDecider = OldDecider:Clone()
				CurrentDecider.Parent = NewStageFolder
				CurrentDecider.Position = CurrentFoundation.Position + Vector3.new(0, 0, CurrentFoundation.Size.Z / 2)
				
				wait(0.75)
				CurrentTrigger:SetAttribute("AlreadyHit", false)
			end
		end
	end
end)

Thank you for your time and for helping!

2 Likes

Are you sure it only fires once, or the code only works once?

Change that to:

if CurrentTrigger:GetAttribute("AlreadyHit") ~= true then

You are not setting index prior to that+this simple change of logic in debounce would be a bit more simpler.

Consider making closure instead of attributes for better replication & perfomance

1 Like

Parts needs to be out of their hitbox to be Touched again.

1 Like

You are binding a .Touched event to the CurrentTrigger, but later on you assign the variable “OldTrigger” to CurrentTrigger and then destroy the OldTrigger. This means that the original CurrentTrigger has now been deleted, so it no longer has the .Touched connection. Even though you cloned the old CurrentTrigger, you never assigned a new Touched connection to it, so there is no connection to be fired again.

4 Likes

Yeah no so I would recommend switching your current if statements.

FROM:

if CONDITION then
   ... -- code
end

TO:

if not CONDITION then
   -- replace return with continue/break if needed
   return print("...") -- use a print statement with the reason why it is not valid
end
... -- code

For reference this would allow you to debug easier and makes your code more readable, else use this video as reference.

ALSO the actual issue is that you delete the current trigger (lets call this trigger 0), now you clone trigger 0 (this clone will be called 1), you delete trigger 0.
You did NOT create a .Touched event on trigger 1.

FINAL note, use task.wait() rather than wait(), it is twice as accurate (there are many devforum posts regarding this).

1 Like

Thank you for those tips. I applied your changes and also changed, that the old Trigger won’t be destroyed but just moved. I noticed, that the problem might be the Attribute since it doesn’t change back to false somehow.

Here is the updated script:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local AreasFolder = game.Workspace:WaitForChild("Areas")
local StartFolder = AreasFolder:WaitForChild("Start")

local Trigger = StartFolder:WaitForChild("Trigger")
local Foundation = StartFolder:WaitForChild("Foundation")
local Decider = StartFolder:WaitForChild("Decider")

local CurrentDecider = Decider
local CurrentFoundation = Foundation

Trigger:SetAttribute("AlreadyHit", false)

Trigger.Touched:Connect(function(hit)
	if not hit.Parent.HumanoidRootPart then
		warn("No HumanoidRootPart found from: " .. hit.Name)
	else
		if not game.Players:GetPlayerFromCharacter(hit.Parent) then
			warn("Did not get player form hit: " .. hit.Name)
		else
			local leaderstats = game.Players:GetPlayerFromCharacter(hit.Parent).leaderstats
			local Stage = leaderstats.Stage
			local TopStage = leaderstats:FindFirstChild("Top Stage")

			if not Trigger:GetAttribute("AlreadyHit") then
				warn("Attribute is false, Event fired!")
				Trigger:SetAttribute("AlreadyHit", true)
				Stage.Value += 1
				if TopStage.Value < Stage.Value then
					TopStage.Value = Stage.Value
				end

				local NewStageFolder = Instance.new("Folder", AreasFolder)
				NewStageFolder.Name = tostring(Stage.Value)

				local OldFoundation = CurrentFoundation
				CurrentFoundation = OldFoundation:Clone()
				CurrentFoundation.Parent = NewStageFolder
				CurrentFoundation.Position = OldFoundation.Position + Vector3.new(0, 0, 60)

				--[[local OldTrigger = CurrentTrigger
				CurrentTrigger = OldTrigger:Clone()
				OldTrigger:Destroy()
				CurrentTrigger.Parent = NewStageFolder]]
				Trigger.Position += Vector3.new(0, 0, 60)

				local OldDecider = CurrentDecider
				CurrentDecider = OldDecider:Clone()
				CurrentDecider.Parent = NewStageFolder
				CurrentDecider.Position = CurrentFoundation.Position + Vector3.new(0, 0, CurrentFoundation.Size.Z / 2)

				Trigger:SetAttribute("AlreadyHit", false)
			else
				warn("Attribute AlreadyHit: " .. tostring(Trigger:GetAttribute("AlreadyHit")))
			end
		end
	end
end)

This is actually the answer. You should just be able to not clone the trigger, and it will start working. Why don’t you just move the original trigger instead of cloning?

1 Like

I do not clone it anymore. Watch the script above. It still doesn’t change itself to false.

Well I don’t see why that would happen. In the same scope that you set it to true, you also set it to false. So that’s impossible given the code you have provided, the error must be somewhere else.

try this simplified version of your script:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local AreasFolder = game.Workspace:WaitForChild("Areas")
local StartFolder = AreasFolder:WaitForChild("Start")

local Trigger = StartFolder:WaitForChild("Trigger")
local Foundation = StartFolder:WaitForChild("Foundation")
local Decider = StartFolder:WaitForChild("Decider")

local CurrentDecider = Decider
local CurrentFoundation = Foundation


Trigger.Touched:Connect(function(hit)
	if not hit.Parent.HumanoidRootPart then return end

	local plr = game.Players:GetPlayerFromCharacter(hit.Parent)

	if not plr then return end
		
	local leaderstats = plr.leaderstats
	local Stage = leaderstats.Stage
	local TopStage = leaderstats:FindFirstChild("Top Stage")

	if Trigger:GetAttribute("AlreadyHit") then return end
	
	Trigger:SetAttribute("AlreadyHit", true)

	Stage.Value += 1
	if Stage.Value > TopStage.Value then TopStage.Value = Stage.Value end

	local NewStageFolder = Instance.new("Folder", AreasFolder)
	NewStageFolder.Name = tostring(Stage.Value)

	local OldFoundation = CurrentFoundation
	CurrentFoundation = OldFoundation:Clone()
	CurrentFoundation.Parent = NewStageFolder
	CurrentFoundation.Position = OldFoundation.Position + Vector3.new(0, 0, 60)

	CurrentTrigger.Parent = NewStageFolder
	Trigger.Position += Vector3.new(0, 0, 60)

	local OldDecider = CurrentDecider
	CurrentDecider = OldDecider:Clone()
	CurrentDecider.Parent = NewStageFolder
	CurrentDecider.Position = CurrentFoundation.Position + Vector3.new(0, 0, CurrentFoundation.Size.Z / 2)

	Trigger:SetAttribute("AlreadyHit") -- delete the attribute
end)

if that doesn’t work, the error truly is somewhere else

Same Problem just without debugging now. But attribute still doesn’t change to false/doesn’t delete itself

Okay I figured it out. The Problem was, that I set the Position of the Model (CurrentDecider) which was not possible. I fixed it by moving all the Parts inside of the Model manually.

Just so you know doing that is not really very good for perfomance
image
Even if it still returns void it could cause some internal AOT problems.

1 Like

are you saying that returning a nil value is bad for performance? I am missing your point sorry

EDIT: I have learned about AOT issues, but I still would like to know how this can cause them? Shouldn’t this be equivalent to returning nil since print always returns a nil value?

Nil != ()

Character limit

Is there anywhere I can read more about this? If () is not equivalent to nil, why does this happen?

image

() is equivalent to nullptr in C++ or NULL in C, as far as I know.
That’s common knowledge. Also, the screenshot you provided makes no sense and proves nothing. Luau, on a core level, has overload for nullptr, obviously to not expose vulnerability.
Proof of action:
tostring() → errors
tostring(nil) → doesn’t error
Also print(tostring(print())) would error btw becouse it returns nullptr (glorified (void)NULL)

Thank you for explaining, but you didn’t have to be rude. I am simply trying to learn

And that definitely isn’t common knowledge for everyone dude, i’ve been programming on roblox for at least 5 years now. I’ve touched C++ maybe twice in my life

Where i were rude?Never meant to be rude, eleborate.

this is the part that seemed rude. I feel like my thought process was a little clear. Lua interpreted the return value of print as nil, so i was wondering where the true difference was