CollectionService in a nutshell

Hello! So, I’ve recently found many people having troubles related to duplicated code, and scripting lots of parts in their games and I thought that this simple tutorial could help those developers.

But first things first, what’s CollectionService? Well, CollectionService is a Service that can be used to manage groups of instances using tags, a set of strings that aren’t visible without using a plugin, we’ll get on that later.

CollectionService is very useful, since it allows us to run scripts or change properties of large group of parts without having to do boring and long loops. Learning how to use this Service will save us tons of lanes of code.

Let’s start by learning some basic functions about CollectionService, let’s create our first tag and let’s tag our first part.


But before starting with the functions, let’s set up our variables

local CollectionService = game:GetService("CollectionService") --The main service

local Part = Instance.new("Part", workspace) --The part that we will tag

:AddTag(instance, string)

CollectionService:AddTag(Part, "testTag")

Our first function is :AddTag() and It will basically tag an instance with the given tag, or, if the tag does not exist, :AddTag() will create a new tag, and then will tag the given instance.

But we can’t know if the part is actually tagged, because the tag is invisible, so let’s see the next function


:GetTags(instance)

CollectionService:AddTag(Part, "testTag")

print(CollectionService:GetTags(Part)) --> {"testTag"}

:GetTags() will return a table with all the tags of a part, so now, if you print the output of this function, It should print something like this:

sd

:GetTagged(string)

CollectionService:AddTag(Part, "testTag")

print(CollectionService:GetTagged("testTag"))

:GetTagged() is very similar to :GetTags(), but instead of returning the tags of an instance, it will return all the instances with a tag.

image

If we try to tag more parts, we will see that the table gets bigger

image


:RemoveTag(instance, string)

CollectionService:AddTag(Part, "testTag")

print(CollectionService:GetTags(Part))

CollectionService:RemoveTag(Part, "testTag")

print(CollectionService:GetTags(Part))

:RemoveTag(), removes a desired tag from an instance. And that’s all, as you can see in this example, if we print the tags of Part before removing them, we will get the table with testTag.

sd

But if we print the tags of Part after removing them, we will get an empty table

image


:HasTag(instance, string)

--// The rest of the code was cut just to save space 

CollectionService:AddTag(Part, "testTag")

if CollectionService:HasTag(Part, "testTag") then
	print("Success")
else 
    print("Not success")
end

This is getting spicy, :HasTag() is a very useful function of CollectionService, and it basically checks if an instance, has got a specified tag, if that instance has got the specified tag, :HasTag() will return true. In this case we’re checking if the Part has got "testTag" and if it is true, we will print “Success”.

image


:GetInstanceAddedSignal() & :GetInstanceRemovedSignal()

--// The rest of the code was cut just to save space 

CollectionService:GetInstanceAddedSignal("testTag"):Connect(function(Object)
    print(Object.Name.." was tagged with testTag")
end)

CollectionService:GetInstanceRemovedSignal("testTag"):Connect(function(Object)
    print(Object.Name.." got removed from testTag")
end)

CollectionService:AddTag(Part, "testTag") --// This will make the script print "Part was tagged with testTag"
CollectionService:RemoveTag(Part, "testTag") --// This will make the script print "Part got removed from testTag"

These 2 functions will fire the callback function when an instance is added/removed from a specified tag. The connected function will return the Instance that has been tagged/untagged as the first argument.


Now that we know all the functions, let’s see what we can do with this.

As said before, with CollectionService we can run codes or change properties of big groups of parts, how? Let’s take a look on how to do it.

So, Imagine that you have 3 parts and you want them to kill the player if it touches them, what would you do?

image

No! Never do that again, that’s time consuming and can even lead to problems.

image

Okay that’s better. In this situation, there are only 3 parts, so It would be very easy to get the 3 parts and connect them to a function, but imagine that instead of 3 parts, you have 500, uh, It wouldn’t be that easy to connect the 500 parts one by one. In this case, we can use CollectionService, which is way better than connecting each part one by one.

local CollectionService = game:GetService("CollectionService")

--// First, we will loop trough all the parts with the "killers" tag using a for loop.

for _, part in pairs(CollectionService:GetTagged("killers")) do
	
	--[[
	Now that we've got our killer parts, we're gonna bind them to a function, 
    so when they get touched, they will fire that function.
	--]]
	
	part.Touched:Connect(function(hit)
		--// Classic killing brick script, nothing very interesting
		
		if (hit.Parent:FindFirstChild("Humanoid")) then
			local humanoid = hit.Parent.Humanoid
			
			humanoid.Health = humanoid.Health - humanoid.MaxHealth
		end
	end)
end

