Hover Over Health

Hello, I have a bug with Hover Over Health for my tower defense game below you have the video and the script

local Players = game:GetService("Players")
local PhysicsService = game:GetService("PhysicsService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local TweenService = game:GetService("TweenService")
local UserInputService = game:GetService("UserInputService")

local modules = ReplicatedStorage:WaitForChild("Modules")
local health = require(modules:WaitForChild("Health"))

local gold = Players.LocalPlayer:WaitForChild("Gold")
local towers = ReplicatedStorage:WaitForChild("Towers")

local functions = ReplicatedStorage:WaitForChild("Functions")
local requestTowerFunction = functions:WaitForChild("RequestTower")
local spawnTowerFunction = functions:WaitForChild("SpawnTower")
local sellTowerFunction = functions:WaitForChild("SellTower")
local changeModeFunction = functions:WaitForChild("ChangeTowerMode")

local gui = script.Parent
local hovergui = gui:WaitForChild("HoverGui")
local healthFrame = hovergui:WaitForChild("HealthFrame")
local currentHealth = healthFrame:WaitForChild("CurrentHealth")

local camera = workspace.CurrentCamera
local map = workspace:WaitForChild("BasePlate")
local base = map:WaitForChild("Base")
local info = workspace:WaitForChild("Info")

local hoveredInstance = nil
local selectedTower = nil
local towerToSpawn = nil
local canPlace = false
local rotation = 0
local placedTowers = 0
local maxTowers = 100
local lastTouch = tick()

local function MouseRaycast(model)
	local mousePos = UserInputService:GetMouseLocation()
	local mouseRay = camera:ViewportPointToRay(mousePos.X, mousePos.Y)
	local raycastParams = RaycastParams.new()
	
	local blacklist = camera:GetChildren()
	table.insert(blacklist, model)
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	raycastParams.FilterDescendantsInstances = blacklist

	local raycastResult = workspace:Raycast(mouseRay.Origin, mouseRay.Direction * 1000, raycastParams)
	
	return raycastResult, mousePos
end

local function hoverOverMob(result, mousePos)
	local mobHumanoid = result.Instance.Parent:FindFirstChild("Humanoid") or result.Instance.Parent.Parent:FindFirstChild("Humanoid")
	
	if mobHumanoid then
		local percent = mobHumanoid.Health / mobHumanoid.MaxHealth
		currentHealth.Size = UDim2.new(0,1,0)
		healthFrame.Health.Text =  mobHumanoid.Health .. "/" .. mobHumanoid.MaxHealth
		hovergui.Title.Text = mobHumanoid.Parent.Name
		hovergui.Position = UDim2.new(0, mousePos.X, 0, mousePos.Y)
		hovergui.Visible = true
	end 
	
end


local function CreateRangeCircle(tower, placeholder)
	
	local range = tower.Config.Range.Value
	local height = (tower.PrimaryPart.Size.Y / 2) + tower.Humanoid.HipHeight
	local offset = CFrame.new(0, -height, 0)
	
	local p = Instance.new("Part")
	p.Name = "Range"
	p.Shape = Enum.PartType.Cylinder
	p.Material = Enum.Material.Neon
	p.Transparency = 0.9
	p.Size = Vector3.new(2, range * 2, range * 2)
	p.TopSurface = Enum.SurfaceType.Smooth
	p.BottomSurface = Enum.SurfaceType.Smooth
	p.CFrame = tower.PrimaryPart.CFrame * offset * CFrame.Angles(0, 0, math.rad(90))
	p.CanCollide = false
	
	if placeholder then
		p.Anchored = false
		local weld = Instance.new("WeldConstraint")
		weld.Part0 = p
		weld.Part1 = tower.PrimaryPart
		weld.Parent = p
		p.Parent = tower
	else
		p.Anchored = true
		p.Parent = workspace.Camera
	end
	
end

local function RemovePlaceholderTower()
	if towerToSpawn then
		towerToSpawn:Destroy()
		towerToSpawn = nil
		rotation = 0
		gui.Controls.Visible = false
	end
end

local function AddPlaceholderTower(name)
	
	local towerExists = towers:FindFirstChild(name)
	if towerExists then
		RemovePlaceholderTower()
		towerToSpawn = towerExists:Clone()
		towerToSpawn.Parent = workspace
		
		CreateRangeCircle(towerToSpawn, true)
		
		for i, object in ipairs(towerToSpawn:GetDescendants()) do
			if object:IsA("BasePart") then
				PhysicsService:SetPartCollisionGroup(object, "Tower")
				if object.Name ~= "Range" then
					object.Material = Enum.Material.ForceField
					object.Transparency = 0.3
				end
			end
		end
		
		gui.Controls.Visible = true
	end
end

local function ColorPlaceholderTower(color)
	for i, object in ipairs(towerToSpawn:GetDescendants()) do
		if object:IsA("BasePart") then
			object.Color = color
		end
	end
end

local function toggleTowerInfo()
	workspace.Camera:ClearAllChildren()
	gui.Towers.Title.Text = "Towers: " .. placedTowers .. "/" .. maxTowers
	
	if selectedTower then
		CreateRangeCircle(selectedTower)
		gui.Selection.Visible = true
		local config = selectedTower.Config
		gui.Selection.Stats.Damage.Value.Text = config.Damage.Value
		gui.Selection.Stats.Range.Value.Text = config.Range.Value
		gui.Selection.Stats.Cooldown.Value.Text = config.Cooldown.Value
		gui.Selection.Title.TowerName.Text = selectedTower.Name
		gui.Selection.Title.TowerImage.Image = config.Image.Texture
		gui.Selection.Title.OwnerName.Text = config.Owner.Value .. "'s"
		
		local modes = {
			["First"] = "rgb(150, 150, 150)",
			["Last"] = "rgb(50, 50, 50)", 
			["Near"] = "rgb(50, 150, 0)", 
			["Strong"] = "rgb(200, 50, 50)", 
			["Weak"] = "rgb(50, 100, 200)"
		}
		local color = modes[config.TargetMode.Value]
		gui.Selection.Action.Target.Title.Text = "Target: <font color=\"" .. color .. "\">" .. config.TargetMode.Value .. "</font>"
		
		if config.Owner.Value == Players.LocalPlayer.Name then
			gui.Selection.Action.Visible = true
			
			local upgradeTower = config:FindFirstChild("Upgrade")
			if upgradeTower then
				gui.Selection.Action.Upgrade.Visible = true
				gui.Selection.Action.Upgrade.Title.Text = "Upgrade (" .. upgradeTower.Value.Config.Price.Value .. ")"
			else
				gui.Selection.Action.Upgrade.Visible = false
			end
		else
			gui.Selection.Action.Visible = false
		end
		
	else
		gui.Selection.Visible = false
	end
end

local function SpawnNewTower()
	if canPlace then
		local placedTower = spawnTowerFunction:InvokeServer(towerToSpawn.Name, towerToSpawn.PrimaryPart.CFrame)
		if placedTower then
			placedTowers += 1
			selectedTower = placedTower
			RemovePlaceholderTower()
			toggleTowerInfo()
		end
	end
end

gui.Controls.Cancel.Activated:Connect(RemovePlaceholderTower)

gui.Selection.Action.Target.Activated:Connect(function()
	if selectedTower then
		local modeChangeSuccess = changeModeFunction:InvokeServer(selectedTower)
		if modeChangeSuccess then
			toggleTowerInfo()
		end
	end
end)

gui.Selection.Action.Upgrade.Activated:Connect(function()
	if selectedTower then
		local upgradeTower = selectedTower.Config.Upgrade.Value
		local upgradeSuccess = spawnTowerFunction:InvokeServer(upgradeTower.Name, selectedTower.PrimaryPart.CFrame, selectedTower)
		
		if upgradeSuccess then
			selectedTower = upgradeSuccess
			toggleTowerInfo()
		end
	end
end)

gui.Selection.Action.Sell.Activated:Connect(function()
	if selectedTower then
		local soldTower = sellTowerFunction:InvokeServer(selectedTower)
		
		if soldTower then
			selectedTower = nil
			placedTowers -= 1
			toggleTowerInfo()
		end
	end
end)

UserInputService.InputBegan:Connect(function(input, processed)
	if processed then
		return
	end
	
	if towerToSpawn then
		if input.UserInputType == Enum.UserInputType.MouseButton1 then
			SpawnNewTower()
		elseif input.UserInputType == Enum.UserInputType.Touch then
			local timeSinceLastTouch = tick() - lastTouch
			if timeSinceLastTouch <= 0.25 then
				SpawnNewTower()
			end
			lastTouch = tick()
		elseif input.KeyCode == Enum.KeyCode.R then
			rotation += 90
		elseif input.KeyCode == Enum.KeyCode.X or input.KeyCode == Enum.KeyCode.C then
			RemovePlaceholderTower()
		end
	elseif hoveredInstance and (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) then
		local model = hoveredInstance:FindFirstAncestorOfClass("Model")
		
		if model and model.Parent == workspace.Towers then
			selectedTower = model
		else
			selectedTower = nil
		end
		
		toggleTowerInfo()
	end
end)

RunService.RenderStepped:Connect(function()
	local result = MouseRaycast(towerToSpawn)
	if result and result.Instance then
		if towerToSpawn then
			hoveredInstance = nil
			
			if result.Instance.Parent.Name == "TowerArea" then
				canPlace = true
				ColorPlaceholderTower(Color3.new(0,1,0))
			else
				canPlace = false
				ColorPlaceholderTower(Color3.new(1,0,0))
			end
			local x = result.Position.X
			local y = result.Position.Y + towerToSpawn.Humanoid.HipHeight + (towerToSpawn.PrimaryPart.Size.Y * 1.5)
			local z = result.Position.Z

			local cframe = CFrame.new(x,y,z) * CFrame.Angles(0, math.rad(rotation), 0)
			towerToSpawn:SetPrimaryPartCFrame(cframe)
		else

			local result, mousePos = MouseRaycast()

			if result and result.Instance and mousePos then
				if result.Instance.Parent.Parent and result.Instance.Parent.Parent.Name == "Mobs" then
					hoverOverMob(result, mousePos)
				elseif result.Instance.Parent.Parent and result.Instance.Parent.Parent.Parent.Name == "Mobs" then
					hoverOverMob(result, mousePos)
				else
					hovergui.Visible = false
				end
			else
				hovergui.Visible = false
			end

		end
	else
		hoveredInstance = nil
	end
end)

local function DisplayEndScreen(status)
	local screen = gui.EndScreen
	
	if status == "GAME OVER" then
		
		screen.Failure:Play()
		screen.Content.Title.TextColor3 = Color3.new(1, 0, 0)
		screen.ImageColor3 = Color3.new(0, 0, 0)
		screen.Content.Subtitle.Text = "Better luck next time"
		
	elseif status == "VICTORY" then
		
		screen.Victory:Play()
		screen.Content.Title.TextColor3 = Color3.new(0, 1, 0)
		screen.ImageColor3 = Color3.new(0.6, 1, 0.4)
		screen.Content.Subtitle.Text = "The garden lives to grow another day!"
		
	end
	
	screen.Content.Title.Text = status
	screen.Stats.Wave.Text = "Wave: " .. workspace.Info.Wave.Value
	screen.Stats.Gold.Text = "Gold: " .. Players.LocalPlayer.Gold.Value
	screen.Stats.Kills.Text = "Kills: " .. Players.LocalPlayer.Kills.Value
	
	screen.Size = UDim2.new(0,0,0,0)
	screen.Visible = true
	
	local tweenStyle = TweenInfo.new(0.5, Enum.EasingStyle.Back, Enum.EasingDirection.Out, 0, false, 0)
	local zoomTween = TweenService:Create(screen, tweenStyle, {Size = UDim2.new(1,0,1,0)})
	zoomTween:Play()
	
end

local function SetupGui()
	health.Setup(base, gui.Info.Health)

	info.Message.Changed:Connect(function(change)
		gui.Info.Message.Text = change
		if change == "" then
			gui.Info.Message.Visible = false
		else
			gui.Info.Message.Visible = true
			
			if change == "VICTORY" or change == "GAME OVER" then
				DisplayEndScreen(change)
			end
		end
	end)

	info.Wave.Changed:Connect(function(change)
		gui.Info.Stats.Wave.Text = "Wave:" .. change
	end)

	gold.Changed:Connect(function(change)
		gui.Info.Stats.Gold.Text = "$" .. gold.Value
	end)
	gui.Info.Stats.Gold.Text = "$" .. gold.Value

	gui.Towers.Title.Text = "Towers: " .. placedTowers .. "/" .. maxTowers
	for i, tower in pairs(towers:GetChildren()) do
		if tower:IsA("Model") then
			local button = gui.Towers.Template:Clone()
			local config = tower:WaitForChild("Config")
			button.Name = tower.Name
			button.Image = config.Image.Texture
			button.Visible = true
			button.LayoutOrder = config.Price.Value
			button.Price.Text = config.Price.Value

			button.Parent = gui.Towers

			button.Activated:Connect(function()
				local allowedToSpawn = requestTowerFunction:InvokeServer(tower.Name)
				if allowedToSpawn then
					AddPlaceholderTower(tower.Name)
				end
			end)
		end
	end
end

SetupGui()

1 Like

Whats the bug? You need to explain the problem.

I’d assume the bug is that the health bar doesn’t go down when the Zombie takes damage

I mean I might be wrong but you might need to loop it?

are you sure the humanoid is losing health in the first place?

yes the humanoid loses hp and I’m sorry I didn’t make it clear to you I meant that the health bar doesn’t change but you can see the health bar itself

Can you show the line where the health ui tries to go down?

local function hoverOverMob(result, mousePos)
	local mobHumanoid = result.Instance.Parent:FindFirstChild("Humanoid") or result.Instance.Parent.Parent:FindFirstChild("Humanoid")
	
	if mobHumanoid then
		local percent = mobHumanoid.Health / mobHumanoid.MaxHealth
		currentHealth.Size = UDim2.new(0,1,0)
		healthFrame.Health.Text =  mobHumanoid.Health .. "/" .. mobHumanoid.MaxHealth
		hovergui.Title.Text = mobHumanoid.Parent.Name
		hovergui.Position = UDim2.new(0, mousePos.X, 0, mousePos.Y)
		hovergui.Visible = true
	end 
	
end

Since you have a base health, and I know from what tutorial you are watching this. Can’t you just copy the same logic of the base health?

I think he has and not found a solution

1 Like