Roblox — Спавнер, простейший

Автор: | 10 сентября, 2026
Поделиться...

Собственно как у нас игра может быть без НПС, в особенности если это экшен или RPG?

Ставим задачу: разместить на карте блок в котором будут создаваться новые НПС с некоторой периодичностью. Само собой, в последствии мы усложним себе задачку.

Для начала берём стандартного Drooling Zombie из тулбокса и кидаем на плейс:

Взяли его по тому, что у него уже есть крипты с анимацией и поведением. Так будет веселее.

Теперь добавляем парт для обозначения спавна. Ставим на него нашего зомби и пихаем его под парт. Также запихиваем в него Script.

Подготовка завершена. Пишем скрипт что будет брать нашего зомби как источник и периодически запускать нового в этом же месте.

local timer = 5 -- Задаём таймер возрождения нового зомби

local zombie = script.Parent["Drooling Zombie"]:Clone()	-- создаём себе модель в памяти
script.Parent["Drooling Zombie"]:Destroy()	-- удаляем старую модель

local oldSpawnTime = workspace:GetServerTimeNow() -- Запоминаем время старого спавна
while task.wait() do
	if workspace:GetServerTimeNow() - oldSpawnTime >= timer then	-- Проверяем прошёл ли таймер
		local newZombie = zombie:Clone() -- Клонируем модель		
		newZombie.Parent = workspace -- Перемещаем модель в workspace
		oldSpawnTime = workspace:GetServerTimeNow() -- Обновляем время старого спавна
	end
end

Ну вот, зомбаки спавнятся и радостно бегут к нам. Заодно и убивают. Можем дать нашему игроку в руки мечь, чтобы давал сдачи и.. вот уже игра — правда без цели.

Первичная задача выполнена. Мы так же можем поставить кучу копий нашего спавнера и каждый из них будет генерировать свою армию. Естественно, что если заменить модельку зомби на иную, то и армия будет разношёрстной (но и код надо менять). И вот они уже задорно машутся, почти не обращая на меня внимания.

Что дальше? Надо упростить работу дизайнеру, чтобы ему не нужно было лезть в код. Никогда!

  • Надо сделать так, чтобы не нужно было менять код, при смене модели для спавна.
  • А ещё, нужно изменить разбег в таймере, да ещё и так чтобы спавн был похож на случайный
  • Добавить ограничение по количеству единовременно заспавленных мобов
  • Добавить радиус реагирования, чтобы мобу не спавнились, если рядом нет игрока (не зачем захламлять карту)

Т.е. нам надо добавить в спавнер параметры, определить место для модели и где будут храниться живые мобы.

Для начала, по взрослому, мы должны наш спавнер превратить в модель. И всё дальнейшее уже производить с ней.

Для начала, в модели должны быть две папочки: Object — в ней будет у нас модель для спавна и Spawned — будет содержать заспавненные модели.

Теперь надо добавить параметры: timeMin, timeMax — интервал времени спавна, spawnNum — ограничитель числа живых на карте, spawnMax — ограничитель общего числа заспавненных, radius — радиус поиска игроков для спавна.

Немножко микро-оптимизации. Стоит сразу определиться какие числа у нас будут целыми, а какие дробными. Не стоит все делать дробными (с заделом на будущее) или целыми, чтобы в последствии не пришлось маться.

Ещё немного об облегчении жизни программиста в будущем. Стоит использовать печатать сообщения, если дизайнер забыл что-то сделать — положить модель, указать значения и.. останавливать работу скрипта, чтобы не плодились ошибки. Либо менять значения на значения по умолчанию.

Ну и собственно сам скрипт:

--[[ Универсальный спавнер НПС

Модель спавнера размещается в любом месте плейса. 
В папку Object необходимо положить модель NPC которого нужно спавнить. 
Модель НПС должна быть размещена на спавнере.

В переменных спавнера задаются значения:

	Radius - радиус спавна NPC от центра спавнера
	TimeMin - минимальное время спавна NPC
	TimeMax - максимальное время спавна NPC
	SpawnMax - максимальное количество NPC одновременно
	SpawnNum - количество данных NPC на карте единовременно
	
Создано: GAVsi 10/09/2026
Изменено:
]]

