Roblox · Песочница · урок 9
Зомби патрулирует лес по точкам, обходит стены и прыгает через препятствия. Заметил игрока — бежит быстрее и бьёт. Скорость и урон настраиваются атрибутами.
Синим — что добавляем на этом уроке.
Workspace ├─ Zombie (Model) — атрибуты Damage, WalkSpeed, SprintSpeed │ └─ EnemyScript (Script) └─ Waypoints (Folder) └─ Point (Part) — невидимые, Anchored, CanCollide выкл.
Где: Workspace → Zombie · Script
Зачем: Патруль, погоня, удары.
-- поиск пути в обход стен
local PathfindingService = game:GetService("PathfindingService")
-- игроки
local Players = game:GetService("Players")
-- противник
local enemy = script.Parent
-- Humanoid
local humanoid = enemy:WaitForChild("Humanoid")
-- центр
local root = enemy:WaitForChild("HumanoidRootPart")
-- точки патруля
local waypoints = workspace:WaitForChild("Waypoints")
-- замечает игрока ближе 40 studs
local SIGHT = 40
-- бьёт ближе 4 studs
local ATTACK_RANGE = 4
-- секунд между ударами
local COOLDOWN = 1
-- время прошлого удара
local lastAttack = 0
-- Animator
local animator = humanoid:FindFirstChildOfClass("Animator") or Instance.new("Animator", humanoid)
-- ходьба
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 path = PathfindingService:CreatePath({
-- ширина противника
AgentRadius = 2,
-- рост
AgentHeight = 6,
-- умеет прыгать
AgentCanJump = true,
-- не лазает
AgentCanClimb = false,
-- вода «дорогая» — обходит, если можно
Costs = {Water = 100},
-- конец настроек
})
-- ближайший живой игрок в поле зрения
local function FindTarget()
-- пока никого
local best, bestHumanoid, 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, bestHumanoid, bestDistance = targetRoot, target, distance end
-- конец проверки
end
-- конец перебора
end
-- центр, Humanoid и расстояние
return best, bestHumanoid, bestDistance
-- конец функции
end
-- идти по найденному пути
local function MoveAlong(destination, chasing)
-- строим путь
local ok = pcall(function() path:ComputeAsync(root.Position, destination) end)
-- путь не нашёлся
if not ok or path.Status ~= Enum.PathStatus.Success then
-- идём напрямик
humanoid:MoveTo(destination)
-- немного
task.wait(0.5)
-- потом снова подумаем
return
-- конец проверки
end
-- точки пути
for i, waypoint in ipairs(path:GetWaypoints()) do
-- тут надо прыгнуть
if waypoint.Action == Enum.PathWaypointAction.Jump then humanoid.Jump = true end
-- к точке
humanoid:MoveTo(waypoint.Position)
-- дошли
humanoid.MoveToFinished:Wait()
-- в погоне путь пересчитываем каждые 3 точки — игрок двигается
if chasing and i >= 3 then return end
-- в патруле заметил игрока — бросаем патруль
if not chasing and FindTarget() then return end
-- конец перебора
end
-- конец функции
end
-- пока жив
while humanoid.Health > 0 do
-- есть кто рядом?
local targetRoot, target, distance = FindTarget()
-- есть
if targetRoot then
-- погоня — быстрее (атрибут SprintSpeed)
humanoid.WalkSpeed = enemy:GetAttribute("SprintSpeed") or 18
-- рядом
if distance <= ATTACK_RANGE then
-- удар готов
if os.clock() - lastAttack >= COOLDOWN then
-- запоминаем
lastAttack = os.clock()
-- урон из атрибута Damage
target:TakeDamage(enemy:GetAttribute("Damage") or 10)
-- конец проверки
end
-- немного
task.wait(0.2)
-- далеко
else
-- бежим в обход препятствий
MoveAlong(targetRoot.Position, true)
-- конец проверки
end
-- никого
else
-- патруль — медленно
humanoid.WalkSpeed = enemy:GetAttribute("WalkSpeed") or 8
-- точки патруля
local points = waypoints:GetChildren()
-- есть
if #points > 0 then
-- случайная точка
local point = points[math.random(1, #points)]
-- идём к ней
MoveAlong(point:IsA("Model") and point:GetPivot().Position or point.Position, false)
-- точек нет
else
-- стоим
task.wait(1)
-- конец проверки
end
-- конец проверки
end
-- конец цикла
endЗапусти Play (или Run) и убедись: