Roblox · RPG · урок 10
Мобы для охоты: у каждого свой уровень, полоса здоровья с числами, они нападают на игрока, а за победу дают опыт и монеты. Над каждым ударом взлетает цифра урона.
Синим — что добавляем на этом уроке.
Workspace └─ Mobs (Folder) └─ Wolf (Model) — Humanoid: DisplayDistanceType None ├─ HealthGui (BillboardGui) — Adornee = Head │ ├─ Lvl (TextLabel) │ └─ Background (Frame) │ ├─ Bar (Frame) — полоса │ │ └─ HealthBar (Script) │ └─ HealthValue (TextLabel) └─ MobAI (Script) ReplicatedStorage └─ Indicator (Part) — маленький, прозрачный, Anchored └─ Num (BillboardGui) └─ Damage (TextLabel) ServerScriptService ├─ MobManager (Script) └─ DamageIndicatorSystem (Script)
Где: Workspace → Mobs → Wolf → HealthGui → Background → Bar · Script
Зачем: Полоса здоровья моба.
-- полоса здоровья
local bar = script.Parent
-- HealthGui: Bar → Background → HealthGui
local gui = bar.Parent.Parent
-- «120 / 150»
local healthText = bar.Parent:WaitForChild("HealthValue")
-- «Ур. 3»
local lvlText = gui:WaitForChild("Lvl")
-- модель моба
local mob = gui.Parent
-- его здоровье
local humanoid = mob:WaitForChild("Humanoid")
-- уровень моба (ставит MobManager)
local level = mob:WaitForChild("Level")
-- обновить полоску
local function Update()
-- длина = доля здоровья
bar.Size = UDim2.fromScale(math.clamp(humanoid.Health / humanoid.MaxHealth, 0, 1), 1)
-- числа
healthText.Text = math.ceil(humanoid.Health) .. " / " .. humanoid.MaxHealth
-- уровень
lvlText.Text = "Ур. " .. level.Value
-- конец функции
end
-- урон
humanoid.HealthChanged:Connect(Update)
-- новый максимум
humanoid:GetPropertyChangedSignal("MaxHealth"):Connect(Update)
-- новый уровень
level.Changed:Connect(Update)
-- сразу
Update()Где: Workspace → Mobs → Wolf · Script
Зачем: Погоня и укусы.
-- игроки
local Players = game:GetService("Players")
-- моб
local mob = script.Parent
-- Humanoid
local humanoid = mob:WaitForChild("Humanoid")
-- центр
local root = mob:WaitForChild("HumanoidRootPart")
-- уровень — от него урон
local level = mob:WaitForChild("Level")
-- Animator
local animator = humanoid:FindFirstChildOfClass("Animator") or Instance.new("Animator", humanoid)
-- замечает игрока ближе 30 studs
local SIGHT = 30
-- кусает ближе 5 studs
local ATTACK_RANGE = 5
-- секунд между укусами
local COOLDOWN = 1.2
-- ходьба
local walk = Instance.new("Animation")
-- стандартная R15
walk.AnimationId = "rbxassetid://507777826"
-- загружаем
local walkTrack = animator:LoadAnimation(walk)
-- по кругу
walkTrack.Looped = true
-- скорость изменилась
humanoid.Running:Connect(function(speed)
-- идёт — шагаем, стоит — стоим
if speed > 0.5 and not walkTrack.IsPlaying then walkTrack:Play() elseif speed <= 0.5 then walkTrack:Stop() end
-- конец функции
end)
-- движение считает сервер
pcall(function() root:SetNetworkOwner(nil) end)
-- куда возвращаться
local home = root.Position
-- время прошлого укуса
local lastAttack = 0
-- пока жив
while humanoid.Health > 0 do
-- ближайший игрок
local best, bestRoot, bestDistance = nil, nil, SIGHT
-- все игроки
for _, player in ipairs(Players:GetPlayers()) do
-- персонаж
local character = player.Character
-- его Humanoid
local target = character and character:FindFirstChildOfClass("Humanoid")
-- его центр
local targetRoot = character and character:FindFirstChild("HumanoidRootPart")
-- жив
if target and targetRoot and target.Health > 0 then
-- расстояние
local distance = (targetRoot.Position - root.Position).Magnitude
-- ближе прошлого
if distance < bestDistance then best, bestRoot, bestDistance = target, targetRoot, distance end
-- конец проверки
end
-- конец перебора
end
-- есть цель
if best then
-- бежим к ней
humanoid:MoveTo(bestRoot.Position)
-- рядом и укус готов
if bestDistance <= ATTACK_RANGE and os.clock() - lastAttack >= COOLDOWN then
-- запоминаем
lastAttack = os.clock()
-- сильнее с уровнем моба
best:TakeDamage(3 + level.Value * 2)
-- конец проверки
end
-- никого
else
-- домой
humanoid:MoveTo(home)
-- конец проверки
end
-- 4 раза в секунду
task.wait(0.25)
-- конец цикла
endГде: ServerScriptService · Script
Зачем: Уровни, награда, возрождение.
-- все мобы
local mobs = workspace:WaitForChild("Mobs")
-- через сколько секунд моб вернётся
local RESPAWN = 15
-- следим за одним мобом
local function Setup(mob)
-- копия целого — для возрождения
local sample = mob:Clone()
-- где стоял
local spot = mob:GetPivot()
-- Humanoid
local humanoid = mob:WaitForChild("Humanoid")
-- уровень моба
local level = mob:FindFirstChild("Level") or Instance.new("IntValue")
-- имя — его читают HealthBar и MobAI
level.Name = "Level"
-- случайный уровень
level.Value = math.random(1, 5)
-- в моба
level.Parent = mob
-- здоровье растёт с уровнем
humanoid.MaxHealth = 50 * level.Value
-- полное
humanoid.Health = humanoid.MaxHealth
-- моб побеждён
humanoid.Died:Connect(function()
-- метка от оружия
local tag = humanoid:FindFirstChild("creator")
-- кто победил
local player = tag and tag.Value
-- игрок ещё в игре
if player and player.Parent and player:FindFirstChild("Exp") then
-- опыт
player.Exp.Value += 40 * level.Value
-- монеты
player.leaderstats["Монеты"].Value += 5 * level.Value
-- конец проверки
end
-- ждём
task.wait(RESPAWN)
-- убираем тело
mob:Destroy()
-- новый моб
local new = sample:Clone()
-- на старое место
new:PivotTo(spot)
-- в игру
new.Parent = mobs
-- следим и за ним
Setup(new)
-- конец функции
end)
-- конец функции
end
-- все мобы
for _, mob in ipairs(mobs:GetChildren()) do Setup(mob) endГде: ServerScriptService · Script
Зачем: Цифры урона.
-- образец индикатора
local RS = game:GetService("ReplicatedStorage")
-- удаляет индикаторы
local Debris = game:GetService("Debris")
-- кубик с BillboardGui Num → Damage
local template = RS:WaitForChild("Indicator")
-- следим за здоровьем одного персонажа или моба
local function Watch(humanoid)
-- здоровье до изменения
local last = humanoid.Health
-- изменилось
humanoid.HealthChanged:Connect(function(health)
-- сколько потерял
local damage = math.floor(last - health + 0.5)
-- запоминаем
last = health
-- где он
local root = humanoid.Parent and humanoid.Parent:FindFirstChild("HumanoidRootPart")
-- это лечение или нет центра
if damage <= 0 or not root then return end
-- новый индикатор
local indicator = template:Clone()
-- рядом, чуть в стороне
indicator.CFrame = CFrame.new(root.Position + Vector3.new(math.random(-2, 2), 2 + math.random(0, 2), math.random(-2, 2)))
-- текст урона
indicator.Num.Damage.Text = "-" .. damage
-- показываем
indicator.Parent = workspace
-- 0.7 секунды
Debris:AddItem(indicator, 0.7)
-- конец функции
end)
-- конец функции
end
-- все, кто уже есть
for _, obj in ipairs(workspace:GetDescendants()) do
-- следим
if obj:IsA("Humanoid") then Watch(obj) end
-- конец перебора
end
-- новые: игроки, возродившиеся мобы
workspace.DescendantAdded:Connect(function(obj)
-- следим и за ними
if obj:IsA("Humanoid") then Watch(obj) end
-- конец функции
end)Запусти Play (или Run) и убедись: