Object Hovering Highlight Module

BASIC FEATURES:

  • Highlights Objects When Hovering Mouse Over Them.
  • Detect When The Player Clicks The Object.

HOW TO SETUP
Create a object and create a boolean attribute in it named “Hover”, then set the value of the attribute to TRUE.

MODULE:

--> Services
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

--> Player
local Player = Players.LocalPlayer
local Mouse = Player:GetMouse()

--> Custom Types
export type HighlightOptions = {
	FillColor: Color3,
	OutlineColor: Color3,
	Pulses: boolean,
}

--> Class
local Class = {}
Class.__index = Class

--> Local Functions

local function createHighlight(FillColor: Color3, OutlineColor: Color3): Highlight --| CREATE HIGHLIGHT OBJECT
	local Highlight = Instance.new("Highlight")
	Highlight.FillColor = FillColor or Color3.fromRGB(98, 98, 98)
	Highlight.OutlineColor = OutlineColor or Color3.fromRGB(199, 199, 199)
	
	return Highlight
end

--> Global Functions
function Class.new(HighlightOptions: HighlightOptions)
	local self = {}
	
	self.Interact = Instance.new("BindableEvent")
	self.CurrentObject = nil
	
	self.HighlightOptions = HighlightOptions
	
	self.MouseMoved = nil
	self.MouseClicked = nil
	self.PulsingTween = nil
	self.currentTween = nil
	
	
	return setmetatable(self, Class)
end

function Class:Watch()
	if self.MouseMoved ~= nil then return end
	
	local Interact = self.Interact
	
	self.MouseMoved = RunService.Heartbeat:Connect(function(deltaTime: number)
		local Target = Mouse.Target
		
		if self.CurrentObject ~= nil then --| IF THERE IS ALREADY A CURRENT PART HOVER REMOVE THE HIGHLIGHT AND RESET CURRENT PART
			if Target == nil then
				if self.CurrentObject:FindFirstChildWhichIsA("Highlight") then
					self.CurrentObject:FindFirstChildWhichIsA("Highlight"):Destroy()
				end
				
				if self.PulsingTween ~= nil then
					self.PulsingTween:Disconnect()
					self.PulsingTween = nil
				end
				
				if self.currentTween ~= nil then
					self.currentTween:Cancel()
					self.currentTween = nil
				end
				
				self.CurrentObject = nil

				return
				
			elseif Target ~= nil then
					
				if self.CurrentObject ~= Target then
					if self.CurrentObject:FindFirstChildWhichIsA("Highlight") then
						self.CurrentObject:FindFirstChildWhichIsA("Highlight"):Destroy()
					end
					
					if self.PulsingTween ~= nil then
						self.PulsingTween:Disconnect()
						self.PulsingTween = nil
					end
					
					if self.currentTween ~= nil then
						self.currentTween:Cancel()
						self.currentTween = nil
					end

					self.CurrentObject = nil
				end
			end
		end
		
		if Target ~= nil then --| IF THE MOUSE TARGET IS NOT NIL CREATE A HIGHLIGHT
			local canHover = Target:GetAttribute("Hover")
			
			if canHover ~= nil and canHover == true then
				if not Target:FindFirstChildWhichIsA("Highlight") then
					local Highlight = createHighlight(unpack(self.HighlightOptions))
					
					Highlight.Parent = Target
					
					if self.HighlightOptions.Pulses == true then
						if self.PulsingTween == nil then
							self.PulsingTween = RunService.Heartbeat:Connect(function()
								if self.currentTween == nil or (self.currentTween ~= nil and (self.currentTween.PlaybackState == Enum.PlaybackState.Completed or self.currentTween.PlaybackState == Enum.PlaybackState.Cancelled)) then
									self.currentTween = TweenService:Create(Highlight, TweenInfo.new(1, Enum.EasingStyle.Back, Enum.EasingDirection.In, math.huge, true, 0), {["FillTransparency"] = 0.8})
									self.currentTween:Play()
								end
							end)
						end
					end
				end
				
				self.CurrentObject = Target
				
			end
		end
	end)
	
	self.MouseClicked = UserInputService.InputBegan:Connect(function(key) --| DETECT WHEN PLAYER CLICKS THE MOUSE AND FIRE REMOTE IF HOVERING OVER A OBJECT
		if key.UserInputType == Enum.UserInputType.MouseButton1 then
			if self.CurrentObject ~= nil then
				self.Interact:Fire(self.CurrentObject)
			end
		end
	end)
