If you are using Wally, you can just install an earlier version (“sleitnick/component@1.1.0”), If not, I could send you the older version if you would like.
Well, the module wouldn’t update unless you insert it back from the toolbox
Here is the Auto function that is in the older version of Component:
--[=[
@param parent Instance
@return RBXScriptConnection
Scans all descendants of `parent` and loads any ModuleScripts found, then
calls `Component.new` on those loaded modules.
Each component module class must have a `Tag` string property to map it
to the proper tag.
]=]
function Component.Auto(parent)
local function Setup(moduleScript)
local m = require(moduleScript)
assert(type(m) == "table", "Expected table for component")
assert(type(m.Tag) == "string", "Expected .Tag property")
Component.new(m.Tag, m, m.RenderPriority, m.RequiredComponents)
end
for _,v in ipairs(parent:GetDescendants()) do
if v:IsA("ModuleScript") then
Setup(v)
end
end
return parent.DescendantAdded:Connect(function(v)
if v:IsA("ModuleScript") then
Setup(v)
end
end)
end
Trying to run this function with the new version on Component will not work now though as Component.new() now takes in new parameters, and a class like the old one took in is not one of them.
It seems to have changed indeed. I would join the Roblox OSS Discord and ask it in #knit. The creator of the framework is quite active in the chat. You can find an invite in the footer of the Rojo home page.
Component.Auto() was removed in favor of manually requiring the components in Knit’s bootstrap code like so:
Knit:Start():andThen(function()
for i, component in pairs(script.Parent.Components:GetChildren()) do
if component:IsA("ModuleScript") then
require(component)
end
end
end):catch(warn)
What’s the point of using the Component Util if I just can use CollectionService myself and save the hassle? It seems like more work unless the Components can be seen via the client and vice versa, I see no reason to use it.
This is true but with Knit Components you have metatables which is nice to have in a component. When you do it normally with CollectionService it is not as powerful. Obviously there is ways to have metatables with the “normal” way but in this case Knit does it for you so you don’t have to do all the extra stuff.
And tbh its not that much code, it may even be less than if you are doing it with CollectionService
local Component = require(ReplicatedStorage.Packages.Component)
local MyComponent = Component.new({
Tag = "MyComponent";
})
function MyComponent:Construct()
-- New Component
end
function MyComponent:Stop()
-- Component Destroyed
end
return MyComponent
Typically when I use components they act as singletons, It’s just a weird way to look at it for me since I’m using to calling Object.new() instead of Object:Construct()
Is there any getting started/tutorial related to the current version of Components? I can’t find anything which tells me how to use the current version, and the docs have been cropped down to basically a list of methods.
Not that I know of, I honestly don’t use components because I use inheritance and I don’t know how to do that with components.
I figured out how to use components through trial an error as the documentation is pretty much non-existent. But it was well worth it; I now use components all the time. It’s actually much simpler to use than it appears. Here’s a quick start guide:
I load all the components after the Knit server has started like this:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Knit = require(ReplicatedStorage:WaitForChild("Packages"):WaitForChild("knit"))
local Components = script.Parent:WaitForChild("Components") -- PUT YOUR OWN PATH TO COMPONENTS FOLDER!
Knit.Start():andThen(function()
Knit.Components = {}
for _, c in pairs(Components:GetChildren()) do
Knit.Components[c.Name] = require(c)
end
end):catch(warn)
You could just require each component, but for me it’s useful to be able to access them all in one place, so I store the required components into a new “Components” variable on the Knit instance.
Then create components into the Components
folder, such as Health.lua
:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Component = require(ReplicatedStorage:WaitForChild("Packages"):WaitForChild("component"))
local Health = Component.new({
Tag = "Health",
})
function Health:Construct()
self.value = 100
end
function Health:Start()
print(self.Instance.." now has a health component")
end
function Health:Stop()
end
function Health:HeartbeatUpdate(dt)
end
function Health:SteppedUpdate(dt)
end
function Health:RenderSteppedUpdate(dt)
end
return Health
Now anything with a “Health” tag added to it will have this component. Pretty simple.
If you wanted to access all the instances which have health from anywhere else in your code (from server) you could just do this:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Knit = require(ReplicatedStorage:WaitForChild("Packages"):WaitForChild("knit"))
Knit.OnStart():await() -- Make sure Knit server is already started
local allHealth = Knit.Components.Health:GetAll()
for _, health in pairs(allHealth) do
print(health.Instance," has Health of ", health.value)
end
As far at inheritance goes you can do it with components like this. Let’s say you have Car and Truck which are both Vehicles. You’d create a Vehicle component. You’d then have a “Car” component, and a “Truck” component, which can access the Vehicle which is attached to their instance.
You’d need to add both a “Vehicle” tag and a “Truck” tag to a truck, and a “Vehicle” tag and a “Car” tag to a car.
While this is not inheritance in the OOP sense, it is essentially the same thing.
Vehicle Component:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Component = require(ReplicatedStorage:WaitForChild("Packages"):WaitForChild("component"))
local Vehicle = Component.new({
Tag = "Vehicle",
})
function Vehicle:Construct()
self.speed = 0
end
return Vehicle
Truck Component:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Component = require(ReplicatedStorage:WaitForChild("Packages"):WaitForChild("component"))
local Knit = require(ReplicatedStorage:WaitForChild("Packages"):WaitForChild("component"))
local Truck = Component.new({
Tag = "Truck",
})
function Truck:Construct()
end
function Truck:Start()
self.vehicle = Knit.Components.Vehicle:FromInstance(self.Instance)
self.vehicle.speed = 10
end
return Truck
Could you explain what components are and what they’re used for? Thank you in advance
Requiring the Components is one way of doing it until it returns the same instance. I personally require the buttons in the script I’m using them in. For example:
-- KnitClientRuntime.client.lua
Knit.Components = script.Parent.Components
Knit.AddControllersDeep(script.Parent.Controllers)
Knit.Start():andThen(function()
for _,v in pairs(componentDir:GetChildren()) do
if (v:IsA("ModuleScript")) then
require(v)
end
end
end):catch(warn)
-- SomeController.lua
local SomeComponent; -- Instances with comp Tag
SomeController:KnitStart()
SomeComponent = require(Knit.Components.Core.SomeComponent)
SomeComponent:WaitForInstance(yourInstance):andThen(function(instanceComp)
instanceComp:yourCompMethod()
end)
end)
Try to think of them as “reusable pieces of code”. For instance, lets say a TextButton
with a Button
Tag. I can construct hover methods in the button class, within a function named “yourCompMethod”, and return the hover for every button or retrieving mouse clicks with our comp methods.
Incredibly useful.
Ah so it just combines OOP and CollectionService. That’s neat
You are indeed correct! It has tons of dev-oriented features, which all comes with practice. A few months should get you somewhat knowledgeable with Knit.