Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

Logically communicating between object and descendants?

Asked by 8 years ago

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
0
And I'm not looking for any _G variable nonsense. It needs to be independent. randomsmileyface 375 — 8y
0
Look into Module Scripts User#5978 25 — 8y
0
They are modulescript... The question is how you can track the Clicked event on an object throughout a hiearchy of objects randomsmileyface 375 — 8y

1 answer

Log in to vote
1
Answered by 8 years ago

I don't fully understand what you're trying to do, but here are a few ideas:

  • Put a BindableEvent in each card object. When you initialize the cards into the deck, start listening to these events. Use a table to keep track of which events have fired (and then stop listening to them). Once all events have fired, you could proceed however you wish. There are two ways to check if all events have fired:
    • Keep track of how many clicks you are listening for and how many clicks have occurred (making sure that you only listen to the first click for each card). Once you have 0 clicks remaining, all cards have been clicked.
    • Keep track of which cards have been clicked in a dictionary, like 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:

    • Keep calling 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).
    • The most complicated option is to yield the current thread until the condition is true. One of the reasons this is the most complicated option is because coroutine.yield() doesn't work properly on a thread that has waited 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:

    • The card class not needing to know about the Deck class (better Object Oriented style)
    • Other classes can listen to the card's Click event (if you make an event instead of hard-coding what function(s) are activated when you click on a card).
0
I love it. I love it, I love it. Bonus points for you. randomsmileyface 375 — 8y
Ad

Answer this question