Загрузка данных



--// SPRINT SYSTEM: PC + MOBILE
--// Помести в StarterPlayer > StarterPlayerScripts

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

local player = Players.LocalPlayer
local playerGui = player:WaitForChild("PlayerGui")

-- НАСТРОЙКИ
local NORMAL_SPEED = 16
local SPRINT_SPEED = 25

local MAX_STAMINA = 100
local DRAIN_RATE = 25       -- расход в секунду
local REGEN_RATE = 18       -- восстановление в секунду
local MIN_STAMINA_TO_RUN = 5

local NORMAL_FOV = 70
local SPRINT_FOV = 80

local stamina = MAX_STAMINA
local sprintRequested = false
local sprinting = false

local character
local humanoid

local isMobile = UserInputService.TouchEnabled
    and not UserInputService.KeyboardEnabled

-- Удаляем старый интерфейс при повторном запуске
local oldGui = playerGui:FindFirstChild("SprintUI")
if oldGui then
    oldGui:Destroy()
end

--// СОЗДАНИЕ ИНТЕРФЕЙСА

local gui = Instance.new("ScreenGui")
gui.Name = "SprintUI"
gui.ResetOnSpawn = false
gui.IgnoreGuiInset = true
gui.DisplayOrder = 10
gui.Parent = playerGui

-- Общий стиль
local function addCorner(object, radius)
    local corner = Instance.new("UICorner")
    corner.CornerRadius = UDim.new(0, radius)
    corner.Parent = object
    return corner
end

local function addStroke(object, color, thickness, transparency)
    local stroke = Instance.new("UIStroke")
    stroke.Color = color
    stroke.Thickness = thickness
    stroke.Transparency = transparency or 0
    stroke.Parent = object
    return stroke
end

-- Панель стамины
local panel = Instance.new("Frame")
panel.Name = "StaminaPanel"
panel.AnchorPoint = Vector2.new(0.5, 1)
panel.Position = UDim2.new(0.5, 0, 1, -38)
panel.Size = UDim2.new(0, 290, 0, 65)
panel.BackgroundColor3 = Color3.fromRGB(18, 22, 34)
panel.BackgroundTransparency = 0.08
panel.BorderSizePixel = 0
panel.Parent = gui

addCorner(panel, 18)
addStroke(panel, Color3.fromRGB(105, 125, 165), 1.2, 0.55)

local panelGradient = Instance.new("UIGradient")
panelGradient.Color = ColorSequence.new({
    ColorSequenceKeypoint.new(0, Color3.fromRGB(30, 36, 55)),
    ColorSequenceKeypoint.new(1, Color3.fromRGB(15, 18, 29))
})
panelGradient.Rotation = 90
panelGradient.Parent = panel

-- Заголовок
local title = Instance.new("TextLabel")
title.Name = "StaminaTitle"
title.Position = UDim2.new(0, 16, 0, 7)
title.Size = UDim2.new(0, 180, 0, 22)
title.BackgroundTransparency = 1
title.Text = "⚡  STAMINA"
title.TextColor3 = Color3.fromRGB(235, 242, 255)
title.TextSize = 14
title.Font = Enum.Font.GothamBold
title.TextXAlignment = Enum.TextXAlignment.Left
title.Parent = panel

-- Проценты
local percent = Instance.new("TextLabel")
percent.Name = "StaminaPercent"
percent.AnchorPoint = Vector2.new(1, 0)
percent.Position = UDim2.new(1, -15, 0, 7)
percent.Size = UDim2.new(0, 65, 0, 22)
percent.BackgroundTransparency = 1
percent.Text = "100%"
percent.TextColor3 = Color3.fromRGB(110, 255, 180)
percent.TextSize = 14
percent.Font = Enum.Font.GothamBold
percent.TextXAlignment = Enum.TextXAlignment.Right
percent.Parent = panel

