Roblox · Усиления

Броня: вторая полоска здоровья

Надел броню — над головой синяя полоска. Урон сначала снимается с брони и только потом со здоровья. Броня держится, пока её не пробьют (или до смерти).

Структура

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

StarterPack — или копии на карте для подбора
└─ Armor (Tool)
   ├─ Handle (Part) — модель; CanCollide выкл.
   │  └─ Use (Sound)
   ├─ Configuration (Configuration)
   │  ├─ Amount (NumberValue) — сколько урона выдержит броня, 50
   │  ├─ Uses (NumberValue) — сколько раз можно использовать, 1
   │  └─ Cooldown (NumberValue) — секунд между использованиями, 1
   └─ ArmorItem (Script)
ServerScriptService
└─ ArmorServer (Script) — следит за здоровьем всех персонажей

Шаги

  1. Предмет — Tool с деталью Handle (CanCollide выкл.), в Handle — Sound «Use». Configuration — папка настроек: наведи на Tool → «+» → Configuration, внутри NumberValue (имена и числа — в «Структуре»).
  2. Предмет только записывает броню в атрибуты Humanoid (Armor, ArmorMax). Считает урон отдельный ArmorServer в ServerScriptService: подписка на здоровье должна жить дольше предмета.
  3. Как работает: при каждом уменьшении здоровья ArmorServer смотрит, сколько брони, возвращает здоровье на эту часть урона и уменьшает броню. Полоска над головой показывает остаток.
  4. Удар, который сразу ставит здоровье в 0, броня не остановит — урон должен идти через TakeDamage.
  5. Полная броня второй раз не надевается.

Скрипты

ArmorServer

Где: ServerScriptService · Script
Зачем: Урон сначала снимает броню; полоска над головой.

-- все игроки
local Players = game:GetService("Players")

-- следит за здоровьем: урон сначала снимает броню
local function Watch(humanoid)
    -- голова — над ней полоска
    local head = humanoid.Parent:WaitForChild("Head")
    -- полоска брони
    local gui = Instance.new("BillboardGui")
    -- имя
    gui.Name = "ArmorGui"
    -- 4 × 0.35 studs
    gui.Size = UDim2.new(4, 0, 0.35, 0)
    -- над головой
    gui.StudsOffset = Vector3.new(0, 2.6, 0)
    -- висит над головой
    gui.Adornee = head
    -- в голову
    gui.Parent = head
    -- фон
    local back = Instance.new("Frame")
    -- во всю полоску
    back.Size = UDim2.fromScale(1, 1)
    -- тёмный
    back.BackgroundColor3 = Color3.fromRGB(30, 30, 40)
    -- в полоску
    back.Parent = gui
    -- броня
    local bar = Instance.new("Frame")
    -- синяя
    bar.BackgroundColor3 = Color3.fromRGB(80, 160, 255)
    -- без рамки
    bar.BorderSizePixel = 0
    -- на фон
    bar.Parent = back
    -- обновить полоску
    local function Show()
        -- броня сейчас
        local armor = humanoid:GetAttribute("Armor") or 0
        -- максимум
        local max = humanoid:GetAttribute("ArmorMax") or 1
        -- длина полосы
        bar.Size = UDim2.fromScale(math.clamp(armor / max, 0, 1), 1)
        -- брони нет — полоски нет
        gui.Enabled = armor > 0
    -- конец функции
    end
    -- сразу
    Show()
    -- броня изменилась
    humanoid:GetAttributeChangedSignal("Armor"):Connect(Show)
    -- здоровье до удара
    local last = humanoid.Health
    -- здоровье изменилось
    humanoid.HealthChanged:Connect(function(health)
        -- сколько брони
        local armor = humanoid:GetAttribute("Armor") or 0
        -- получил урон, жив, броня есть
        if health < last and health > 0 and armor > 0 then
            -- сколько урона забирает броня
            local absorb = math.min(armor, last - health)
            -- броня тратится
            humanoid:SetAttribute("Armor", armor - absorb)
            -- здоровье возвращаем на столько же
            last = health + absorb
            -- здоровье не убавилось (или убавилось меньше)
            humanoid.Health = last
        -- лечение или броня кончилась
        else
            -- просто запоминаем
            last = health
        -- конец проверки
        end
    -- конец обработчика
    end)
-- конец функции
end

-- новый персонаж
local function OnCharacter(character)
    -- следим за его здоровьем
    Watch(character:WaitForChild("Humanoid"))
-- конец функции
end
-- игрок зашёл
Players.PlayerAdded:Connect(function(player)
    -- каждый его персонаж
    player.CharacterAdded:Connect(OnCharacter)
    -- уже появился
    if player.Character then OnCharacter(player.Character) end
-- конец обработчика
end)
-- игроки, что уже в игре
for _, player in ipairs(Players:GetPlayers()) do
    -- их будущие персонажи
    player.CharacterAdded:Connect(OnCharacter)
    -- и нынешние
    if player.Character then OnCharacter(player.Character) end
-- конец перебора
end

ArmorItem

Где: StarterPack → Armor · Script
Зачем: Выдаёт полную броню.

-- броня (Tool)
local tool = script.Parent
-- модель
local handle = tool:WaitForChild("Handle")
-- настройки
local config = tool:WaitForChild("Configuration")
-- звук использования
local useSound = handle:WaitForChild("Use")
-- все игроки
local Players = game:GetService("Players")
-- время прошлого использования
local lastUse = 0
-- сколько раз ещё можно
local uses = config.Uses.Value
-- подсказка на панели предметов
tool.ToolTip = "Броня: " .. uses

-- клик, пока предмет в руках (событие приходит и на сервер)
tool.Activated:Connect(function()
    -- кто держит
    local humanoid = tool.Parent:FindFirstChildOfClass("Humanoid")
    -- нет персонажа или он мёртв
    if not humanoid or humanoid.Health <= 0 then return end
    -- его персонаж
    local character = humanoid.Parent
    -- и игрок
    local player = Players:GetPlayerFromCharacter(character)
    -- броня и так полная — не тратим
    if (humanoid:GetAttribute("Armor") or 0) >= config.Amount.Value then return end
    -- откат ещё не прошёл
    if os.clock() - lastUse < config.Cooldown.Value then return end
    -- запоминаем
    lastUse = os.clock()
    -- звук
    useSound:Play()
    -- максимум брони
    humanoid:SetAttribute("ArmorMax", config.Amount.Value)
    -- броня полная — дальше работает ArmorServer
    humanoid:SetAttribute("Armor", config.Amount.Value)
    -- минус одно использование
    uses -= 1
    -- обновляем подсказку
    tool.ToolTip = "Броня: " .. uses
    -- использования кончились
    if uses <= 0 then
        -- убираем из рук; здесь скрипт продолжит работать
        tool.Parent = game:GetService("ServerScriptService")
        -- ждём конца эффекта — иначе его таймер остановится
        task.wait(1)
        -- теперь удаляем совсем
        tool:Destroy()
    -- конец проверки
    end
-- конец обработчика
end)

Проверка

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

Собрать броню одной командой