Roblox · Шутер · урок 7
Замах по клику, в нужный момент анимации граната вылетает вперёд-вверх и через полторы секунды взрывается.
Синим — что добавляем на этом уроке.
Workspace └─ Grenade (Tool) ├─ Handle (Part) — модель гранаты │ ├─ Throw (Sound) — звук броска │ ├─ Boom (Sound) — звук взрыва │ ├─ Attachment (Attachment) — точка приложения силы │ └─ VectorForce (VectorForce) — Attachment0 = Attachment ├─ Animation (Animation) — AnimationId броска ├─ Throw (RemoteEvent) — клиент → сервер ├─ GrenadeLocal (LocalScript) └─ GrenadeServer (Script)
Где: Workspace → Grenade · LocalScript
Зачем: По клику играет замах; на кадре Release просит сервер бросить.
-- граната (Tool)
local grenade = script.Parent
-- анимация броска
local anim = grenade:WaitForChild("Animation")
-- сигнал «бросок» на сервер
local throwEvent = grenade:WaitForChild("Throw")
-- загрузим, когда возьмём гранату
local animTrack = nil
-- бросок уже начат?
local thrown = false
-- взяли гранату
local function OnEquipped()
-- анимации ещё нет — бросим без замаха
if anim.AnimationId == "" then return end
-- Humanoid персонажа
local humanoid = grenade.Parent:WaitForChild("Humanoid")
-- готовим анимацию
animTrack = humanoid.Animator:LoadAnimation(anim)
-- анимация дошла до именованного кадра
animTrack.KeyframeReached:Connect(function(kfName)
-- кадр, где рука отпускает гранату
if kfName == "Release" then
-- просим сервер бросить
throwEvent:FireServer()
-- конец проверки
end
-- конец обработчика кадра
end)
-- конец функции
end
-- каждый раз, когда берут в руки
grenade.Equipped:Connect(OnEquipped)
-- подобрали с земли: скрипт запустился уже в руках — Equipped был раньше
if grenade.Parent and grenade.Parent:FindFirstChildOfClass("Humanoid") then OnEquipped() end
-- убрали гранату
grenade.Unequipped:Connect(function()
-- бросок отменён — можно снова
thrown = false
-- конец обработчика
end)
-- клик, пока граната в руках
grenade.Activated:Connect(function()
-- уже бросаем — второй раз не надо
if thrown then return end
-- бросок начат
thrown = true
-- анимация есть
if animTrack then
-- замах — бросок на кадре Release
animTrack:Play()
-- анимации нет
else
-- бросаем сразу
throwEvent:FireServer()
-- конец проверки
end
-- конец обработчика
end)Где: Workspace → Grenade · Script
Зачем: Бросает копию гранаты, взрывает её и убирает гранату из инвентаря.
-- граната (Tool)
local grenade = script.Parent
-- модель гранаты
local handle = grenade:WaitForChild("Handle")
-- сигнал «бросок» от клиента
local throwEvent = grenade:WaitForChild("Throw")
-- удаление по таймеру
local Debris = game:GetService("Debris")
-- граната одна — бросок один
local thrown = false
-- клиент дошёл до кадра Release
throwEvent.OnServerEvent:Connect(function(player)
-- уже брошена или не в руках у этого игрока
if thrown or grenade.Parent ~= player.Character then return end
-- запоминаем
thrown = true
-- звук броска
handle.Throw:Play()
-- летящая копия гранаты
local grenadeClone = handle:Clone()
-- отскакивает от земли и стен
grenadeClone.CanCollide = true
-- в мир
grenadeClone.Parent = workspace
-- граната в руке исчезла
handle.Transparency = 1
-- корпус персонажа
local hrp = player.Character:WaitForChild("HumanoidRootPart")
-- направление: вперёд и вверх
local dir = hrp.CFrame.LookVector + hrp.CFrame.UpVector
-- толчок; учитываем массу — любая граната летит одинаково
grenadeClone.VectorForce.Force = dir * grenadeClone.AssemblyMass * 300
-- толкаем 0,2 секунды
task.wait(0.2)
-- дальше летит сама
grenadeClone.VectorForce.Enabled = false
-- запал
task.wait(1.5)
-- звук взрыва
grenadeClone.Boom:Play()
-- взрыв
local exp = Instance.new("Explosion")
-- там, где граната
exp.Position = grenadeClone.Position
-- радиус
exp.BlastRadius = 20
-- сила отбрасывания
exp.BlastPressure = 500000
-- взрываем
exp.Parent = workspace
-- граната исчезла
grenadeClone.Transparency = 1
-- стоит на месте, пока доигрывает звук
grenadeClone.Anchored = true
-- ни с чем не сталкивается
grenadeClone.CanCollide = false
-- через 5 с удаляется
Debris:AddItem(grenadeClone, 5)
-- убираем гранату из инвентаря — в самом конце: скрипт внутри неё
grenade:Destroy()
-- конец обработчика
end)Запусти Play (или Run) и убедись: