Plugin: Components

componentHeader

Components is a brand new plugin that allows you to extend existing objects in your experience with custom behavior or functionality.

Those who have used other engines may be familiar with the concept already, but it’s a great way to create and re-use common components that make up your experience and share them with other developers.

Each component is represented by a BindableEvent which allows you to view them in the explorer window and interact with them from other components or systems via the Roblox API.

You can install the plugin by following this link or you can add it in Studio by searching for “Components” under the plugins section of the toolbox.

Features

The plugin currently supports the following:

  • Add custom behavior to instances in your project
  • Insert and view components in the explorer
  • Communicate directly between components and other systems
  • Custom icons to tell components apart

In the future, these features will be added:

  • Component benchmarking
  • ComponentService API for adding/removing and fetching different component types
  • Running components in Studio

Examples

Lava

The Lava component has a damage attribute which allows you customize how many times the player can touch the brick before they die.

local Component = {}

function Component:Initialize()
	self:SetAttribute("Damage", 50)
end

function Component:OnStart()
	self.touchedConnection = self.Parent.Touched:Connect(function (hit)
		local humanoid = hit.Parent:FindFirstChildWhichIsA("Humanoid")
		if humanoid and not humanoid:GetAttribute("Damaging") then
			humanoid:SetAttribute("Damaging", true)
			humanoid:TakeDamage(self:GetAttribute("Damage"))
			task.wait(1)
			humanoid:SetAttribute("Damaging", false)
		end
	end)
end

function Component:OnStop()
	self.touchedConnection:Disconnect()
end

return Component
Spinner

The Spinner components makes the part its parented to spin around a set number of times per second.

local Component = {}
local RunService = game:GetService("RunService")

function Component:Initialize()
	self:SetAttribute("Speed", 1)
end

function Component:OnStart()
	self.renderConnection = RunService.RenderStepped:Connect(function (step)
		local theta = math.pi * 2 * self:GetAttribute("Speed") * step
		self.Parent.CFrame *= CFrame.Angles(0, theta, 0)
	end)
end

function Component:OnStop()
	self.renderConnection:Disconnect()
end

return Component

Documentation

Component

Initialize()

Called the very first time a component is created. You should use this to setup the initial state of your component.

function Component:Initialize()
	self:SetAttribute("Example", true)
end

Lifecycle

Each component has a number of methods which are called throughout its lifecycle. Typically the lifecycle of a component looks like so:

OnAwake → OnEnable → OnStart → OnStop → OnDisable → OnDestroy

Generally speaking, all your code should go into OnStart and OnStop unless you want to run some code when the game isn’t running or before the component is enabled.

function Component:OnStart()
	print(self, "is running")
end

function Component:OnStop()
	print(self, "has stopped running")
end

OnAwake()

Called when the component has just been created

OnEnable()

Called when the component has been enabled but is not yet running

OnStart()

Called when the component starts running

OnStop()

Called when the component stops running

OnDisable()

Called when the component is no longer enabled

OnDestroy()

Called when the component is being removed

OnMessage(message, …)

Called when another script calls ‘Fire’ on the BindaleEvent instance.

function Component:OnMessage(message, ...)
	if message == "Shout" then
		print("HELLO WORLD!")
	end
end

Parent

Returns the parent instance of the component

self.Parent

Variables

Variables can be assigned to components directly, allowing you to maintain runtime variables.

function Component:OnStart()
	self.startTime = os.clock()
end

function Component:OnStop()
	print("Component was alive for", os.clock() - self.startTime)
end

GetAttribute(name)

Gets the attribute of the given name and returns its value

self:GetAttribute("Example")

SetAttribute(name, value)

Sets the attribute of the given name to the given value

self:SetAttribute("Example", true)

GetAttributes()

Returns a table of all of the components attributes

self:GetAttributes()

GetAttributeChangedSignal(name)

Returns an RBXScriptSignal which can be connected to, to listen for attribute changes.

self:GetAttributeChangedSignal("Example"):Connect(function ()
	-- do something
end)
ComponentService

Coming soon

Changelog

  • Added dev-forum link for documentation
37 Likes

i dont understand anything how to use it you can make a video?

2 Likes

I am currently putting a video together. I’ll be sure to share it here when it’s done :slight_smile:

1 Like

I have uploaded the video to YouTube and added it to the original post. If you still have any questions then send them my way and I’ll be happy to answer them

2 Likes

Ok ty upload video now i go watch

Seems like a great way to keep things more organized!

I made a chess game using the plugin. It’s open-source in case anyone wants to see it in action.

https://www.roblox.com/games/7835825439/Components-Demo-Chess

1 Like

i am creating a chess game but i don’t know how to do it i made chess i need script and camera

I’ve been using something like this in-house but it was all hardcoded values and created more clutter than it aimed to reduce.

It also had a less-than favourable syntax.

2 Likes

Out of curiosity, why did you opt to make this a plugin and not a module?

What’s the difference between using this versus the Tag Editor Plugin and CollectionService?

3 Likes

While it is possible to use the service without a plugin it would lead to a worse user experience. Adding the relevant attributes, tagging the instances, etc. are all things the user shouldn’t need to worry about when using components.

Now, that’s not to say I couldn’t release the service as a standalone module. If that is something people are interested so they could create their own tooling or for some other reason then I would definitely look into it.

1 Like

When it comes to components, I think of them as an expansion of Collection Service. Components uses collection service to manage tagged instances, but provides an easy to use framework for each tagged item.

2 Likes

@kingerman88 put it really well.

Under the hood there’s nothing going on that you couldn’t replicate with CollectionService. Components brings together a number of features such as tags, attributes, and the bindable API and provides you with a scripting environment that makes them all simple to use together.

2 Likes

What differ’s from Eltobb’s components?

I haven’t used Elttob’s component module myself. I suspect most of the differences stem from it being a module rather than a plugin. Both allow you to implement components into your game whereas this plugin also provides some additional functionality and an easy way to insert components at edit-time.

Just noticed components dont react to outside changes, I honestly think they should since it feels a bit pointless to have the properties in the window if they dont do anything after creation

What do you mean by outside changes?

Attributes can be retrieved at anytime and you’ll get the newest value. It’s directly calling the attributes API under the hood.

I have been watching this plugin being developed since 2021 sadly I think it didn’t continue to its full potential. I was eagerly waiting for it, especially for other features to come around like the ComponentService APIs. I wish this plugin will continue to be worked on. I fully support this.