Нажми — и деталь появится в мире
- ⏱ Сколько займёт
- 30–50 минут, 5 шагов. Каждый шаг заканчивается результатом на экране.
- 💻 Что нужно
- Компьютер с Windows или macOS. Понадобится Roblox Studio — бесплатная, поставим на первом шаге. С телефона этот квест не проходится.
- ⏸ Если прервёшься
- Ничего не потеряется: прогресс сохраняется на этом устройстве. Вернёшься — продолжишь с того же шага.
- 🎓 Чему научишься
- клавиши и LocalScript · кулдаун · клиент и сервер
Анимация по команде игрока
Боцман Клык встаёт напротив и складывает руки: «Ну, ударь».
Ты жмёшь кнопку — герой машет. Клык не впечатлён: «Слишком часто. Так победит тот, кто быстрее долбит по клавише».
Между ударами нужна пауза. Она превращает мельницу руками в честный бой.
Это запись из Roblox Studio: удар по клавише и пауза между ударами — ровно то, что ты сделаешь за этот квест. Полоска на экране — просто подсказка для записи, рисовать её не обязательно.
До сих пор анимации включались автоматически. Сегодня их будет запускать человек.
Нажатие клавиши — дело личное: сервер не знает, что ты нажал F. Значит, ловить клавиши обязан LocalScript, и положим мы его в StarterPlayer → StarterCharacterScripts: оттуда Roblox кладёт копию скрипта прямо в персонажа — и после каждого возрождения удар работает заново.
- 1StarterPlayer → StarterCharacterScriptsСюда кладут LocalScript — он работает у каждого игрока отдельно и заново запускается после каждого возрождения. Клавиши ловит только он.
- 2ПКМ → Insert Object → LocalScriptНазови
PunchOnKey. Обычный Script здесь не сработает: сервер не знает, что ты нажал F. - 3Проверь: Play → клавиша FУдар должен идти один раз на нажатие. Долбит без остановки — не хватает кулдауна.
- 4RemoteEvent — чтобы удар видели всеВ
ReplicatedStorageположи RemoteEvent. Клиент просит, сервер решает — золотое правило.
Обрати внимание: удар не зациклен. Зацикленная анимация удара выглядела бы как мельница.
Ловим клавишу
local UserInputService = game:GetService("UserInputService") local character = script.Parent -- скрипт лежит внутри персонажа local humanoid = character:WaitForChild("Humanoid") local animator = humanoid:FindFirstChildOfClass("Animator") or Instance.new("Animator", humanoid) local animation = Instance.new("Animation") animation.AnimationId = "rbxassetid://9093241065" -- свой ID local punch = animator:LoadAnimation(animation) UserInputService.InputBegan:Connect(function(input, processed) if processed then return end -- игрок печатает в чате — не мешаем if input.KeyCode == Enum.KeyCode.F then punch:Play() end end)
UserInputService — служба, которая слышит клавиши, мышь и касания экрана. InputBegan срабатывает в момент нажатия. Аргумент processed говорит, «съел» ли это нажатие интерфейс: если игрок печатает в чате, буква F не должна бить. Скрипт лежит в StarterPlayer → StarterCharacterScripts: Roblox кладёт его копию внутрь персонажа при каждом появлении, поэтому script.Parent — это персонаж, а после смерти дорожка создаётся заново и удар не пропадает.Запусти и нажми F. Персонаж ударит.

- 1StarterPlayer — разверни, внутри StarterPlayerScriptsЖми треугольник слева от строки: раскроются StarterPlayerScripts и StarterCharacterScripts. LocalScript с клавишей F кладут в первую. В ServerScriptService он не заругается — он просто промолчит, и это самая обидная ошибка новичка.
- 2ReplicatedStorage — единственная общая папкаЕё видят и клиент, и сервер. Наведи на строку → «+» → RemoteEvent, назови PunchEvent. Это мост: клиент кричит FireServer, сервер слышит OnServerEvent.
- 3ServerScriptService — обычный Script для всехОн ловит сигнал и включает анимацию удара так, чтобы её увидели остальные игроки. Правило на всю жизнь: клиент просит, сервер решает.
- 4Синий треугольник ▶ — проверь клавишу FУдар должен идти один раз на нажатие. Долбит без остановки — не хватает кулдауна: флажок canPunch и task.wait(0.8).
- 5Вкладка Script — окно OutputВкладки View в этой Studio нет, Output открывают отсюда. Красная строка назовёт скрипт и номер строки — читай до конца, там уже написан ответ.
Это настоящий экран Roblox Studio 2026 — такой же, как у тебя: та же лента вкладок, тот же Explorer со всеми сервисами, та же панель Properties. Нажимай на кружки по порядку: метка покажет место, строка ниже объяснит, зачем оно. Чего на кадре нет — про то честно написано словами. Отмечай пройденное — прогресс сохранится.
Чтобы не спамили
local canPunch = true UserInputService.InputBegan:Connect(function(input, processed) if processed then return end if input.KeyCode ~= Enum.KeyCode.F then return end if not canPunch then return end -- ещё не перезарядились canPunch = false punch:Play() task.wait(0.8) -- пауза между ударами canPunch = true end)
UserInputService.InputBegan:Connect(...) целиком — оставишь оба, и первый по-прежнему будет бить без паузы. Приём называется кулдаун. Переменная-флажок canPunch закрывается на время удара и открывается обратно. Без него игрок задолбит клавишу и получит дёргающуюся кашу вместо анимации. Знак ~= в Lua означает «не равно».Кулдаун есть в каждой игре, где что-то можно нажимать: удар, выстрел, способность, прыжок. Запомни этот приём — пригодится всюду.
local CAS = game:GetService("ContextActionService")
local function onPunch(_, state)
if state ~= Enum.UserInputState.Begin then return end
if not canPunch then return end
canPunch = false
punch:Play()
task.wait(0.8)
canPunch = true
end
CAS:BindAction("Punch", onPunch, true, Enum.KeyCode.F)
Третий аргумент
true и означает «покажи кнопку на сенсорном экране». Проверка state ~= Enum.UserInputState.Begin обязательна: без неё действие сработает и на нажатие, и на отпускание — удар пойдёт дважды.
Почему удар нельзя жать без конца
Пауза между ударами — кулдаун — существует в каждой боевой игре. Без неё побеждает тот, у кого быстрее палец, а не тот, кто лучше играет.
Второе назначение паузы — читаемость: противник должен успеть увидеть замах и среагировать. Бой без пауз выглядит как каша.
Профессионалы делят удар на три части: замах, попадание, возврат. Игрок реагирует на замах — и это делает бой честным.
Удар, который виден всем
Поэтому клиент только просит: «я ударил», а сервер сам проверяет паузу и включает удар. Передают такие сообщения через RemoteEvent.
-- ReplicatedStorage → RemoteEvent с именем PunchEvent -- В LocalScript, вместо punch:Play(): game.ReplicatedStorage.PunchEvent:FireServer() -- В Script (ServerScriptService): local ev = game.ReplicatedStorage:WaitForChild("PunchEvent") local COOLDOWN = 0.8 local lastHit = {} -- когда игрок бил в прошлый раз local tracks = {} -- готовая дорожка на каждого ev.OnServerEvent:Connect(function(player) local now = os.clock() if lastHit[player] and now - lastHit[player] < COOLDOWN then return end lastHit[player] = now -- кулдаун считает сервер, а не клиент local character = player.Character if not character then return end local humanoid = character:WaitForChild("Humanoid") local animator = humanoid:FindFirstChildOfClass("Animator") or Instance.new("Animator", humanoid) local track = tracks[character] if not track then -- дорожку грузим один раз local animation = Instance.new("Animation") animation.AnimationId = "rbxassetid://9093241065" track = animator:LoadAnimation(animation) tracks[character] = track end track:Play() end)
FireServer — «эй, сервер, случилось вот что». OnServerEvent — «сервер слушает». Первым аргументом сервер всегда получает игрока, который прислал сообщение — это Roblox добавляет сам, подделать нельзя. Паузу считает сервер: клиент может слать FireServer хоть сто раз в секунду — пока не прошёл COOLDOWN, сервер просто ничего не сделает. И дорожку мы грузим один раз на персонажа, а не заново на каждый удар.Это фундамент любой многопользовательской игры. Всё, что должны видеть другие, проходит через сервер.
Свои три действия
Набор из трёх действий на клавишах — это уже система управления персонажем. В играх такое называют «мувсет».
Задание Гильдии: сделай так, чтобы после удара из кулака вылетала искра — ParticleEmitter с коротким Lifetime. Эффект в момент действия работает как восклицательный знак.
Поднимай флаг.