local me = script.Parent	-- ссылка на сам спавнер

local model = me.Object:FindFirstChildWhichIsA("Model")	-- нам нужна модель

if model then	-- проверка того, что модель есть
	local npc = model:Clone()	-- создаём себе модель в памяти
	model:Destroy()				-- удаляем старую модель
	
	local radius = me.Radius.Value		-- радиус реагирования на игрока для спавна
	local timeMin = me.TimeMin.Value	-- минимальное время
	local timeMax = me.TimeMax.Value	-- максимальное время
	local spawnNum = me.SpawnNum.Value	-- ограничитель числа НПС на карте
	local spawnMax = me.SpawnMax.Value	-- ограничитель общего числа заспавненных НПС

	-- проверка на корректность значений
	if radius == 0 then
		print("Radius не может быть 0")
		radius = 100
	end
	if timeMax == 0 then
		print("TimeMax не может быть 0")
		timeMax = 6
	end
	if timeMin == 0 then
		print("TimeMin не может быть 0")
		timeMin = 3
	end
	if timeMin > timeMax then
		print("TimeMin не может быть больше TimeMax")
		timeMin = timeMax
	end
	if spawnNum == 0 then
		print("SpawnNum не может быть 0")
		spawnNum = 5
	end
	if spawnMax == 0 then
		print("SpawnMax не может быть 0")
		spawnMax = 10
	end
	
	local newSpawnTime = workspace:GetServerTimeNow()	-- Запоминаем время старого спавна
	
	local allSpawned = 0 -- Сколько НПС уже было заспавнено
	while allSpawned < spawnMax do
		task.wait()	-- технологическое прерывание цикла
		
		-- определяем есть ли хоть один игрок на дистанции для спавна
		local distance = 0 -- Расстояние между игроком и NPC
		for i, player in pairs(game.Players:GetPlayers()) do	-- Проверяем расстояние между игроком и NPC
			local character = player.Character -- Получаем модель игрока
			if character then
				local head = character:FindFirstChild("Head") -- Ищем голову у игрока
				if head then
					local humanoid = character:FindFirstChild("Humanoid")
					if humanoid then
						if humanoid.Health > 0 then	-- игрок есть и он живой
							local dst = (me.Spawner.Position - head.Position).Magnitude
							if dst <= radius then
								distance = dst	-- расстояние как флаг
								break	-- дальше не зачем проходить цикл
							end
						end
					end
				end
			end
		end
		if distance > 0 then	-- игрок найден
			if workspace:GetServerTimeNow() > newSpawnTime then	-- время вышло, можно спавнить
				local current = me.Spawn:GetChildren()	-- сколько сейчас заспавнено
				if #current < spawnNum then	-- можно спавнить?
					allSpawned = allSpawned + 1	-- увеличиваем счетчик спавненных NPC
					
					newSpawnTime = workspace:GetServerTimeNow() + math.random(timeMin, timeMax)	-- время следующего спавна
					local newNPC = npc:Clone()	-- Клонируем модель		
					newNPC.Parent = me.Spawn	-- Перемещаем модель в workspace
				end
			end
		end
	end
else
	warn("Нет модели в Object", script.Parent)	-- критическое замечание, блокирующее работу скрипта
end

Как можно заметить, большая часть скрипта, это комментарии на будущее вмешательство и.. проверка ошибок человеческого фактора.

Ну как то так. Правда случился косяк — одна модель не полностью удалилась и считалась как присутствующая… Но это уже косяк скрипта в зомбике, а не в нашем. Хотя… Мы конечно можем добавить у себя проверку на то, что НПС живой, ведь не всегда модели поверженных НПС убираются из мира.

Само собой, можем размножить модель спавнера с заменой модели НПС и поменяв остальные настройки. Но! В качестве домашнего задания — а что будет когда таких спавнеров десятки и в его скрипте надо что-то изменить? Ответ «простой» — надо скрипт выносить отдельно, чтобы он следил сразу за всеми спавнерами. Но это уже к простейшему спавнеру не относится.


Поделиться...

Добавить комментарий