-- Фон полосы
local barBack = Instance.new("Frame")
barBack.Name = "BarBackground"
barBack.Position = UDim2.new(0, 15, 0, 36)
barBack.Size = UDim2.new(1, -30, 0, 14)
barBack.BackgroundColor3 = Color3.fromRGB(48, 55, 73)
barBack.BorderSizePixel = 0
barBack.ClipsDescendants = true
barBack.Parent = panel

addCorner(barBack, 7)

-- Заполнение стамины
local barFill = Instance.new("Frame")
barFill.Name = "BarFill"
barFill.Size = UDim2.fromScale(1, 1)
barFill.BackgroundColor3 = Color3.fromRGB(65, 245, 155)
barFill.BorderSizePixel = 0
barFill.Parent = barBack

addCorner(barFill, 7)

local barGradient = Instance.new("UIGradient")
barGradient.Color = ColorSequence.new({
    ColorSequenceKeypoint.new(0, Color3.fromRGB(40, 230, 140)),
    ColorSequenceKeypoint.new(1, Color3.fromRGB(115, 255, 195))
})
barGradient.Parent = barFill

--// МОБИЛЬНАЯ КНОПКА

local sprintButton
local buttonStroke
local buttonText

if isMobile then
    sprintButton = Instance.new("TextButton")
    sprintButton.Name = "SprintButton"
    sprintButton.AnchorPoint = Vector2.new(1, 1)
    sprintButton.Position = UDim2.new(1, -25, 1, -150)
    sprintButton.Size = UDim2.fromOffset(92, 92)
    sprintButton.BackgroundColor3 = Color3.fromRGB(27, 37, 55)
    sprintButton.BackgroundTransparency = 0.05
    sprintButton.BorderSizePixel = 0
    sprintButton.AutoButtonColor = false
    sprintButton.Text = ""
    sprintButton.Parent = gui

    addCorner(sprintButton, 28)
    buttonStroke = addStroke(
        sprintButton,
        Color3.fromRGB(70, 240, 160),
        2,
        0.1
    )

    local buttonGradient = Instance.new("UIGradient")
    buttonGradient.Color = ColorSequence.new({
        ColorSequenceKeypoint.new(0, Color3.fromRGB(48, 68, 91)),
        ColorSequenceKeypoint.new(1, Color3.fromRGB(21, 28, 43))
    })
    buttonGradient.Rotation = 45
    buttonGradient.Parent = sprintButton

    local icon = Instance.new("TextLabel")
    icon.Name = "SprintIcon"
    icon.Position = UDim2.new(0, 0, 0, 13)
    icon.Size = UDim2.new(1, 0, 0, 38)
    icon.BackgroundTransparency = 1
    icon.Text = "⚡"
    icon.TextSize = 30
    icon.Font = Enum.Font.GothamBold
    icon.TextColor3 = Color3.fromRGB(100, 255, 175)
    icon.Parent = sprintButton

    buttonText = Instance.new("TextLabel")
    buttonText.Name = "ButtonText"
    buttonText.Position = UDim2.new(0, 0, 0, 52)
    buttonText.Size = UDim2.new(1, 0, 0, 22)
    buttonText.BackgroundTransparency = 1
    buttonText.Text = "БЕГ"
    buttonText.TextSize = 14
    buttonText.Font = Enum.Font.GothamBold
    buttonText.TextColor3 = Color3.fromRGB(255, 255, 255)
    buttonText.Parent = sprintButton

    sprintButton.Activated:Connect(function()
        if stamina <= 0 then
            return
        end

        sprintRequested = not sprintRequested
    end)
end

--// ПОДКЛЮЧЕНИЕ ПЕРСОНАЖА

local function setupCharacter(newCharacter)
    character = newCharacter
    humanoid = newCharacter:WaitForChild("Humanoid")

    humanoid.WalkSpeed = NORMAL_SPEED
    sprintRequested = false
    sprinting = false

    if isMobile and buttonText then
        buttonText.Text = "БЕГ"
    end
end

player.CharacterAdded:Connect(setupCharacter)

if player.Character then
    task.spawn(setupCharacter, player.Character)
end

--// УПРАВЛЕНИЕ НА КОМПЬЮТЕРЕ

UserInputService.InputBegan:Connect(function(input, processed)
    if processed then
        return
    end

    if input.KeyCode == Enum.KeyCode.RightShift and not isMobile then
        sprintRequested = true
    end
end)

UserInputService.InputEnded:Connect(function(input)
    if input.KeyCode == Enum.KeyCode.RightShift and not isMobile then
        sprintRequested = false
    end
end)

-- Если окно потеряло фокус, прекращаем бег
UserInputService.WindowFocusReleased:Connect(function()
    sprintRequested = false
end)

--// ОБНОВЛЕНИЕ СТАМИНЫ, СКОРОСТИ И КАМЕРЫ

local currentFOV = NORMAL_FOV

RunService.RenderStepped:Connect(function(dt)
    if not humanoid or humanoid.Health <= 0 then
        return
    end

    local moving = humanoid.MoveDirection.Magnitude > 0.05

    -- Бег только при движении и наличии стамины
    sprinting = sprintRequested
        and moving
        and stamina > 0

    if sprinting then
        stamina = math.max(0, stamina - DRAIN_RATE * dt)

        if stamina <= 0 then
            sprintRequested = false
            sprinting = false
        end
    else
        stamina = math.min(
            MAX_STAMINA,
            stamina + REGEN_RATE * dt
        )
    end

    -- Скорость персонажа
    if sprinting then
        humanoid.WalkSpeed = SPRINT_SPEED
    else
        humanoid.WalkSpeed = NORMAL_SPEED
    end

    -- Камера плавно меняет поле зрения
    local targetFOV = sprinting and SPRINT_FOV or NORMAL_FOV
    currentFOV += (targetFOV - currentFOV)
        * math.min(dt * 5, 1)

    local camera = workspace.CurrentCamera
    if camera then
        camera.FieldOfView = currentFOV
    end

    -- Обновляем полосу стамины
    local ratio = stamina / MAX_STAMINA

    TweenService:Create(
        barFill,
        TweenInfo.new(0.12, Enum.EasingStyle.Linear),
        {Size = UDim2.new(ratio, 0, 1, 0)}
    ):Play()

    percent.Text = tostring(math.floor(stamina + 0.5)) .. "%"

    -- Цвет меняется при низкой стамине
    if ratio > 0.5 then
        barGradient.Color = ColorSequence.new({
            ColorSequenceKeypoint.new(0, Color3.fromRGB(40, 230, 140)),
            ColorSequenceKeypoint.new(1, Color3.fromRGB(115, 255, 195))
        })
        percent.TextColor3 = Color3.fromRGB(110, 255, 180)
    elseif ratio > 0.2 then
        barGradient.Color = ColorSequence.new({
            ColorSequenceKeypoint.new(0, Color3.fromRGB(255, 180, 50)),
            ColorSequenceKeypoint.new(1, Color3.fromRGB(255, 220, 95))
        })
        percent.TextColor3 = Color3.fromRGB(255, 205, 100)
    else
        barGradient.Color = ColorSequence.new({
            ColorSequenceKeypoint.new(0, Color3.fromRGB(255, 65, 85)),
            ColorSequenceKeypoint.new(1, Color3.fromRGB(255, 125, 125))
        })
        percent.TextColor3 = Color3.fromRGB(255, 100, 120)
    end

    -- Состояние мобильной кнопки
    if sprintButton and buttonText and buttonStroke then
        if sprintRequested and stamina > 0 then
            buttonText.Text = "БЕГ!"
            buttonStroke.Color = Color3.fromRGB(100, 255, 175)
        else
            buttonText.Text = "БЕГ"
            buttonStroke.Color = Color3.fromRGB(100, 125, 160)
        end
    end
end)