.Touched Event causing lag on entering

Good day,
I am currently scripting a system for displaying the streetname of the street where the player is/the zone. For that I use a part whis is as big as the street with canCollide off and connect a .touched and .touchEnded function. It works fine when just walking in but if you are driving inside it with cars at some higher speed, it causes the player to lag. However I did insert a debounce but that does not work. Im open for any new methos for handling this, but I do not want to work with a module.

For reverence: v is the part
This is a Script inside workspace

local plrIDsTable = {}
local db = false
v.Touched:Connect(function(touchPart)
	if touchPart.Parent:FindFirstChildWhichIsA("Humanoid") and db == false then
		db = true
		local plr = game.Players:GetPlayerFromCharacter(touchPart.Parent)
		local plrID = plr.UserId
		if not table.find(plrIDsTable, plrID) then
			plr.PlayerGui.streetGUI.TextLabel.Text = v.Name
			table.insert(plrIDsTable, plrID)
		end
				
		task.wait(0.1)
		db = false
	end
end)
		
v.TouchEnded:Connect(function(touchPart)
	if touchPart.Parent:FindFirstChildWhichIsA("Humanoid") then
		local plr = game.Players:GetPlayerFromCharacter(touchPart.Parent)
		local plrID = plr.UserId
		if table.find(plrIDsTable, plrID) then
		    plr.PlayerGui.streetGUI.TextLabel.Text = " "
			table.remove(plrIDsTable, table.find(plrIDsTable, plr.UserId))
		end
	end
end)
1 Like

I believe using GetPartsInPart would be a better approach to this ( detect if for example, the humanoidrootpart is in this Part that has the shape of the street,zone, ecc…)

1 Like

Wouldnt I then need to require a heartbeat loop or sth?

2 Likes

well you could create a function that detects when the player is in that region (GetPartsInPart),and then , if it enters another region you will know that that the player is not in that zone anymore. This will work only if every street,zone in your map will have a “name” and a part to detect the player or whatever. so for example if there is a street with no part that detects whenever the players is in there, it will result that the players is in the previous street, which he isn’t.
(sorry for bad grammar…).

Yeah Ik, thats the same with the .Touched event. But as GetPartsInPart is not an Event, I would need a loop that detects the player right? Well and you can implement that on leave it goes away(in the for loop for getPartsInPart making a return if theres a catch and if it all goes trough, at the end of the function making the text empty).

Didn’t think about it. Then you could implement the .Touched event with what i said before (player in region, player goes into another region…) and then make a debounce system, so the .Touched event fires only once.

And how should it fix the problem? My thought was that the .Touched event gets triggered so fast and so much that it lags and with the touched event I already have the touchPart. With using the .Touched Event AND :GetPartsInPart I would have sort of doubled it. And as I said, I already have a debounce in it.

EDIT:
In studio, you do not notice the lag, however inside the roblox game, your cpu explodes when entering:

i meant to use only the touch event… This could fix the lag problem because if you do like i said in my previous replies (you use normally the .toched event. once the player is in that zone, use a variable to store in which zone the player is, and then, if the player goes into another zone, you will know that the player entered another zone, and is no more in the previous one; so now you can update the variable that stores the zone the player is in,and so on…) you will fire the .Touched event only once every time the player touches a zone. For example:

local Streets = {} -- this table stores all the parts that detects the player
for _,Parts in pairs(game.Workspace.SomeFolder:GetChildren()) do -- if you don't have your "detector parts" all in one parent (like this folder) you could use CollectionService
  table.insert(Streets,Parts) --inserts all the parts in the table
end
local CurrentPlayerStreet = workspace.SomeFolder.Street1



for _,DetectorPart in pairs(Streets) do --gets all the parts of the table
   DetectorPart.Touched:Connect(function()
		if DetectorPart == CurrentPlayerStreet then -- if the detector that got touched is the same as the one of the street the player is in, return.
			return
		else -- else, if it is a different part,
			print("Player is in another Street.Street name:"..DetectorPart.Name..";Last street:"..CurrentPlayerStreet.Name)
		CurrentPlayerStreet = DetectorPart -- sets the current player street to the one that got touched.
		 -- do your code
	    end
   end)
   
end

Edit: Otherwise , if the problem is the .Touched event being fired too many times, you could use any other way, but you will still need to check the street the player is in ,continuously, Unless you make a system that checks the street the player is in every 1,3,5 seconds, but if you make that time too high (Like 5 seconds) you will lack precision

Yeah so I edited my code with deleting the TouchEnded event, but it does still lag. (script.Parent is the folder where the streetdetectionparts are in). So would you say that I need to make a loop and then check every second if the player is inside the zone?

task.wait(1)

for i, v in pairs(script.Parent:GetChildren()) do
	if v:IsA("Part") or v:IsA("BasePart") then
		local db = false
		v.Touched:Connect(function(touchPart)
			if touchPart.Parent:FindFirstChildWhichIsA("Humanoid") and db == false then
				db = true
				local plr = game.Players:GetPlayerFromCharacter(touchPart.Parent)
				plr.PlayerGui.streetGUI.TextLabel.Text = v.Name
			end
			
			wait(0.1)
			db = false
		end)
	end