And now we have our 3 functional killer parts, and everything in less than 25 lines of code and just using one script. The best thing of all is that we can easily change the script whenever we want and our parts will still work. Just imagine if you had to manage 300 killing bricks without CollectionService.

Well, maybe you’re thinking about using for loops to iterate through all the parts and connect them to a function, actually, that is what we did in the code above us, but there’s one little difference between using for loops and using CollectionService. If you wanted to use for loops to do this, you would have to give the parts a Key name or insert some sort of value into them so the script could know they are the correct parts, by using CollectionService, you can avoid those steps.

If you’re going to use CollectionService for your game, I really, really (just do it) recommend you installing Tag Editor Plugin, you can find a detailed explanation about it in the next paragraph.


Tag Editor Plugin

As I said before, @Sweetheartichoke’s plugin, Tag Editor Plugin, is basically a plugin that makes It easier & faster to manipulate tags on Roblox Studio.

If you want detailed information about the Plugin and you want to get it, check the original post linked above, but here I’m gonna show you the basics and how to use this plugin to make your life much more easier when using tags.

Let’s imagine I want to create a new tag for the killing parts, instead of creating a whole script using :AddTag() & looping through a folder or group of parts, I will open Tag Editor and I will type the name of my new tag

image

Press enter and… there it goes, your new tag without having to script nothing

image

Now that we have our tag, we just have to select the parts and apply that tag to the parts.

If you want to know if you really tagged your parts, you can check it out activating World View. (also from the Tag Editor Plugin).

image

And now you will be able to see an outline, or a box at all the parts tagged with the tag that you selected.

And now that you have your tags created, you can freely use them in your scripts, amazing!


Well, that’s all about CollectionService, hope It was useful. If you want to know more about the Tag Editor Plugin just go and check the official post and get it!

40 Likes

Thank you so much! You have no idea how useful this is to me, when my game has over 500 scripts…
A couple of suggestions for this tutorial:

  • Show us how to make a script for the parts (so not just an event)
  • Maybe check your grammar, but then again who cares?
1 Like

Gonna look in adding more examples :wink:

Sorry, but I’m from Spain and I did my best to do not use google translate :sweat_smile:

3 Likes

Hola, para saber los ganadores al terminar una ronda , podrías enseñar como hacerlo aplicando Collection Service :nerd_face:

Well my problem is that how do I run this with a object that is added to the game while the for loop is running like if I already have kill parts then I add another one with the tag it won’t work. How would I do that??

What I do in my projects is making a function called “UpdateTags” so everytime I know a new part is added I fire that function which fires again the for loop to connect all the new part/s.

1 Like

CAn you show me an example of this and also I don’t want mine to fire again for the parts already tagged.

local CollectionService = game:GetService("CollectionService")

local TagNames = {
	PadTag = "PadObject",
	JumpPad = "JumpPad",
	SpeedPad = "SpeedPad",
	MagnetPad = "MagnetPad",
}

local TagHandler = {}

function TagHandler.UpdateTags(group)
	if (typeof(group) == "Instance") then
		for _, object in pairs(group:GetDescendants()) do
			if (object:IsA("BasePart") and object:FindFirstChild("PadConfiguration")) then
				CollectionService:AddTag(object, TagNames.PadTag)

				if (object.PadConfiguration:FindFirstChild("Type") and type(object.PadConfiguration.Type.Value) == "string") then
					for _, name in pairs(TagNames) do
						if (object.PadConfiguration.Type.Value:match(name)) then
							CollectionService:AddTag(object, object.PadConfiguration.Type.Value)
						end
					end
				end
			end

			if (object:IsA("BasePart") and object:FindFirstChild("CanKill") and object.CanKill:IsA("BoolValue")) then
				CollectionService:AddTag(object, "CanKill")
			end
		end
	end
end

return TagHandler

That’s the code that I use in my project, basically what the code does is checking all the parts and looking into them for some sort of value with a name, if the script finds the value then that part is tagged.

An easier example is something like this:

function UpdateTagFunction(Tag)
   if Tag == "killBrick" then
       for _, part in pairs(game:GetService("CollectionService"):GetTagged(Tag)) do
          part.Touched:Connect(...)
      end
   end
end

If you have multiple tags you can do

function UpdateTagFunction(Tag)
   if Tag == "killBrick" then
      for _, part in pairs(game:GetService("CollectionService"):GetTagged(Tag)) do
          part.Touched:Connect(...)
      end
   elseif Tag == "otherTag" then
       --other thing
   end
end

Then you must create some sort of array containing the parts you recently tagged and only tag & connect the parts into the array

Thanks for everything… I’ll use this to fix my stuff.

do tag changes replicate client → server?

Tags will only replicate from the server to client, not from client to server.

1 Like

This was one explanation amongst many that I fully understood, thank you very much!