Roblox · Приключение · урок 4
Отбиваемся мечом, лечимся зельем, прячемся зельем невидимости. Побеждённые гоблины роняют монеты и возвращаются, а охотник даёт квест на их уничтожение.
Синим — что добавляем на этом уроке.
StarterPack └─ Sword (Tool) ├─ Handle (Part) — клинок └─ SwordScript (Script) ServerStorage ├─ Drop (Part) — мешочек с монетами │ └─ DropScript (Script) └─ Shop (Folder) — товары (урок «Магазин») ├─ HealingPotion (Tool) — Handle → Drink (Sound); PotionScript └─ InvisiblePotion (Tool) — Handle; InvisibleScript ServerScriptService └─ EnemyManager (Script) Workspace └─ Hunter (Model) — QuestGiver: «Уничтожение», 3, 30
Где: StarterPack → Sword · Script
Зачем: Удар мечом.
-- игроки
local Players = game:GetService("Players")
-- удаляет объекты через время
local Debris = game:GetService("Debris")
-- меч
local tool = script.Parent
-- клинок
local handle = tool:WaitForChild("Handle")
-- урон за удар
local DAMAGE = 25
-- длина взмаха
local COOLDOWN = 0.6
-- анимация взмаха
local slash = Instance.new("Animation")
-- стандартная R15
slash.AnimationId = "rbxassetid://522635514"
-- идёт взмах
local swinging = false
-- кого уже ударили этим взмахом
local hitList = {}
-- клик мышью
tool.Activated:Connect(function()
-- взмах ещё идёт
if swinging then return end
-- владелец
local humanoid = tool.Parent:FindFirstChildOfClass("Humanoid")
-- погибший не бьёт
if not humanoid or humanoid.Health <= 0 then return end
-- начали
swinging = true
-- новый взмах — список пуст
table.clear(hitList)
-- анимации владельца
local animator = humanoid:FindFirstChildOfClass("Animator")
-- взмах
if animator then animator:LoadAnimation(slash):Play() end
-- ждём
task.wait(COOLDOWN)
-- можно снова
swinging = false
-- конец функции
end)
-- клинок коснулся
handle.Touched:Connect(function(hit)
-- бьём только во время взмаха
if not swinging then return end
-- модель, которой принадлежит деталь
local model = hit:FindFirstAncestorOfClass("Model")
-- её Humanoid
local target = model and model:FindFirstChildOfClass("Humanoid")
-- не цель, сам себя или уже ударили
if not target or target.Health <= 0 or model == tool.Parent or hitList[target] then return end
-- игроков не бьём — только противников
if Players:GetPlayerFromCharacter(model) then return end
-- этим взмахом больше не бьём
hitList[target] = true
-- прошлая метка
local old = target:FindFirstChild("creator")
-- убираем
if old then old:Destroy() end
-- метка «кто ударил»
local tag = Instance.new("ObjectValue")
-- стандартное имя метки в Roblox
tag.Name = "creator"
-- игрок с мечом
tag.Value = Players:GetPlayerFromCharacter(tool.Parent)
-- в Humanoid противника
tag.Parent = target
-- через 2 секунды метка исчезнет
Debris:AddItem(tag, 2)
-- урон
target:TakeDamage(DAMAGE)
-- конец функции
end)Где: ServerStorage → Shop → HealingPotion · Script
Зачем: Лечит на 50.
-- удаляет объекты через время
local Debris = game:GetService("Debris")
-- зелье
local tool = script.Parent
-- сколько лечит
local HEAL = 50
-- клик — выпить
tool.Activated:Connect(function()
-- кто пьёт
local humanoid = tool.Parent:FindFirstChildOfClass("Humanoid")
-- погибшим не помочь
if not humanoid or humanoid.Health <= 0 then return end
-- +50, но не больше максимума
humanoid.Health = math.min(humanoid.Health + HEAL, humanoid.MaxHealth)
-- звук глотка
local sound = tool.Handle:FindFirstChild("Drink")
-- звук есть
if sound and humanoid.RootPart then
-- переносим в игрока — иначе пропадёт вместе с зельем
sound.Parent = humanoid.RootPart
-- буль
sound:Play()
-- потом удалим
Debris:AddItem(sound, 3)
-- конец проверки
end
-- зелье выпито
tool:Destroy()
-- конец функции
end)Где: ServerStorage → Shop → InvisiblePotion · Script
Зачем: Невидимость на 5 секунд.
-- здесь скрипт доработает после того, как зелье пропадёт из рук
local SSS = game:GetService("ServerScriptService")
-- зелье
local tool = script.Parent
-- секунд невидимости
local DURATION = 5
-- уже выпито
local used = false
-- плавно меняет прозрачность
local function Fade(saved, toInvisible)
-- 10 шагов
for i = 1, 10 do
-- доля невидимости
local k = toInvisible and i / 10 or 1 - i / 10
-- каждая деталь
for obj, base in pairs(saved) do
-- от своей прозрачности к 1
if obj.Parent then obj.Transparency = base + (1 - base) * k end
-- конец перебора
end
-- полсекунды на всё
task.wait(0.05)
-- конец цикла
end
-- конец функции
end
-- клик — выпить
tool.Activated:Connect(function()
-- уже
if used then return end
-- кто пьёт
local character = tool.Parent
-- Humanoid
local humanoid = character:FindFirstChildOfClass("Humanoid")
-- погибший не пьёт
if not humanoid or humanoid.Health <= 0 then return end
-- выпито
used = true
-- убираем из рук, но скрипт продолжает работать
tool.Parent = SSS
-- деталь → её прозрачность
local saved = {}
-- всё в персонаже
for _, obj in ipairs(character:GetDescendants()) do
-- видимые детали и лицо
if (obj:IsA("BasePart") or obj:IsA("Decal")) and obj.Name ~= "HumanoidRootPart" then
-- запоминаем
saved[obj] = obj.Transparency
-- конец проверки
end
-- конец перебора
end
-- противники перестают видеть
character:SetAttribute("Invisible", true)
-- исчезаем
Fade(saved, true)
-- ждём
task.wait(DURATION)
-- появляемся
Fade(saved, false)
-- снова виден
character:SetAttribute("Invisible", nil)
-- теперь зелье можно удалить
tool:Destroy()
-- конец функции
end)Где: ServerStorage → Drop · Script
Зачем: Мешочек с монетами.
-- игроки
local Players = game:GetService("Players")
-- мешочек
local drop = script.Parent
-- сколько монет внутри
local COINS = 5
-- через сколько секунд исчезнет
local LIFETIME = 30
-- уже подобран
local taken = false
-- касание
drop.Touched:Connect(function(hit)
-- уже взяли
if taken then return end
-- игрок?
local player = Players:GetPlayerFromCharacter(hit.Parent)
-- его таблица
local stats = player and player:FindFirstChild("leaderstats")
-- не игрок
if not stats then return end
-- больше не берётся
taken = true
-- монеты
stats.Coins.Value += COINS
-- мешочек пропал
drop:Destroy()
-- конец функции
end)
-- ждём
task.wait(LIFETIME)
-- никто не взял — убираем
if drop.Parent then drop:Destroy() endГде: ServerScriptService · Script
Зачем: Возрождение, награды, квест.
-- здесь лежит награда Drop
local SS = game:GetService("ServerStorage")
-- все противники
local enemies = workspace:WaitForChild("Enemies")
-- через сколько секунд противник вернётся
local RESPAWN_TIME = 10
-- монет за победу
local KILL_REWARD = 3
-- квест, которому засчитываются победы
local KILL_QUEST = "Уничтожение"
-- следим за одним противником
local function Setup(enemy)
-- копия целого — для возрождения
local sample = enemy:Clone()
-- где стоял
local spot = enemy:GetPivot()
-- Humanoid
local humanoid = enemy:WaitForChild("Humanoid")
-- противник погиб
humanoid.Died:Connect(function()
-- метка от меча
local tag = humanoid:FindFirstChild("creator")
-- кто победил
local player = tag and tag.Value
-- игрок ещё в игре
if player and player.Parent then
-- таблица
local stats = player:FindFirstChild("leaderstats")
-- монеты
if stats then stats.Coins.Value += KILL_REWARD end
-- квест
local quest = player:FindFirstChild("QuestInfo")
-- взят квест на противников
if quest and quest.Title.Value == KILL_QUEST then
-- +1
quest.Progress.Value += 1
-- конец проверки
end
-- конец проверки
end
-- мешочек с монетами
local drop = SS:FindFirstChild("Drop")
-- есть
if drop then
-- копия
local copy = drop:Clone()
-- там, где упал противник
copy:PivotTo(CFrame.new(enemy:GetPivot().Position))
-- в мир
copy.Parent = workspace
-- конец проверки
end
-- ждём
task.wait(RESPAWN_TIME)
-- убираем тело
enemy:Destroy()
-- новый противник
local new = sample:Clone()
-- на старое место
new:PivotTo(spot)
-- в игру — его EnemyScript запустится сам
new.Parent = enemies
-- следим и за ним
Setup(new)
-- конец функции
end)
-- конец функции
end
-- все противники
for _, enemy in ipairs(enemies:GetChildren()) do
-- следим
Setup(enemy)
-- конец перебора
endЗапусти Play (или Run) и убедись: