Best way to share global state amgonst objects in a class

I have a class called “Interactable” and in that class is a signal, “Hovered” that is fired whenever the instance is hovered over with the mouse. This class is instantiated multiple times in my game and therefore there are multiple “Interactable” objects within the game at any given point in time.

My issue is that if one of the Interactable objects in the game is currently being hovered over, I don’t want any other Interactable objects to be able to fire their Hovered signal.

-- Simplified version

function Interactable.new(instance: Instance)
    self.Hovered = Signal.new()
    self._isHovered = false

    instance.MouseHovered:Connect(function()
        self._isHovered = true
        self.Hovered:Fire()
    end)
end

What would be the best way of going about this? I could obviously have a global variable at the top of the script that is set to true when an object is hovered over and use that to determine if any Interactable object in the game is being hovered over. But I feel like this approach may be “frowned upon”.

Gather all of your hovers with a for loop and turn them all off. Then, after the loop turn back on the current one only.

We can use the actor observer design pattern and allow inversion of control.

Code:

local HoverManager = {}
HoverManager.__index = HoverManager

function HoverManager.new()
    local self = setmetatable({}, HoverManager)
    self.hoveredObject = nil
    return self
end

function HoverManager:setHoveredObject(object)
    if self.hoveredObject == object then
        return
    end

    if self.hoveredObject then
        self.hoveredObject._isHovered = false
    end

    self.hoveredObject = object
    self.hoveredObject._isHovered = true
end

function HoverManager:clearHoveredObject(object)
    if self.hoveredObject == object then
        self.hoveredObject._isHovered = false
        self.hoveredObject = nil
    end
end

Usage:

local hoverManager = HoverManager.new()

function Interactable.new(instance: Instance, hoverManager)
    local self = setmetatable({}, Interactable)
    self.Hovered = Signal.new()
    self._isHovered = false

    instance.MouseHovered:Connect(function()
        hoverManager:setHoveredObject(self)
        self.Hovered:Fire()
    end)

    instance.MouseLeave:Connect(function()
        hoverManager:clearHoveredObject(self)
    end)

    return self
end

1 Like

I knew there was most likely a design pattern to solve this. Thanks a lot!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.