end

Yes, that could be a solution. in this code you wait .1 (don’t use wait, use task.wait() instead) seconds, and then the touched event fires again by making the debounce bool false again, so you didn’t solve anything. instead, you could use the system of my previous code (you could test the lag like that). Also, another solution could be to place two Detector Parts in every “entrance” of every street : one inside the street the player is, and after it, another one in the other street, and then detect which part is being touched (using my previous code system), so you know where the player is.For example:


If the player is in the red part, then it is in Street1, if it is in the green part, the player is in Street2,so like this, the parts are not touched continuously.However, if the players somehow finds a way to not touch these parts, and still get to another street, you would not know where the player really is till he doesn’t touch another Detector Part.

Just a small suggestion. This touch part will trigger with multiple touches. More so if the player moves while still on the trigger. You’re using a debounce technique here but, you’re not taking full advantage of it.

local db = true
v.Touched:Connect(function(touchPart)
	if db and touchPart.Parent:FindFirstChildWhichIsA("Humanoid") then db = false
      --
      task.wait(2)
      db = true 
    end
end)

Just a small change that helps your debounce work as fully intended.

One of my workarounds to TouchEnded…
ZonesSetup.rbxm (4.9 KB) --insert file

I like this one but it’s a bit hardcore most the time use two parts, one outside of the other with touched events. It can do many zones however…

That’s exactly what i said in my previous comment

Ya, I started when there was no replies. It took me a bit to find my Zones file. Seen what you said and removed most my post. If you look at what I left it’s not the same. It’s avoiding testing touchPart at all if db is false.

Did try that and still does not work. With adding print parts, I did saw that the debounce does not work and it prints many times behind. Is there maybe like another method with what I can detect the player? I would have use Region3 but that is deprecated… Oh and I did try changing it to a local script and that did nothing. When I am making the size of the block smaller however it does work, but is there really no other method than doing that?

That one is more for an area than a part. It’s set up with a module to handle many without having to run multiple loops to check them. If this is a part and it’s triggered by contact (Touched), set it up so you have two parts and the player can’t avoid touching the second one when leaving the first. Then you’re back to using just Touched, and that works perfectly.

The only real problem is that TouchEnded isn’t as reliable as you need it to be in this case.

Nah my problem is, that .Touched is lagging when entering the Part with a fast driving vehicle because there are many parts being detected at once. And I wonder if there is anything I can do or use another method, but still having a really zone

I have a race track with “waypoints”. They have to go through all of them for a lap to count.
All I did was set up large invisible blocks that stretch across the road. No lag problem like this.
Possibly you’re trying to do too many things in that moment. In my case I’m just adding to a count, then checking that count at the finish of the lap. TouchEnded isn’t a part of that script on purpose.

Using a touch event for this causes it to trigger tens of thousands of times using a loop to track what zone you are in via the client would be sufficient especially with streaming enabled. you will only have a few zones to check. Or you can do a

local touched

function touched()
Touched:Once(function(hit)
if game.Players:FindFirstChild(hit.Parent.Name) then
task.wait()
end
touched()
end)
end
touched()

This could throttle the touch connection to once per frame. Which wouldn’t work so well with a race track checkpoint for mine I used a touch connection and made sure that the car does not touch.
Or you could do a for loop and merely check the distance of each point in an array and determine which is in range and closest.

1 Like

Yes I also did think about this but then it would not be as accurate as my method. How did you set the touchEvent up, that cars do not touch? I mean the player is literally in the car. Your suggestion with limiting it to a frame will probably not work that good because every car part does also touch again every frame so the player will probably never be found (I think so). Can I maybe try to work with collision groups?

Yeah so I made it so the cars entire model does not touch besides the seat so I could use a simple touch event Touched:Connect(). Or you could add an exception to identify the car and thus the player in the car. Also enabling the option TouchEvents use Collision groups on the workspace could help but I’ve never tried it because I like to use the Collision Groups for things that do not collide. But again I’m not 100% on how that particular thing works. I created a touchevent module for a recent project and it looks like this.

--local touchevent=require(game.ReplicatedStorage.FashionShow.Utility.TouchedEvent)(handle,clothingprotocol,true,true)
return function(object,payload,playersonly,once)
	local init,touched=nil,nil
	local touchedevent=nil
	local onceperplayer={}
	function touched(hit)
		local humanoid=hit.Parent:FindFirstChild("Humanoid")
		if humanoid and onceperplayer[humanoid.Parent.Name]==nil then
			if once then onceperplayer[humanoid.Parent.Name]=true
			end 
			local player=nil
			if playersonly then
				player=game.Players:FindFirstChild(humanoid.Parent.Name)
				if player==nil then
					return nil
				end	
			end
			payload(humanoid,player,object)
		
		end
	end	
		object.CanTouch=true
		touchedevent=object.Touched:Connect(touched)
	return touchedevent
end

This is the strong touch event i used for the racetrack checkpoint.