Grid Based Connections

Hello, I’m LuaGirlDeveloper and I’ve been working on a Grid based game and I need feedback on my detection code.

And I need feedback on would this lag if I have a grid of 100x100?

        local Connection
		local FallConnection
		
		--// Detect Hit
		Connection = NewPart.Touched:Connect(function(Hit)
			local Player = Players:GetPlayerFromCharacter(Hit:FindFirstAncestorOfClass("Model"))
			if not Player then return nil end
			Connection:Disconnect()
			
			for Index = 1, #Colors do
				NewPart.BrickColor = Colors[Index]
				task.wait(0.25)
			end
			
			local FallTween = TweenService:Create(NewPart, NewPartTweenInfo, {CFrame = NewPart.CFrame * CFrame.new(0, -50, 0)})
			FallTween:Play()
			
			FallConnection = FallTween.Completed:Connect(function()
				NewPart:Destroy()
				FallConnection:Disconnect()
			end)
		end)

2 Likes

It likely could. It does sorta depend on how big each part of the grid is, the smaller the parts the more extreme performance issues.

The main issues you should try to address is having the code run independent of the 10000 Parts. 10k connections is not exactly… very healthy for the game and i believe a better approach would be for you to instead utilize the player character to detect whenever theire actually touching any of these parts. This would entirely remove the need to create 10k connections and still provide the same result. This would further optimize your code since technically within the scope of the code the player character would be present by default so you will no longer need to manually detect and search for the player character.
For this sort of approach you should be able to use CollectionService to provide every one of those parts with a special tag (said tag can be anything you want) in order to actually determine whenever or not whatever the player is touching/around is one of those 10k parts from the grid.

Another thing to note here is that your code is written in such a way that will force it to stack functions over and over every time one of those parts got touched. This happens due to each .Touched event creating a brand new “thread” and will NOT wait for any previously running code to finish. This “stacking” specifically happens because of that wait function inside the color for loop. During the waiting period, the same code can execute every time each part was touched causing the code to run multiple times over. This of course will result in pretty broken looking visuals along with heavily hurt performance.
What you can do here is create a way to check whenever or not any previously running code finished running or not. This can be as simple as creating a “IsFinished” boolean variable before the event connection and then checking whenever or not its true as the first line of the function. If its true then simply set it to false (meaning that now there IS running code) and set it back to true in that tween’s completed event.

Another simple optimization would be formatting that for loop differently. I believe you have a “Colors” table, yes? Well in that case you can simply instead for loop utilizing that table directly instead of needing to manually index each value.
Here’s the code for that:

for Index, Color in pairs(Colors) do
	NewPart.BrickColor = Color
	task.wait(0.25)
end

Looping through the table this way would be slightly faster and more cleaner mostly because again, you would not need to manually index through the Colors table.

How would I use CollectionService in this use? Like not to repeat .Touched and stuff?

If all of the 10k parts already exist within studio then you can simply select them, scroll down in the properties tab and take a look at the “Tags” section. You can insert a new tag to all 10k parts right there. If you generate these parts at runtime then you can use CollectionService’s “AddTag” method during the creation of every one of these parts.

As to how you could actually detect them, you could simply utilize the player charater’s left/right foot and check whatever it is touching. You can check whenever or not the object the foot touched is one of the grid parts by utilizing the “HasTag” method (of either CollectionService or that individual instance). If it does have the required tag then youre basically golden.

For example, like this?

local CollectionService = game:GetService("CollectionService")

local Connections = {}

local function MakeTile(Part)
	local Connection = Part.Touched:Connect(function()
		-- Code here
	end)
	
	Connections[Part] = Connection
end

for _, Object in pairs(CollectionService:GetTagged("Tile")) do
	MakeTile(Object)
end

CollectionService:GetInstanceAddedSignal("Tile"):Connect(function(Object)
	MakeTile(Object)
end)

CollectionService:GetInstanceRemovedSignal("Tile"):Connect(function(Object)
	if Connections[Object] then
		Connections[Object]:Disconnect()
	end
end)

Not quite, as ive said, my proposed solution relies on a singular (or two, if you want to use both feet) .Touched event directly coming from the player character’s foot.

Would this work?

local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")

local Connections = {}

local function MainLeg(Part)
	local Connection = Part.Touched:Connect(function(Hit)
		-- Code here
		print(Hit.Name)
	end)
	
	Connections[Part] = Connection
end

Players.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Character)
		local LeftLeg = Character:WaitForChild("Left Leg")
		local RightLeg = Character:WaitForChild("Right Leg")
		
		if LeftLeg and RightLeg then
			CollectionService:AddTag(LeftLeg, "Leg")
			CollectionService:AddTag(RightLeg, "Leg")
		end
	end)
end)

