Roblox · Интерфейсы

Полоска здоровья над мобом или NPC

Над каждым противником и NPC — имя и полоска здоровья: уменьшается плавно, меняет цвет от зелёного к красному, показывает числа. Один скрипт сам находит всех мобов, даже появившихся позже.

Структура

Синим — что нужно создать.

ReplicatedStorage
└─ HealthBar (BillboardGui) — шаблон: Size {4,0},{1.2,0}, StudsOffset 0, 2.5, 0, AlwaysOnTop
   ├─ NameLabel (TextLabel) — имя сверху
   └─ Background (Frame) — тёмная подложка
      ├─ Bar (Frame) — цветная полоса, Size {1,0},{1,0}
      └─ HealthText (TextLabel) — числа, ZIndex 2
StarterPlayer → StarterPlayerScripts
└─ HealthBarLocal (LocalScript)
Workspace
└─ Dummy (Model) — манекен для проверки (по желанию)
   ├─ ClickDetector (ClickDetector)
   └─ ClickDamage (Script)

Шаги

  1. ReplicatedStorage → BillboardGui «HealthBar». Size в studs (Scale): {4, 0}, {1.2, 0} — полоска уменьшается с расстоянием, как настоящий предмет. StudsOffset 0, 2.5, 0 — над головой. AlwaysOnTop вкл., MaxDistance 60, LightInfluence 0.
  2. Внутри: TextLabel «NameLabel» (верхняя половина), Frame «Background» (нижняя, тёмная), в нём Frame «Bar» (Size {1,0},{1,0}, зелёная) и TextLabel «HealthText» (ZIndex 2, поверх полосы). Имена важны — по ним ищет скрипт.
  3. StarterPlayer → StarterPlayerScripts → LocalScript «HealthBarLocal».
  4. Скрипт берёт все Humanoid в Workspace, которые не игроки, и вешает копию шаблона в Head (или в HumanoidRootPart). DescendantAdded ловит новых мобов: возрождение, волны Tower Defense, монстров из ServerStorage.
  5. Полоска живёт у каждого игрока своя — серверу не нужно ничего делать: здоровье Humanoid и так видно всем.
  6. Мирному NPC полоска не нужна — добавь ему атрибут NoHealthBar (Attributes → «+», тип boolean, вкл.).
  7. Хочешь полоску только у раненых — SHOW_WHEN_FULL = false.
  8. Для проверки: манекен с ClickDetector и скриптом «ClickDamage» — клик отнимает 15, потом он понемногу лечится.

Скрипты

HealthBarLocal

Где: StarterPlayer → StarterPlayerScripts · LocalScript
Зачем: Полоски над всеми мобами.

-- игроки
local Players = game:GetService("Players")
-- здесь шаблон полоски
local RS = game:GetService("ReplicatedStorage")
-- плавное уменьшение
local TweenService = game:GetService("TweenService")
-- шаблон BillboardGui
local template = RS:WaitForChild("HealthBar")
-- false — полоска появится только после первого удара
local SHOW_WHEN_FULL = true
-- много здоровья
local GREEN = Color3.fromRGB(80, 220, 90)
-- половина
local YELLOW = Color3.fromRGB(250, 210, 60)
-- мало
local RED = Color3.fromRGB(235, 60, 60)

-- цвет по доле здоровья от 0 до 1
local function ColorFor(k)
    -- от жёлтого к зелёному
    if k > 0.5 then return YELLOW:Lerp(GREEN, (k - 0.5) * 2) end
    -- от красного к жёлтому
    return RED:Lerp(YELLOW, k * 2)
-- конец функции
end

-- повесить полоску на одного моба
local function Attach(humanoid)
    -- модель моба
    local model = humanoid.Parent
    -- Humanoid не в модели
    if not model or not model:IsA("Model") then return end
    -- игрокам полоска не нужна
    if Players:GetPlayerFromCharacter(model) then return end
    -- атрибут NoHealthBar — без полоски (мирные жители)
    if model:GetAttribute("NoHealthBar") then return end
    -- над чем висеть
    local head = model:FindFirstChild("Head") or model:WaitForChild("Head", 3) or model:FindFirstChild("HumanoidRootPart")
    -- не к чему крепить или уже есть
    if not head or head:FindFirstChild("HealthBar") then return end
    -- прячем стандартное имя и здоровье
    humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
    -- копия шаблона
    local gui = template:Clone()
    -- висит над головой
    gui.Adornee = head
    -- удалится вместе с мобом
    gui.Parent = head
    -- цветная полоса
    local bar = gui.Background.Bar
    -- «45 / 60»
    local text = gui.Background.HealthText
    -- имя моба
    gui.NameLabel.Text = humanoid.DisplayName ~= "" and humanoid.DisplayName or model.Name

    -- обновить полоску
    local function Update()
        -- доля здоровья
        local k = math.clamp(humanoid.Health / math.max(humanoid.MaxHealth, 1), 0, 1)
        -- плавно укорачиваем
        TweenService:Create(bar, TweenInfo.new(0.2), {Size = UDim2.fromScale(k, 1)}):Play()
        -- цвет
        bar.BackgroundColor3 = ColorFor(k)
        -- числа
        text.Text = math.ceil(humanoid.Health) .. " / " .. math.ceil(humanoid.MaxHealth)
        -- погиб — прячем
        gui.Enabled = humanoid.Health > 0 and (SHOW_WHEN_FULL or k < 1)
    -- конец функции
    end
    -- урон или лечение
    humanoid.HealthChanged:Connect(Update)
    -- сменился максимум
    humanoid:GetPropertyChangedSignal("MaxHealth"):Connect(Update)
    -- сразу
    Update()
-- конец функции
end

-- мобы, которые уже есть
for _, obj in ipairs(workspace:GetDescendants()) do
    -- вешаем полоску
    if obj:IsA("Humanoid") then task.spawn(Attach, obj) end
-- конец перебора
end
-- появился новый объект
workspace.DescendantAdded:Connect(function(obj)
    -- это моб — вешаем полоску
    if obj:IsA("Humanoid") then task.spawn(Attach, obj) end
-- конец функции
end)

ClickDamage

Где: Workspace → Dummy · Script
Зачем: Манекен для проверки: урон по клику.

-- манекен для проверки
local dummy = script.Parent
-- его здоровье
local humanoid = dummy:WaitForChild("Humanoid")
-- клик мышью
local clicker = dummy:WaitForChild("ClickDetector")

-- клик по манекену
clicker.MouseClick:Connect(function()
    -- −15 здоровья
    humanoid:TakeDamage(15)
-- конец функции
end)
-- медленно лечится
while true do
    -- раз в секунду
    task.wait(1)
    -- +2, пока жив
    if humanoid.Health > 0 then humanoid.Health = math.min(humanoid.Health + 2, humanoid.MaxHealth) end
-- конец цикла
end

Проверка

Запусти Play (или Run) и убедись:

Собрать полоску здоровья одной командой