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”.
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