end

function Class:Disconnect()
	if self.MouseMoved ~= nil then
		self.MouseMoved:Disconnect()
	end
	if self.MouseClicked ~= nil then
		self.MouseClicked:Disconnect()
	end
	
	if self.CurrentObject ~= nil then
		if self.CurrentObject:FindFirstChildWhichIsA("Highlight") then
			self.CurrentObject:FindFirstChildWhichIsA("Highlight"):Destroy()
		end
		self.CurrentObject = nil
	end
end

--> Return Class
return Class

EXAMPLE SCRIPT:

--> Module
local Hover = require(script:WaitForChild("Hover"))

--> Make Class
local Class = Hover.new({FillColor = Color3.fromRGB(100, 100, 100), OutlineColor = Color3.fromRGB(29, 29, 29), Pulses = true})
local Interact = Class.Interact

--> Start Watching
Class:Watch()

--> Detect Interactions
Interact.Event:Connect(function(Object)
	print(Object)
end)

VIDEO:

Any Feedback, or criticism would be appreciated!

8 Likes

This seems a bit overly complicated. Given that it doesn’t have easing or really any unique interaction, wouldn’t it be more convenient to use click detectors and just toggle a highlight on and off? Don’t get me wrong though, if it had easing, pulsing, animations or something else that isn’t as straightforward to implement with native features, it could be a really useful module. :sweat_smile:

2 Likes

That is true, the main purpose for this module is to not use click detectors. But the pulsing animation would be a nice feature to add, thank you for the idea!

1 Like

I don’t know if this is exactly what you mean, but i made a tween with the fill transparency when your hovering

2 Likes

does this still work? the interactions event isnt doing anything

nevermind i dont know how to read :sob:
thanks for the module by the way, very cool :+1:

This is pretty over done. I was able to do the same thing in around 50 lines within a local script.

Yes the code isn’t the best but it does work. You will probably modify it to work with your own game.

Still cool tho so gj.

Suggestions:

  • Distance limit
  • Option to tag check selected items
  • Disable/Enable click callback.
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")

local highlight = game:GetService("ReplicatedStorage"):WaitForChild("Highlight")

local player = game.Players.LocalPlayer

local mouse = player:GetMouse()

local distance = 5

local currentTween, PulsingTween

RunService.Heartbeat:Connect(function(delta)

	if mouse.Target then

		local target = mouse.Target
	
		local magnitude = (target.Position - player.Character.HumanoidRootPart.Position).Magnitude

		if magnitude < distance then

			if target:GetAttribute("IsItem") == true then
				
				highlight.Adornee = target
				
				if PulsingTween == nil then
					PulsingTween = RunService.Heartbeat:Connect(function()
						if currentTween == nil or (currentTween ~= nil and (currentTween.PlaybackState == Enum.PlaybackState.Completed or currentTween.PlaybackState == Enum.PlaybackState.Cancelled)) then
							currentTween = TweenService:Create(highlight, TweenInfo.new(1, Enum.EasingStyle.Back, Enum.EasingDirection.In, math.huge, true, 0), {["FillTransparency"] = 0.8})
							currentTween:Play()
							print("playing tween")
						end
						
					end)
					
				end

			else
				highlight.Adornee = nil
				if PulsingTween then
					PulsingTween:Disconnect()
				end
			end
			
		else
			highlight.Adornee = nil
			if PulsingTween then
				PulsingTween:Disconnect()
			end
		end
	else
		highlight.Adornee = nil
		if PulsingTween then
			PulsingTween:Disconnect()
		end
	end

end)
1 Like