-- Подключаем сервис игроков: через него получаем список всех игроков в игре
local Players = game:GetService("Players")
-- Ждём, пока в Workspace появится папка SpawnPoints (там лежат Part с точками спавна)
local spawnFolder = workspace:WaitForChild("SpawnPoints")
-- Число: минимальная дистанция между центром нового спавна и другими игроками (в студиях)
local minDistance = 8
--[[
Локальная функция getSpawns:
- нужна, чтобы один раз собрать все Part из папки в таблицу (массив точек)
- возвращает таблицу parts — по ним потом выбираем случайную позицию
]]
local function getSpawns()
local points = {} -- пустая таблица, сюда будем добавлять части
-- ipairs обходит детей папки по порядку с 1,2,3...
for _, obj in ipairs(spawnFolder:GetChildren()) do
-- BasePart — это Part, SpawnLocation, MeshPart и т.д. (у всех есть Position)
if obj:IsA("BasePart") then
table.insert(points, obj) -- добавляем часть в конец таблицы
end
end
return points -- отдаём список всех точек спавна
end
--[[
Локальная функция isFarFromOthers(pos):
- аргумент pos — Vector3, куда хотим поставить игрока
- возвращает true, если от всех других игроков далеко, иначе false
]]
local function isFarFromOthers(pos)
-- GetPlayers() — метод сервиса Players, даёт таблицу всех игроков сейчас в игре
for _, plr in ipairs(Players:GetPlayers()) do
-- У игрока может ещё не быть персонажа — проверяем Character
if plr.Character and plr.Character:FindFirstChild("HumanoidRootPart") then
local otherPos = plr.Character.HumanoidRootPart.Position -- позиция другого игрока
-- (otherPos - pos) — разница векторов; .Magnitude — длина вектора = расстояние
if (otherPos - pos).Magnitude < minDistance then
return false -- слишком близко — эту точку не берём
end
end
end
return true -- ни один живой игрок не слишком близко
end
--[[
Локальная функция spawnCharacter(character):
- character — модель персонажа, который только что заспавнился
- переносим HumanoidRootPart на выбранную позицию
]]
local function spawnCharacter(character)
-- WaitForChild ждёт появления дочернего объекта (корень персонажа для перемещения)
local root = character:WaitForChild("HumanoidRootPart")
local points = getSpawns() -- получаем все Part-точки
if #points == 0 then return end -- если точек нет — выходим, нечего делать
-- Цикл: пробуем до стольки раз, сколько у нас точек (чтобы не крутиться бесконечно)
for i = 1, #points do
-- math.random(1, #points) — случайное целое от 1 до количества точек
local point = points[math.random(1, #points)]
-- Position — центр Part; + Vector3.new(0, 3, 0) чуть поднимаем, чтобы не застрять в полу
local pos = point.Position + Vector3.new(0, 3, 0)
if isFarFromOthers(pos) then
-- CFrame.new(pos) — новая ориентация и позиция; ставим персонажа сюда
root.CFrame = CFrame.new(pos)
return -- нашли место — выходим из функции
end
end
-- Если все точки "заняты" по правилу дистанции — всё равно ставим в случайную
local fallback = points[math.random(1, #points)]
root.CFrame = CFrame.new(fallback.Position + Vector3.new(0, 3, 0))
end
--[[
Событие PlayerAdded:
- срабатывает, когда новый игрок заходит в игру
- внутри подписываемся на CharacterAdded этого игрока (каждый новый персонаж / респавн)
]]
Players.PlayerAdded:Connect(function(player)
player.CharacterAdded:Connect(function(character)
task.wait(0.1) -- маленькая пауза: даём движку "успокоить" персонажа после спавна
spawnCharacter(character) -- вызываем нашу функцию переноса
end)
end)