Oh boy, this is a big one. Here's what I'm trying to do.
A big object that holds a table of values creates a manager object. This "manager" object creates a GUI-based Object for every item in the big object.
When someone clicks the one of the GUI-based Objects, somehow the message needs to come back to the big object that the clicked object needs to be removed from the big object.
I'm not expecting any code, but does anyone know what kind of concept I should use to accomplish this?
Let me clarify a bit more for you. All of these objects are based off of moduleScripts
I've got a Deck Object. What is important here is the :search(x) method. Here it is to the Bones:
local Deck = {} -------------------------------------------------- --CONSTRUCTOR-- function Deck.new(...) local cards ={...} return setmetatable(cards, Deck) end -------------------------------------------------- --MISC METHODS-- function Deck:search(x) --Looks for x amount of cards --Create new GUIBlock Object and waits for its descendants to be clicked end -------------------------------------------------- --METAMETHODS-- Deck.__index = Deck --All indexes to this object will be directed to the module's items -------------------------------------------------- return Deck
Here is the "manager" object to the bones. It is named GUIBlock, as it creates many GUI's off of Deck.
local GUIBlock = {} function GUIBlock.new(Deck, Player) --------------------- --PRIVATE VARIABLES-- local main = Instance.new("ScreenGui", Player.PlayerGui) local cards = {} --This will be filled with lots of GUI objects local stuff = {} -------------------------------------------------- --SETTINGS-- for i, v in ipairs(Deck) do cards[i] = GUI.new(main, function()print(i)end , Deck[i]) --function right here is a sample. It prints the index of the item in the Deck object when called on cards[i]:moveGUITo(cards[i]:getScreenPosition() + UDim2.new((i-1)*.2,0,0,0)); end --------------------- setmetatable(stuff, GUI); return stuff end -------------------------------------------------- --METAMETHODS-- GUIBlock.__index = GUIBlock --All indexes to this object will be directed to the module's items -------------------------------------------------- return GUIBlock
And now the GUI related object itself
local GUI = {} -------------------------------------------------- --CONSTRUCTOR-- function GUI.new(PARENT, CLICKEFFECT, CARD) --------------------- --PRIVATE VARIABLES-- local card = Instance.new("ImageButton", PARENT) local clickEffect = Instance.new("BindableFunction", card) --Helps to make a public instance of a sent in functions local stuff = {} -------------------------------------------------- --SETTINGS-- card.Size = UDim2.new(.2, 0, .5, 0) card.Position = UDim2.new(.2, 0, .25, 0) clickEffect.OnInvoke = (CLICKEFFECT) -------------------------------------------------- --ACCESSOR METHODS-- function stuff:getScreenPosition() --Returns the UDim2 of the Position return card.Position end -------------------------------------------------- --MODIFIER METHODS-- function stuff:moveGUITo(newPosition) --Moves the GUI to newPosition(a UDim2) card.Position = newPosition; end -------------------------------------------------- --EVENT LISTENERS-- card.MouseButton1Down:connect(function()clickEffect:Invoke()end); --Fires the sent in function when clicked on. Its a sample --------------------- setmetatable(stuff, GUI); return stuff end -------------------------------------------------- --METAMETHODS-- GUI.__index = GUI --All indexes to this object will be directed to the module's items -------------------------------------------------- return GUI
I don't fully understand what you're trying to do, but here are a few ideas:
cardsClicked[card] = boolean
. (Alternatively, put a clicked
boolean variable in your Card class and simply iterate over the relevant cards and see if they all have .clicked == true
To "proceed however you wish", you have a couple options:
- Receive a callback function in your search
function. Instead of the calling code using the result of search
immediately, you transfer that logic to a function that will get called later - when all cards have been clicked.
ex. Instead of
local cards = deck:search(5) for i = 1, #cards do print(cards[i]) end
do:
deck:search(5, function(cards) for i = 1, #cards do print(cards[i]) end end)
Or:
wait()
in the search
function until the appropriate condition has been met. Though potentially easier to write, it is less efficient (you must check a condition numerous times per second instead of only checking it when a card is clicked).coroutine.yield()
doesn't work properly on a thread that has wait
ed at any time (this was the case last I checked - I reported this to Roblox a couple weeks ago and they might have fixed it by now). You can get around this by using :wait()
on a Roblox event (like ChildAdded
or Changed
), but it is nonetheless more complicated. The benefit is that you can say local cards = deck:search(5)
while maintaining the efficiency of using events instead of a while not condition do wait() end
Another option entirely is to tell the Card what Deck it is in and add a function in Deck, CardClicked
. When the card is clicked, call the CardClicked
function. In there, the Deck can proceed as before, just as if it had received an event. The advantages of not using this option include:
Click
event (if you make an event instead of hard-coding what function(s) are activated when you click on a card).