Lets say I have a variable
local var = 0
And a function
function updateText(text) TextLabel.Text = text end
Then I change the variable.
var = 35
How do I run the function updateText(var) when the variable changes? The variable will have to work for every value type (including tables).
I have thought of a few methods of doing this but some are pretty hacky. I would prefer to do this just inside the script and not using any roblox provided objects if possible
METHOD 1: Whenever I change the variable fire the function.
Aww that's no fun. I would like to not have to type that out everytime
METHOD 2: Fire a remoteEvent with an argument of what we want to change the variable to, then (assuming this is client side), in the serverside using the OnServerEvent event fire the remoteEvent again, in client side using the OnClientEvent event run the function and change the variable to the argument that we provided
Uh, hacky and we need to wait for Server and Client communications to happen and that will only work if we have a player in the game and it is client side.
METHOD 3: Use a value object and use the Changed event
What about table variables
Any help would be appreciated
There isn't a direct way to watch a variable change.
This is mostly to make Lua understandable -- when you change a variable, only that variable changes.
You can still accomplish this, though. First: there is a reason you cannot do extra work when dealing simply with variable. It makes Lua easier to understand when you play by the normal rules. ROBLOX cheats all over the place with Lua's rules; if you think about it, you can probably come up with lots of different places where it cheats. That doesn't mean you should!
An idiomatic solution is getters and setters. Instead of using a variable directly, you use two functions. This lets you react to changes. For instance, we can limit a number to be between 0 and 1:
do local x = 0 -- local in a do means no one can directly use `x` -- EXCEPT by getX and setX -- (if you trust yourself to not use `x`, the `do/end` is unnecessary) function getX() return x end function setX(newX) if newX > 1 then x = 1 elseif newX < 0 then x = 0 else x = newX end end end setX(2) print(getX()) -- 1 setX(0.5) print(getX()) -- 0.5
An often sufficient method is to just repeatedly ask. If, for instance, you just need to show a value on the screen, this is probably enough:
while wait() do script.Parent.Text = value end
If you want to do it in the background, you can spawn
a new thread to do that.
Lua has a feature called metatables. These redefine the way that basic operations work in Lua.
Using the __index
and __newindex
metamethods, we can take advantage of the getter and setter pattern, but make it look like property of an object (this is more or less how .Changed
is implemented in ROBLOX objects)
It looks like this:
local t = {} local value function get(obj, property) assert(property == "value") -- only allow `t.value` to be gotten return value end function set(obj, property, newValue) assert(property == "value") -- only allow `t.value` to be set if newValue > 1 then value = 1 elseif newValue < 0 then value = 0 else value = newValue end -- (Do whatever extra stuff here) end setmetatable(t, {__index = get, __newindex = set} ) t.value = 5 print(t.value) -- 1 t.value = 0.5 print(t.value) -- 0.5
Pure Lua 5.1 will let you do this more directly. Diito's answer tells you how to get this to work in ROBLOX.
First: do not do this. To an even greater extent than the above, it can be incredibly confusing and frustrating.
Global variables (as opposed to local, not those in _G
-- although in vanilla Lua this is essentially the same) are actually properties stored in a table. That table is called the environment, and you can give it a metatable.
Applying the previous lets you do getters and setters on plain variables -- horrifying!
setmetatable( getfenv(), {__index = get, __newindex = set} ) -- get and set from before value = 1 print(value) -- 1 value = -1.5 print(value) -- 0 ??? value = 0.5 print(value) -- 0.5
Following up BlueTaslem... Metamethod + Environment Hack [in a correct way if pro] :
local Environment = getfenv(1) local Metatable = {} Metatable.__index = {} Metatable.__metatable = "This metatable is locked" function Metatable:__newindex(self, index, value) Metatable.__index[index] = value updateText() end setfenv(1, setmetatable({}, Metatable))