Скрипт: NPC, который ходит по точкам и говорит
Заготовка простого NPC: он идёт от точки к точке по кругу, а когда игрок подходит близко — над ним появляется реплика. Всё считает сервер.
Куда положить
Внутрь модели NPC, тип объекта Script
Что должно быть в проекте
- Модель NPC с Humanoid и HumanoidRootPart — подойдёт обычный Rig из вкладки Avatar
- Модель Waypoints в Workspace с деталями-точками маршрута
Код
local Players = game:GetService("Players")local npc = script.Parentlocal humanoid = npc:WaitForChild("Humanoid")local root = npc:WaitForChild("HumanoidRootPart")local waypoints = workspace:WaitForChild("Waypoints"):GetChildren()table.sort(waypoints, function(a, b)return a.Name < b.Nameend)local function say(text: string)local existing = root:FindFirstChild("Line")if existing thenexisting:Destroy()endlocal gui = Instance.new("BillboardGui")gui.Name = "Line"gui.Size = UDim2.fromScale(6, 1.4)gui.StudsOffset = Vector3.new(0, 3.5, 0)gui.Parent = rootlocal label = Instance.new("TextLabel")label.Size = UDim2.fromScale(1, 1)label.BackgroundTransparency = 0.2label.TextScaled = truelabel.Text = textlabel.Parent = guitask.delay(4, function()gui:Destroy()end)endtask.spawn(function()while npc.Parent dofor _, point in ipairs(waypoints) dohumanoid:MoveTo(point.Position)humanoid.MoveToFinished:Wait()task.wait(1)endendend)task.spawn(function()while npc.Parent dotask.wait(1)for _, player in ipairs(Players:GetPlayers()) dolocal character = player.Characterlocal playerRoot = character and character:FindFirstChild("HumanoidRootPart")if playerRoot and (playerRoot.Position - root.Position).Magnitude < 12 thensay("Привет, " .. player.Name .. "!")breakendendendend)
Проверка расстояния идёт раз в секунду, а не каждый кадр: NPC не стоит того, чтобы жечь на нём производительность.
На что обратить внимание
- Точки маршрута называй Point1, Point2 — сортировка по имени задаёт порядок обхода
- MoveToFinished ждёт прихода или таймаута, поэтому цикл не зависнет на застрявшем NPC
- Для сложных маршрутов с препятствиями смотри PathfindingService