Roblox · Королевская битва · урок 10

Экран смерти и дроп

Погиб — мир размывается, появляется экран смерти с отсчётом и кнопкой «В лобби». Там, где погиб, остаются его предметы и шар здоровья.

Структура

Синим — что добавляем на этом уроке.

Players — CharacterAutoLoads выкл. (ставит DeathServer)
StarterGui
└─ DeathGui (ScreenGui) — ResetOnSpawn выкл.
   └─ DeathFrame (Frame) — Visible выкл.; UIAspectRatioConstraint
      ├─ Skull (ImageLabel)
      ├─ TeleportButton (TextButton) — «В лобби»
      ├─ TimeToTeleport (TextLabel)
      └─ DeathLocal (LocalScript)
ReplicatedStorage
└─ DeathEvent (RemoteEvent)
ServerStorage
└─ HealthDrop (Part) — зелёный шар; Sound
ServerScriptService
├─ DeathServer (Script)
└─ DropServer (Script)

Шаги

  1. DeathGui → DeathFrame: ImageLabel «Skull» (Image — ID картинки), TextButton «TeleportButton», TextLabel «TimeToTeleport». UIAspectRatioConstraint в DeathFrame — пропорции не плывут на разных экранах.
  2. Размытие — BlurEffect в Lighting (DeathLocal создаёт его сам, Size 0 → 20). Одновременно работает только один BlurEffect.
  3. Players → CharacterAutoLoads выкл.: персонаж не возрождается сам. DeathServer возрождает по кнопке или после отсчёта (и страхует, если клиент промолчал). Возрождать можно только мёртвых.
  4. В методичке игрока переносило в отдельный плейс лобби; у нас лобби на той же карте — LoadCharacter возрождает у SpawnLocation лобби.
  5. Кнопка подписана один раз (в методичке — при каждой смерти: после третьей смерти клик срабатывал трижды).
  6. DropServer: предметы погибшего (рюкзак и руки) раскладываются вокруг места смерти — их можно забрать. Через секунду — шар здоровья: +40 один раз (в методичке лечил много раз, пока играл звук), исчезает через 2 минуты.

Скрипты

DeathServer

Где: ServerScriptService · Script
Зачем: Возрождение.

-- игроки
local Players = game:GetService("Players")
-- события
local RS = game:GetService("ReplicatedStorage")
-- кнопка «В лобби»
local deathEvent = RS:WaitForChild("DeathEvent")
-- столько же, сколько отсчёт на экране смерти
local RESPAWN_TIME = 8
-- сами решаем, когда игрок возрождается
Players.CharacterAutoLoads = false

-- игрок мёртв?
local function IsDead(player)
    -- Humanoid
    local humanoid = player.Character and player.Character:FindFirstChildOfClass("Humanoid")
    -- нет персонажа или здоровье 0
    return not humanoid or humanoid.Health <= 0
-- конец функции
end
-- возродить в лобби
local function Respawn(player)
    -- только мёртвых — живой не «перезапустится» кнопкой
    if player.Parent and IsDead(player) then player:LoadCharacter() end
-- конец функции
end
-- игрок зашёл
local function Setup(player)
    -- новый персонаж
    player.CharacterAdded:Connect(function(character)
        -- погиб
        character:WaitForChild("Humanoid").Died:Connect(function()
            -- страховка: если клиент не нажал — возродим сами
            task.delay(RESPAWN_TIME + 2, Respawn, player)
        -- конец функции
        end)
    -- конец функции
    end)
    -- первый персонаж — сами (автозагрузка выключена)
    if not player.Character then player:LoadCharacter() end
-- конец функции
end
-- новые игроки
Players.PlayerAdded:Connect(Setup)
-- кто зашёл раньше скрипта
for _, player in ipairs(Players:GetPlayers()) do task.spawn(Setup, player) end
-- нажал «В лобби» или кончился отсчёт
deathEvent.OnServerEvent:Connect(Respawn)

DeathLocal

Где: StarterGui → DeathGui → DeathFrame · LocalScript
Зачем: Экран смерти.

-- игроки
local Players = game:GetService("Players")
-- события
local RS = game:GetService("ReplicatedStorage")
-- плавность
local TS = game:GetService("TweenService")
-- размытие
local Lighting = game:GetService("Lighting")
-- этот игрок
local player = Players.LocalPlayer
-- DeathFrame
local frame = script.Parent
-- «В лобби»
local button = frame:WaitForChild("TeleportButton")
-- отсчёт
local timeLabel = frame:WaitForChild("TimeToTeleport")
-- попросить возрождение
local deathEvent = RS:WaitForChild("DeathEvent")
-- секунд до автоматического возвращения
local RESPAWN_TIME = 8
-- размытие мира
local blur = Lighting:FindFirstChild("DeathScreenBlur") or Instance.new("BlurEffect")
-- имя
blur.Name = "DeathScreenBlur"
-- пока не размыто
blur.Size = 0
-- включено (сила 0)
blur.Parent = Lighting
-- плавно
local info = TweenInfo.new(1, Enum.EasingStyle.Quint, Enum.EasingDirection.InOut)
-- сейчас мёртв?
local dead = false
-- экран смерти скрыт
frame.Visible = false

