How do I check if a player touches a part with a specific name?

Ok, so a friend helped me out to get it functioning properly, the only issue I had is that I had to get the “Complete” parts outside of the levels and now it won’t say what level they just completed. Is there a way to make a StringValue to make it say which area (Level) they’re currently in?

I have soundRegion parts where it plays if ur inside the specific part, I was wondering if I could make it if they are touching that part, the StringValue gets updated to the LevelName.

Here’s the current code I have right now:

wait(1)
local levels = workspace:WaitForChild("Levels"):GetChildren()

local repStorage = game:GetService("ReplicatedStorage")
local remotes = repStorage:WaitForChild("Remotes")
local reset = remotes:WaitForChild("Reset")

local Transition = require( repStorage:WaitForChild("Client").Transition )

local debounce = false

local touchPart = script.Parent
local plr = game:GetService("Players")

for _, level in levels do
	if level:IsA("Folder") then print(level) continue end
		level.Complete.Touched:Connect(function(hit)
			if debounce == false then
				print("CompleteFunction Started")
				local player = plr:GetPlayerFromCharacter( hit.Parent )
				local name = hit.Parent.Name
				if ( not player ) then return end
				debounce = true
				-- do other stuff
				game:GetService("TextChatService").TextChannels.RBXSystem:DisplaySystemMessage(
					"<font color=\"rgb(137, 255, 129)\">[System]: "..name.." has completed "..touchPart.Parent.Name.."!</font> "
				)
				task.wait(2)
				Transition.Start()
				hit.Parent:FindFirstChild("Humanoid").Parent:MoveTo(Vector3.new(-76, 4.35, -14))
				task.wait(0.1)
				Transition.Out()
				
				task.wait(3)
				debounce = false
			end
	end)
end

I would love to really solve the issue of it just printing the Levels folder and actually print what level they in. Any info for that would be a great help.

Here is an image providing CompletePart locations, and the SoundRegion parts:
image

Ok, after more debugging, it seems to completely break its functionality when they try to attempt another Complete Part, going back seems to make that other one not work at all. Anyone help?

Is this also because I have StreamingEnabled for this? I have it enabled due to performance and disabling it breaks the entire game.

Looking at the video you provided, you teleport the player to the level whose portal they go into. You can update their current stage there. However, for the sake of organization, I would suggest putting the Complete parts inside of the folder of the stage they belong to:
image

This way, you can just check the name of the folder the part is parented to:

local plr = game:GetService("Players")
local repStorage = game:GetService("ReplicatedStorage")
local remotes = repStorage:WaitForChild("Remotes")
local reset = remotes:WaitForChild("Reset")
local Transition = require( repStorage:WaitForChild("Client").Transition)
local levels = workspace:WaitForChild("Levels")


for _, level in ipairs(levels:GetDescendants()) do
	if (not level:IsA("BasePart") or level.Name ~= "Complete") then -- Check if level is NOT a basepart OR does NOT have the name "Complete"
		continue -- We skip over this index
	end
	
	local stageName = level.Parent.Name -- Would be "Opposite Day" in this example
	local debounce = false

	level.Touched:Connect(function(hit)
		-- Complete part has been touched
		if debounce == false then
			print("CompleteFunction Started")
			local player = plr:GetPlayerFromCharacter(hit.Parent)
			local name = hit.Parent.Name
			if (not player) then return end
			debounce = true
			-- do other stuff
			game:GetService("TextChatService").TextChannels.RBXSystem:DisplaySystemMessage(
				"<font color=\"rgb(137, 255, 129)\">[System]: "..name.." has completed "..stageName.."!</font> "
			)
			task.wait(2)
			Transition.Start()
			hit.Parent:FindFirstChild("Humanoid").Parent:MoveTo(Vector3.new(-76, 4.35, -14))
			task.wait(0.1)
			Transition.Out()

			task.wait(3)
			debounce = false
		end
	end)
end 

As you previously mentioned, CollectionService can be used here too. If you select an instance and scroll to the bottom of the Properties window, you will see a Tags heading. You can create a tag for each Complete part, like so:
image

Once you create a tag, it will just show up in the drop menu whenever you click the plus button again and you can just select it from there:
image

Anyways, using this allows you to just iterate over a specified array of instances using CollectionService:GetTagged(). The parameter it takes is the name of the tag, which in the example above would be “CompletePart”:

local CollectionService = game:GetService("CollectionService")
local CompleteParts = CollectionService:GetTagged("CompletePart") -- Returns an array of all of the instances that have the tag "CompletePart"

Knowing this, we can use the array given by :GetTagged() instead of iterating over the entire Levels folder that has many different types of instances. This example also assumes that the Complete parts are parented to the folder they belong to:

local plr = game:GetService("Players")
local collectionService = game:GetService("CollectionService")
local repStorage = game:GetService("ReplicatedStorage")
local remotes = repStorage:WaitForChild("Remotes")
local reset = remotes:WaitForChild("Reset")
local Transition = require( repStorage:WaitForChild("Client").Transition)
local levels = workspace:WaitForChild("Levels")


for _, complete in ipairs(collectionService:GetTagged("CompletePart")) do
	local stageName = complete.Parent.Name -- Would be "Opposite Day" in this example
	local debounce = false

	complete.Touched:Connect(function(hit)
		-- Complete part has been touched
		if debounce == false then
			print("CompleteFunction Started")
			local player = plr:GetPlayerFromCharacter(hit.Parent)
			local name = hit.Parent.Name
			if (not player) then return end
			debounce = true
			-- do other stuff
			game:GetService("TextChatService").TextChannels.RBXSystem:DisplaySystemMessage(
				"<font color=\"rgb(137, 255, 129)\">[System]: "..name.." has completed "..stageName.."!</font> "
			)
			task.wait(2)
			Transition.Start()
			hit.Parent:FindFirstChild("Humanoid").Parent:MoveTo(Vector3.new(-76, 4.35, -14))
			task.wait(0.1)
			Transition.Out()

			task.wait(3)
			debounce = false
		end
	end)
end 

1 Like

This works beautifully! Only issue I have is once I transfer through another portal, it breaks. I do have StreamingEnabled so it loads the entire level and deloads everything else once I transfer there. It also breaks every other exit door that have CompletePart tag. How would I work around this so StreamingEnabled works with this? Like, is there a way that StreamingEnabled can ignore certain parts that cannot deload at all?

I also have this LocalScript under StarterPlayerScripts, unsure if that should be the correct spot but that’s where it has worked so far all the time.

Since StreamingEnabled loads the instances that are within a certain proximity of the player, the script may not account for the ones that are not there initially. That is what is causing that issue. Luckily, CollectionService has a listener that can be used to combat this. CollectionService:GetInstanceAddedSignal() is used to detect when an instance is given the tag, which is the parameter:

local CollectionService = game:GetService("CollectionService")
CollectionService:GetInstanceAddedSignal("CompletePart"):Connect(function()

end)

In the case for StreamingEnabled, this will run whenever the instance is loaded for that particular player. So we can transform the previous code into:

local plr = game:GetService("Players")
local collectionService = game:GetService("CollectionService")
local repStorage = game:GetService("ReplicatedStorage")
local remotes = repStorage:WaitForChild("Remotes")
local reset = remotes:WaitForChild("Reset")
local Transition = require( repStorage:WaitForChild("Client").Transition)
local levels = workspace:WaitForChild("Levels")

-- We change it to a function since we are calling it multiple times (just helps with readability and is good practice!)
local function onCompletePart(part)
	local stageName = part.Parent.Name -- Would be "Opposite Day" in this example
	local debounce = false

	part.Touched:Connect(function(hit)
		-- Complete part has been touched
		if debounce == false then
			print("CompleteFunction Started")
			local player = plr:GetPlayerFromCharacter(hit.Parent)
			local name = hit.Parent.Name
			if (not player) then return end
			debounce = true
			-- do other stuff
			game:GetService("TextChatService").TextChannels.RBXSystem:DisplaySystemMessage(
			"<font color=\"rgb(137, 255, 129)\">[System]: "..name.." has completed "..stageName.."!</font> "
			)
			task.wait(2)
			Transition.Start()
			hit.Parent:FindFirstChild("Humanoid").Parent:MoveTo(Vector3.new(-76, 4.35, -14))
			task.wait(0.1)
			Transition.Out()

			task.wait(3)
			debounce = false
		end
	end)
end

-- Detects when an instance is added (in our case loaded)
collectionService:GetInstanceAddedSignal("CompletePart"):Connect(onCompletePart)

 -- If there are parts that are initially in proximity, this will account for those
for _, complete in ipairs(collectionService:GetTagged("CompletePart")) do
	onCompletePart(complete)
end
1 Like

Oh my god, thank you so much this is amazing! Thank you so much for your help it works perfectly! Thank you for also explaining it in detail, really helps me understand it a lot more.
image

Many thanks!

1 Like

Before I finally celebrate fully, I was trying to add a difficulty tag and it seems to work fine. But apparently the StringValue tags only work only if they have not deloaded on the specific thing. Might be just a me thing but I am probably doing it in the most inconvenient way.

local plr = game:GetService("Players")
local collectionService = game:GetService("CollectionService")
local repStorage = game:GetService("ReplicatedStorage")
local remotes = repStorage:WaitForChild("Remotes")
local reset = remotes:WaitForChild("Reset")
local Transition = require( repStorage:WaitForChild("Client").Transition)
local levels = workspace:WaitForChild("Levels")

-- We change it to a function since we are calling it multiple times (just helps with readability and is good practice!)
local function onCompletePart(part)
	local stageName = part.Parent.Name -- Would be "Opposite Day" in this example
	local difficulty = part.Parent.Difficulty
	local colour = difficulty.Colour
	local r,g,b = math.floor(colour.Value.R * 255),math.floor(colour.Value.G * 255),math.floor(colour.Value.B * 255)
	local debounce = false

	part.Touched:Connect(function(hit)
		-- Complete part has been touched
		if debounce == false then
			print("CompleteFunction Started")
			local player = plr:GetPlayerFromCharacter(hit.Parent)
			local name = hit.Parent.Name
			if (not player) then return end
			debounce = true
			-- do other stuff
			game:GetService("TextChatService").TextChannels.RBXSystem:DisplaySystemMessage(
				"<font color=\"rgb(137, 255, 129)\">[System]: <b>"..name.."</b> has completed <b>"..stageName.."</b>!</font> <font color=\"rgb("..r..','..g..','..b..")\">["..difficulty.Value.."]</font> "
			)
			task.wait(2)
			Transition.Start()
			hit.Parent:FindFirstChild("Humanoid").Parent:MoveTo(Vector3.new(-76, 4.35, -14))
			task.wait(0.1)
			Transition.Out()

			task.wait(3)
			debounce = false
		end
	end)
end

-- Detects when an instance is added (in our case loaded)
collectionService:GetInstanceAddedSignal("CompletePart"):Connect(onCompletePart)

-- If there are parts that are initially in proximity, this will account for those
for _, complete in ipairs(collectionService:GetTagged("CompletePart")) do
	onCompletePart(complete)
end

It errors Difficulty is not a valid member of Complete, line 12

Would I have to add the Values inside the Complete Part?

I’m a bit confused on what exactly you’re asking for but I’ll make an assumption and if it’s wrong just correct me. If you wanted to get the color of the difficulty, we can just create a folder of each difficulty and put the stages under their respective difficulty:
image

This allows us to just reference the parent like we did before. Except this time, we’ll get the parent of the "Opposite Day" folder:

local stage = part.Parent -- Would be "Opposite Day" in this example
local difficulty = stage.Parent -- Would be "Easy" in this example

Instead of creating color values inside of each of these folders, we can just create a table – more specifically a dictionary:

local colors = {
	["Easy"] = Color3.new(0, 255, 0); -- Green
	["Medium"] = Color3.new(255, 255, 0); -- Yellow
	["Hard"] = Color3.new(255, 0, 0); -- Red
	-- You can add more here
    -- Template is: ["Difficulty"] = Color3.new(Value);
}

print(colors["Easy"]) -- This would print the color value of "Easy" (Green)

We can then reference this table and get the color we need:

local stage = part.Parent -- Would be "Opposite Day" in this example
local difficulty = stage.Parent -- Would be "Easy" in this example
local color = colors[difficulty.Name] or Color3.new(255, 255, 255) -- default if difficulty.Name is not found in colors dictionary
local r,g,b = color.R, color.G, color.B

All of that implemented into the previous code would be:

local plr = game:GetService("Players")
local collectionService = game:GetService("CollectionService")
local repStorage = game:GetService("ReplicatedStorage")
local remotes = repStorage:WaitForChild("Remotes")
local reset = remotes:WaitForChild("Reset")
local Transition = require( repStorage:WaitForChild("Client").Transition)
local levels = workspace:WaitForChild("Levels")

local colors = {
	["Easy"] = Color3.new(0, 255, 0);
	["Medium"] = Color3.new(255, 255, 0);
	["Hard"] = Color3.new(255, 0, 0);
	-- You can add more here
    -- Template is: ["Difficulty"] = Color3.new(Value);
}

-- We change it to a function since we are calling it multiple times (just helps with readability and is good practice!)
local function onCompletePart(part)
	local stage = part.Parent -- Would be "Opposite Day" in this example
	local difficulty = stage.Parent -- Would be "Easy" in this example
	local color = colors[difficulty.Name] or Color3.new(255, 255, 255) -- default if difficulty.Name is not found in colors dictionary
	local r,g,b = color.R, color.G, color.B
	local debounce = false

	part.Touched:Connect(function(hit)
		-- Complete part has been touched
		if debounce == false then
			print("CompleteFunction Started")
			local player = plr:GetPlayerFromCharacter(hit.Parent)
			local name = hit.Parent.Name
			if (not player) then return end
			debounce = true
			-- do other stuff
			game:GetService("TextChatService").TextChannels.RBXSystem:DisplaySystemMessage(
			"<font color=\"rgb(137, 255, 129)\">[System]: <b>"..name.."</b> has completed <b>"..stage.Name.."</b>!</font> <font color=\"rgb("..r..','..g..','..b..")\">["..difficulty.Value.."]</font> "
			)
			task.wait(2)
			Transition.Start()
			hit.Parent:FindFirstChild("Humanoid").Parent:MoveTo(Vector3.new(-76, 4.35, -14))
			task.wait(0.1)
			Transition.Out()

			task.wait(3)
			debounce = false
		end
	end)
end

-- Detects when an instance is added (in our case loaded)
collectionService:GetInstanceAddedSignal("CompletePart"):Connect(onCompletePart)

-- If there are parts that are initially in proximity, this will account for those
for _, complete in ipairs(collectionService:GetTagged("CompletePart")) do
	onCompletePart(complete)
end
1 Like

Shortly after I said that I was thinking of this but had no idea how I would execute this and this is exactly it. Thanks again!

1 Like


Nevermind, something broke here :slightly_frowning_face:

Nvm, fixed it! Thanks so much.

1 Like

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