for _, Object in pairs(CollectionService:GetTagged("Leg")) do
	MainLeg(Object)
end

CollectionService:GetInstanceAddedSignal("Leg"):Connect(function(Object)
	MainLeg(Object)
end)

CollectionService:GetInstanceRemovedSignal("Leg"):Connect(function(Object)
	if Connections[Object] then
		Connections[Object]:Disconnect()
	end
end)

Sure. Though you dont need to create tags for the feet. You only need to create tags for the 10k tile parts. You can basically skip the entire CollectionService process for the legs. You only need CollectionService for the 10k parts. (For detecting them in the MainLeg .Touched event function)

I’m going to keep it like this because it will be better because the connections can be disconnected to prevent memory leaks.

1 Like

Thank you @XenoDenissboss1 for taking part of your day helping me!

1 Like

Before you go is this good for checking if the Player is still alive, has character?

local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")

local Connections = {}

local function MainLeg(Part)
	local Connection = Part.Touched:Connect(function(Hit)
		local IsTouchingPlayer = Players:GetPlayerFromCharacter(Hit:FindFirstAncestorOfClass("Model"))
		if IsTouchingPlayer then return nil end
		
		local OurPlayer = Players:GetPlayerFromCharacter(Part.Parent)
		if not OurPlayer then return nil end
		
		local Character = OurPlayer.Character
		if not Character then return end
		
		local Humanoid = Character:FindFirstChild("Humanoid")
		if not Humanoid then return end
		if Humanoid.Health < 0 then return end
		
		-- Touched Something
		print(Hit.Name)
	end)
	
	Connections[Part] = Connection
end

Players.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Character)
		local LeftLeg = Character:WaitForChild("Left Leg")
		local RightLeg = Character:WaitForChild("Right Leg")
		
		if LeftLeg and RightLeg then
			CollectionService:AddTag(LeftLeg, "Leg")
			CollectionService:AddTag(RightLeg, "Leg")
		end
	end)
end)

for _, Object in pairs(CollectionService:GetTagged("Leg")) do
	MainLeg(Object)
end

CollectionService:GetInstanceAddedSignal("Leg"):Connect(function(Object)
	MainLeg(Object)
end)

CollectionService:GetInstanceRemovedSignal("Leg"):Connect(function(Object)
	if Connections[Object] then
		Connections[Object]:Disconnect()
		Connections[Object] = nil
		print("Disconnect Legs")
	end
end)

Would this work for detecting if you hit the tile?

if CollectionService:HasTag(Hit, "Tile") then
	print(Hit.Name)
end

ONE LAST QUESTION! How can I implement this into my Round system?

@XenoDenissboss1 I have a question how can I implement this code into a round system?

local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")

local Connections = {}

local function MainLeg(Part)
	local Connection = Part.Touched:Connect(function(Hit)
		local IsTouchingPlayer = Players:GetPlayerFromCharacter(Hit:FindFirstAncestorOfClass("Model"))
		if IsTouchingPlayer then return nil end

		local OurPlayer = Players:GetPlayerFromCharacter(Part.Parent)
		if not OurPlayer then return nil end

		local Character = OurPlayer.Character
		if not Character then return end

		local Humanoid = Character:FindFirstChild("Humanoid")
		if not Humanoid then return end

		if Humanoid.Health > 0 then
			if CollectionService:HasTag(Hit, "Tile") then
				-- Do stuff here...
			end
		end
	end)

	Connections[Part] = Connection
end

Players.PlayerAdded:Connect(function(Player)
	Player.CharacterAdded:Connect(function(Character)
		local LeftLeg = Character:WaitForChild("Left Leg")
		local RightLeg = Character:WaitForChild("Right Leg")

		if LeftLeg and RightLeg then
			CollectionService:AddTag(LeftLeg, "Leg")
			CollectionService:AddTag(RightLeg, "Leg")
		end
	end)
end)

for _, Object in pairs(CollectionService:GetTagged("Leg")) do
	MainLeg(Object)
end

CollectionService:GetInstanceAddedSignal("Leg"):Connect(function(Object)
	MainLeg(Object)
end)

CollectionService:GetInstanceRemovedSignal("Leg"):Connect(function(Object)
	if Connections[Object] then
		Connections[Object]:Disconnect()
		Connections[Object] = nil
	end
end)

Yep.

Thats a little more complex to gauge. Theoretically you should be able to just reset the system every time you want to start/restart a round.

Like should I keep the Connections table?

And should I make it a function to disable and enable it?

How would I communicate to tell the tile to disapear?

Yeah.

Yeah.

If you mean to delete each tile then you can simply make some sort of function to just wipe them all.

Like should I make a module called TileClass and it handles things like a Table called CurrentTiles and when the player touches a tile it tells the TileClass to remove that tile and play the effect?

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