-- в лобби
local function Leave()
    -- уже
    if not dead then return end
    -- больше не ждём
    dead = false
    -- прячем экран
    frame.Visible = false
    -- мир снова чёткий
    TS:Create(blur, info, {Size = 0}):Play()
    -- сервер возрождает
    deathEvent:FireServer()
-- конец функции
end
-- подписка одна (в методичке — при каждой смерти)
button.MouseButton1Click:Connect(Leave)

-- новый персонаж
local function OnCharacter(character)
    -- Humanoid
    local humanoid = character:WaitForChild("Humanoid")
    -- жив
    dead = false
    -- экран скрыт
    frame.Visible = false
    -- без размытия
    blur.Size = 0
    -- погиб
    humanoid.Died:Connect(function()
        -- мёртв
        dead = true
        -- мир размывается
        TS:Create(blur, info, {Size = 20}):Play()
        -- секунда
        task.wait(1)
        -- уже нажал
        if not dead then return end
        -- экран смерти
        frame.Visible = true
        -- отсчёт
        for i = RESPAWN_TIME, 1, -1 do
            -- нажал кнопку
            if not dead then return end
            -- текст
            timeLabel.Text = "В лобби через " .. i .. " с"
            -- секунда
            task.wait(1)
        -- конец отсчёта
        end
        -- время вышло
        Leave()
    -- конец функции
    end)
-- конец функции
end
-- каждый новый персонаж
player.CharacterAdded:Connect(OnCharacter)
-- текущий
if player.Character then OnCharacter(player.Character) end

DropServer

Где: ServerScriptService · Script
Зачем: Лут погибшего и шар здоровья.

-- игроки
local Players = game:GetService("Players")
-- образец дропа
local SS = game:GetService("ServerStorage")
-- удаление через время
local Debris = game:GetService("Debris")
-- шар здоровья (внутри Sound)
local healthSample = SS:WaitForChild("HealthDrop")
-- сколько лечит
local HEAL = 40
-- через сколько секунд исчезнет, если не взяли
local LIFETIME = 120

-- шар здоровья на месте смерти
local function DropHealth(position)
    -- копия
    local orb = healthSample:Clone()
    -- висит
    orb.Anchored = true
    -- сквозь
    orb.CanCollide = false
    -- где погиб
    orb.Position = position
    -- в мир
    orb.Parent = workspace
    -- ещё не взяли
    local used = false
    -- коснулись
    orb.Touched:Connect(function(hit)
        -- персонаж
        local humanoid = hit.Parent:FindFirstChildOfClass("Humanoid")
        -- уже взяли или мёртв
        if used or not humanoid or humanoid.Health <= 0 then return end
        -- один раз (в методичке лечил, пока играл звук)
        used = true
        -- лечим
        humanoid.Health = math.min(humanoid.Health + HEAL, humanoid.MaxHealth)
        -- звук
        orb.Sound:Play()
        -- шар исчезает
        orb.Transparency = 1
        -- удалим, когда доиграет звук
        Debris:AddItem(orb, 2)
    -- конец функции
    end)
    -- не взяли — исчезнет сам
    Debris:AddItem(orb, LIFETIME)
-- конец функции
end

-- предметы погибшего — на землю
local function DropTools(player, character, position)
    -- список
    local tools = {}
    -- рюкзак
    for _, tool in ipairs(player.Backpack:GetChildren()) do
        -- инструменты
        if tool:IsA("Tool") then table.insert(tools, tool) end
    -- конец перебора
    end
    -- что было в руках
    local held = character:FindFirstChildOfClass("Tool")
    -- тоже
    if held then table.insert(tools, held) end
    -- каждый
    for i, tool in ipairs(tools) do
        -- за что двигать
        local handle = tool:FindFirstChild("Handle")
        -- есть
        if handle then
            -- раскладываем по кругу
            local angle = i / #tools * math.pi * 2
            -- на землю
            tool.Parent = workspace:FindFirstChild("Loot") or workspace
            -- вокруг места смерти
            handle.CFrame = CFrame.new(position + Vector3.new(math.cos(angle) * 4, 1, math.sin(angle) * 4))
        -- конец проверки
        end
    -- конец перебора
    end
-- конец функции
end

-- игрок зашёл
local function Setup(player)
    -- новый персонаж
    player.CharacterAdded:Connect(function(character)
        -- погиб
        character:WaitForChild("Humanoid").Died:Connect(function()
            -- центр
            local root = character:FindFirstChild("HumanoidRootPart")
            -- уже нет
            if not root then return end
            -- место смерти
            local position = root.Position
            -- лут погибшего
            DropTools(player, character, position)
            -- секунда
            task.wait(1)
            -- шар здоровья
            DropHealth(position)
        -- конец функции
        end)
    -- конец функции
    end)
-- конец функции
end
-- новые игроки
Players.PlayerAdded:Connect(Setup)
-- кто зашёл раньше скрипта
for _, player in ipairs(Players:GetPlayers()) do Setup(player) end

Проверка

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