Okay, what I'm looking for is maybe an explanation or a link to an article that can fill me in on the techniques of event-driven programming in lua. I know that Roblox already has a functioning event based system with objects like BinableEvent
and the Event properties which fire upon certain changes to a part.
If you don't know, Event-Driven programming is an important way to fashion your code so that changes to code will happen when other changes to the code occur. Let's say I click a button, making that button into a clicked state. A code designed to run after the button is clicked will now act because I clicked the button, which fired an event that signified it's clicked state.
The challenge here, is that I want to know a feasible way of implementing these kinds of events without using the Roblox Tools - but only conventions of the lua programming language itself. This would enable me to take my game outside of roblox if I so desired.
From a basic lookup on stackoverflow, I could find that the game/program I would be programming would have to be split up into multiple frames. Any changes made to the internal data would be loaded with the start of the frame, and as the frame passes, variables are checked against prior data. If a change is detected, a callback function will fire.
For example, this will print "a changed from 5 to 7" when a variable is changed in the SomeFunctionThatOperatesTime
function
WatchedVariables = { a = 5, b = 22, } WatchedVariables_cache = {} for k,v in pairs(WatchedVariables) do WatchedVariables_cache[k] = v end function OnFrame() print("NEXT FRAME! (possibly 1 second later or something)") for k,v in pairs(WatchedVariables) do local v_old = WatchedVariables_cache[k] if v ~= v_old then -- this is the "callback" print(tostring(k).." changed from "..tostring(v_old).." to "..tostring(v)) WatchedVariables_cache[k] = v end end end function SomeFunctionThatOperatesSomeTime() print("about to change a, brother!") WatchedVariables.a = -7 print("a is changed") end
Although I get the mechanics of how it works, the only callback functions I've found as examples are repetitive calls to the print function. Is there a way to utilize some sort of callback function that provides a signal or flag as versatile as how roblox implement's it's "Fired" methods in BindableEvents? Maybe I'm just not seeing the big picture yet I'd love any advice. Sorry, this concept might be big.
This is a good question!
You actually don't have to use bindable events however it's recommended to keep threading identical to that of Roblox's signals, although to keep code shorter I won't use them in my example, same idea though.
By using meta tables we can essentially create a middle man between the table that has the data we want and the coder. We can then use the metatables of this middle man to check if a value being added is new, and if it is, fire an event. It's really that simple:
local this = {}; local events = {}; local proxy = setmetatable({}, { __index = this; __newindex = function(t, k, v) if events[k] and this[k] ~= v then -- fire event events[k](v); end; -- new value being passed, update this[k] = v; end; }); proxy.cats = 10; proxy.likesCats = true; events.cats = function(value) print("cats was changed to", value); end; events.likesCats = function(value) print("likesCats changed to", value); end; proxy.cats = 5; proxy.likesCats = false; print(proxy.cats);
Hope that helps!
Edit:
If you wanted to add a wait then you could do it like this. Although honestly speaking I think a bindable event is better for this.
local this = {}; local events = {}; local proxy = setmetatable({}, { __index = this; __newindex = function(t, k, v) if events[k] and this[k] ~= v then -- fire event events[k](v); end; -- new value being passed, update this[k] = v; end; }); function proxy:wait(index) local current = self[index]; repeat wait() until current ~= self[index]; end; proxy.cats = 10; delay(5, function() proxy.cats = 5; end); local t = tick(); proxy:wait("cats"); print(tick() - t, "cats: " .. proxy.cats);