← Все практические скрипты
Игровые системы · Продвинутый · 40 мин

Бег на Shift и телефоне через единый контроллер

Удерживайте Shift или сенсорную кнопку: ускорение добавляется к другим бонусам.

Иллюстрация: Бег на Shift и телефоне через единый контроллер
🎯 Что получится

Ускорение по удержанию Shift или мобильной кнопки. Сервер проверяет запросы, а контроллер сочетает бег с бонусами от площадок.

1. Подготовьте объект

Где разместить: Продолжение урока 91: два новых скрипта и общий StatsController.

Структура в Explorer
ServerScriptService
  StatsController (ModuleScript из урока 91)
  SprintServer (Script)
StarterPlayer
  StarterPlayerScripts
    SprintClient (LocalScript)
ReplicatedStorage
  IgroSprintRequest (RemoteEvent, создаётся сервером)
  1. Сначала выполните урок «Единый контроллер: скорость, прыжок и размер». Не создавайте второй StatsController.
  2. В ServerScriptService добавьте обычный Script SprintServer и вставьте первый блок.
  3. В StarterPlayer → StarterPlayerScripts добавьте LocalScript SprintClient и вставьте второй блок.
  4. Запустите Play и удерживайте левый Shift. Для телефона используйте кнопку «Бег», которую создаёт ContextActionService.
  5. Добавьте SpeedPad из предыдущего урока: бонус площадки и бег должны работать вместе.
  6. Проверьте отпускание кнопки, гибель и возрождение, а также игру с двумя игроками.
  7. Не устанавливайте старые версии «Бег с выносливостью» или «Бег на телефоне» параллельно: они напрямую меняют WalkSpeed.
Карта файлов в Explorer

Это пути для скриптов из блоков кода ниже. Остальные объекты создайте по инструкции.

├── ServerScriptService
│   └── SprintServer (Script)
└── StarterPlayer
    └── StarterPlayerScripts
        └── SprintClient (LocalScript)

2. Вставьте код

ServerScriptService/SprintServer (Script)
-- Script: ServerScriptService/SprintServer
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Controller = require(script.Parent:WaitForChild("StatsController"))
local remote = ReplicatedStorage:FindFirstChild("IgroSprintRequest")
if not remote then
    remote = Instance.new("RemoteEvent")
    remote.Name = "IgroSprintRequest"
    remote.Parent = ReplicatedStorage
end
local lastCall = {}
remote.OnServerEvent:Connect(function(player, wantsSprint)
    if typeof(wantsSprint) ~= "boolean" then return end
    local now = os.clock()
    -- Do not throttle releases: otherwise a fast Shift tap can leave sprint stuck.
    if wantsSprint and now - (lastCall[player] or -100) < 0.08 then return end
    lastCall[player] = now
    local character = player.Character
    local humanoid = character and character:FindFirstChildOfClass("Humanoid")
    if not humanoid or humanoid.Health <= 0 then return end
    if wantsSprint then
        Controller.Apply(player, "Sprint", {speed = 1.5})
    else
        Controller.Remove(player, "Sprint")
    end
end)
Players.PlayerRemoving:Connect(function(player) lastCall[player] = nil end)
StarterPlayer/StarterPlayerScripts/SprintClient (LocalScript)
-- LocalScript: StarterPlayer/StarterPlayerScripts/SprintClient
local ContextActionService = game:GetService("ContextActionService")
local UserInputService = game:GetService("UserInputService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")
local remote = ReplicatedStorage:WaitForChild("IgroSprintRequest")

local function onSprint(_, inputState)
    if inputState == Enum.UserInputState.Begin then
        remote:FireServer(true)
    elseif inputState == Enum.UserInputState.End
        or inputState == Enum.UserInputState.Cancel then
        remote:FireServer(false)
    end
    return Enum.ContextActionResult.Pass
end
ContextActionService:BindAction(
    "IgroSprint", onSprint, true,
    Enum.KeyCode.LeftShift, Enum.KeyCode.ButtonL3
)
ContextActionService:SetTitle("IgroSprint", "Бег")
ContextActionService:SetPosition("IgroSprint", UDim2.new(1, -100, 1, -190))
Players.LocalPlayer.CharacterAdded:Connect(function()
    remote:FireServer(false)
end)
-- If the player switches windows while holding Shift, release the sprint effect.
UserInputService.WindowFocusReleased:Connect(function()
    remote:FireServer(false)
end)

3. Проверьте в игре

Нажмите Play в Roblox Studio и проверьте действие механики. Если механика не работает, откройте окно Output и проверьте тип скрипта, его расположение и названия объектов.

Ваш прогресс

Когда проверите механику в Roblox Studio, отметьте практику как выполненную. Отметка хранится только в этом браузере, не в личном кабинете.

Если объединяете несколько скриптов

Добавляйте механики по одной и проверяйте окно Output. Не создавайте несколько одинаковых систем монет или интерфейсов; скрипты, меняющие WalkSpeed, прыжок или освещение, могут влиять друг на друга.

⭐ Три шага к собственной игре
1. Повторите и измените

Измените множитель бега с 1.5 на 1.3.

2. Улучшите

Добавьте бег на ButtonL3 геймпада и проверьте работу.

3. Придумайте своё

Создайте гонку, где игроки выбирают между прыжком и скоростью.

4. Проверьте себя

Почему изменение скорости выполняется на сервере, а не только в LocalScript?

🛠 Если не работает

LocalScript должен быть в StarterPlayerScripts, а SprintServer — в ServerScriptService. В ReplicatedStorage появится IgroSprintRequest. Проверьте, что урок 91 установлен, и не дублируйте SprintServer. Мобильное управление проверяйте на реальном устройстве или эмуляторе Roblox Studio.