Making experiences interactive often means manipulating object properties and attributes:
Properties are part of the object class. For example, the BasePart.Anchored property controls physics for the part. In a track and field experience, you might want to anchor a discus or javelin the instant it lands so that players have a visual indicator of how far it traveled.
Attributes are essentially custom properties that you define. For example, the Plant reference project uses attributes to set the purchase price for seeds and the maximum plant size that a pot can hold.
Getting Objects
The first step to modifying object properties and attributes is to get a reference to the object. The simplest solution is to make the script a child of the object in the Explorer and use script.Parent to reference the object.
![A script parented to a model in the Explorer.](https://prod.docsiteassets.roblox.com/assets/scripting/script-parent.png)
local sign = script.Parent
The more universal solution is to get the object from a service using methods like Instance:FindFirstChild() or Instance:WaitForChild().
![A script within a folder in ReplicatedStorage.](https://prod.docsiteassets.roblox.com/assets/scripting/script-parent-rep.png)
local ReplicatedStorage = game:GetService("ReplicatedStorage")local signsFolder = ReplicatedStorage:WaitForChild("Signs")local sign = signsFolder:WaitForChild("InteractiveSign")
Modifying Properties
Properties are straightforward to access—just use a . after the object reference—although if you're working with a model, you might need to choose an individual part rather than the model itself.
![A script within a folder in ReplicatedStorage.](https://prod.docsiteassets.roblox.com/assets/scripting/script-part.png)
local ReplicatedStorage = game:GetService("ReplicatedStorage")local chair = ReplicatedStorage:WaitForChild("Chair")chair.LeftArmRest.Size = Vector3.new(10, 1, 10)
Creating Attributes
Although you can create attributes programmatically, the more common solution is to create them with default values in the Studio user interface. Then you can use scripts to modify their values in response to player actions.
![A script within a folder in ReplicatedStorage.](https://prod.docsiteassets.roblox.com/assets/scripting/script-attributes.png)
For information on creating attributes in Studio, see Instance Attributes.
Setting Attributes
To modify an attribute's value, call Instance:SetAttribute() with a name and value.
Create or Modify Attribute
local cabbage = script.Parentcabbage:SetAttribute("Harvestable", true)
If the attribute doesn't already exist, this method creates it.
Getting Attribute Values
To get the value of one existing attribute, call Instance:GetAttribute() on the instance.
Get Attribute Value
local cabbage = script.Parentcabbage:SetAttribute("Harvestable", true)local isHarvestable = cabbage:GetAttribute("Harvestable")print(isHarvestable) --> true
Similarly, you can get all attributes by calling Instance:GetAttributes(). This method returns a dictionary of key-value pairs.
Get All Attributes
local cabbage = script.Parentlocal cabbageAttributes = cabbage:GetAttributes()print(cabbageAttributes.GrowthRate) --> 2for k, v in cabbageAttributes doprint(k, v)end
Deleting Attributes
To delete an attribute, set its value to nil.
Delete Attribute
local cabbage = script.Parentcabbage:SetAttribute("GrowthRate", nil)
Detecting Changes
There are several ways to listen for changes to properties and attributes:
The Instance.Changed event listens for changes to any property (including attributes) and passes the name of the changed property as a parameter.
The Instance.AttributeChanged event listens for changes to any attribute and passes the name of the changed attribute as a parameter.
The Instance:GetPropertyChangedSignal() method lets you listen for changes to one property and passes no parameters.
The Instance:GetAttributeChangedSignal() method lets you listen for changes to one attribute and passes no parameters.
Due to the minimal information that these events and methods pass as parameters, all of them are a good fit for anonymous functions, particularly Instance:GetPropertyChangedSignal() and Instance:GetAttributeChangedSignal(). To learn more about anonymous functions and working with events, see Events.
Listen for Changes
local cabbage = script.Parent
-- Local functions
local function onAnyPropertyChange(property)
-- Ignore changes to attributes
if property ~= "Attributes" then
print(property) --> Name
print(cabbage[property]) --> Cabbage1
end
end
local function onAnyAttributeChange(attribute)
print(attribute) --> Grow, GrowthRate
print(cabbage:GetAttribute(attribute)) --> false, 3
end
-- Listen for changes and connect to local functions
cabbage.Changed:Connect(onAnyPropertyChange)
cabbage.AttributeChanged:Connect(onAnyAttributeChange)
-- Listen for changes and connect to anonymous functions
cabbage:GetPropertyChangedSignal("Name"):Connect(function()
print(cabbage.Name) --> Cabbage1
end)
cabbage:GetAttributeChangedSignal("GrowthRate"):Connect(function()
print(cabbage:GetAttribute("GrowthRate")) --> 3
end)
-- Fires Changed and GetPropertyChangedSignal()
cabbage.Name = "Cabbage1"
-- Fires Changed and AttributeChanged
cabbage:SetAttribute("Grow", false)
-- Fires Changed, AttributeChanged, and GetAttributeChangedSignal()
cabbage:SetAttribute("GrowthRate", 3)