This is a plugin for editing CollectionService tags. If you aren’t familiar with what that is, please read the wiki page and then continue reading this post: http://wiki.roblox.com/index.php?title=API:Class/CollectionService
This plugin allows you to create tags, and then assign them to objects in your game. You can also visualize and view a list of what objects have a given tag, and so on. It’s become an essential tool in many game developers’ toolboxes.
Why use CollectionService?
CollectionService allows you to avoid copying and pasting scripts throughout your game and avoid scanning the workspace for hardcoded names. It makes it easy to add scripted behaviors to objects created by level designers on a multi-disciplinary team.
By handling both the added and removed signals in your scripts, it makes it easy to write code that’s compatible with StreamingEnabled.
For example, in the old days someone might implement a kill brick by writing this Script and putting it inside their first kill brick:
script.Parent.Touched:Connect(function(part)
part:BreakJoints()
end)
Then they would copy and paste that kill brick thousands of times throughout their place. Then they later realize that the brick only breaks your legs off and doesn’t actually kill you when you jump up and down on it, and they want to replace it with this:
script.Parent.Touched:Connect(function(part)
local humanoid = part.Parent and part.Parent:FindFirstChild("Humanoid")
if humanoid then
humanoid.Health = 0
else
part:BreakJoints()
end
end
But now they have a dilemma, that they have thousands of copies of this script that all need to be individually updated. There are a few solutions to this problem today that are used:
- LinkedScripts, which have the issue that if you ever want to add a ModuleScript child or something, well, you just can’t.
- Scanning the entire data model for parts named “KillBrick” and attaching code to them, which is slow and is often done without accounting for new bricks being added after the game starts. It also means all of your parts are named after behavioral characteristics (that they kill you) rather than functional ones (hurdles, lava pits, etc.), which some developers further work around by inserting StringValues instead of relying on the part’s name.
CollectionService gets around this in an intuitive way. You’d write this script:
local CollectionService = game:GetService("CollectionService")
function makeKillBrick(part)
local data = {}
data.touchedConn = part.Touched:Connect(function(part)
part:BreakJoints()
end)
return data
end
function undoKillBrick(data)
data.touchedConn:Disconnect()
end
------------------------------------------------------------
local killBricks = {}
local addedSignal = CollectionService:GetInstanceAddedSignal("KillBrick")
local removedSignal = CollectionService:GetInstanceRemovedSignal("KillBrick")
local function onAdded(brick)
killBricks[brick] = makeKillBrick(brick)
end
local function onRemoved(brick)
if killBricks[brick] then
undoKillBrick(killBricks[brick])
killBricks[brick] = nil
end
end
for _,brick in pairs(CollectionService:GetTagged("KillBrick")) do
onAdded(brick)
end
addedSignal:Connect(onAdded)
removedSignal:Connect(onRemoved)
Then you can add a new tag to the tag editor like so, which level designers can then assign to objects in the world.
Then, when you realize later that the kill brick chops your legs off instead of actually killing you, you just change that one script.
By doing it this way, you able to dynamically tag and un-tag kill bricks whenever you like, and you can also assign multiple tags to a single part to create compound behaviors.
Note that about half of this snippet is code that can be extracted into a module script and shared between all of your game objects. For fans of OOP, you can also easily reimagine this into an object with a :destroy()
method, but I left it out for simplicity of the example. The Maid pattern also works excellently in this scenario.
Features
Completely rewritten
The old plugin was 500 lines in a single script file. The new plugin consists of over 5000 lines of code, and also uses Roact and Rodux.
Totally new UI design
I needed to redo the UI so that it’d work well as a PluginGui when that goes live.
When this feature goes live, the plugin will automatically begin using it.
Customizable icons and colors
As you can see in the above screenshot, every tag can have its own icon. These are selected from the FamFamFam Silk icon set, which is the same one used by Studio for the Explorer icons.
Icon Picker
Because the FamFamFam set has over 700 icons in it, I needed to create a nice UI for selecting them. So I created an interface with categories, search, and a preview window.
World View
The plugin offers built in visualization by selecting the “World View” button.
When you toggle this, it will show objects with tags depending on how you have them configured.
You can configure how each tag renders, with the following options:
- Selection box (filled or outline only)
- Floating icon
- Floating text label
- Sphere
- None
You can also quickly toggle a tag on and off by clicking the lightbulb button on the main tag list.
Enabling the world view also makes it so hovering a tagged object with your mouse will create a tooltip showing what tags it has. It also shows the name and class.
Color picker
The box and sphere display options display a colored box. As such, there is a color picker so you can select the color to use.
Instance view
The instance view shows a list of all of the instances with a given tag, which allows you to quickly select one or more of them. The selection syncs with Studio’s built in object selection.
Groups
Some developers have a bunch of tags that are all related in some way, so there is a grouping feature that allows you organize your tags. The groups can be expanded and collapsed.