скрипт на генерацию пустыни в роблокс студио
Creado el: 17 de febrero de 2025
Creado el: 17 de febrero de 2025
скрипт на генерацию пустыни в роблокс студио
Ниже приведён пример простого скрипта на языке Lua (используется в Roblox Studio), который генерирует процедурную «пустыню» с высотами, напоминающими дюны. Скрипт создаёт новый участок ландшафта (Terrain) из песка и формирует его высоту с помощью шума Perlin. Обратите внимание, что этот пример довольно базовый: он лишь показывает общий принцип, но вы можете доработать его под свои нужды (добавить растения, объекты, улучшить детали и т. д.).
lua--[[ Скрипт можно запустить через Командную строку (Command Bar) в Roblox Studio или поместить его в обычный Script/LocalScript (для плагина/инструмента разработки). ВНИМАНИЕ: 1. Генерация может занять некоторое время и потребовать немало памяти при больших размерах. 2. Перед началом работы желательно очистить или сохранить текущую Terrain, чтобы избежать наложения старого ландшафта на новый. --]] local terrain = workspace:FindFirstChildWhichIsA("Terrain") if not terrain then error("Terrain не найден. Убедитесь, что у вас есть объект Terrain в workspace.") end -- Параметры генерации local desertSizeX = 256 -- Размер пустыни по оси X (в вокселях) local desertSizeZ = 256 -- Размер пустыни по оси Z (в вокселях) local maxHeight = 30 -- Максимальная высота «дюн» local baseHeight = 20 -- Базовая (минимальная) высота песка local scale = 50 -- Коэффициент «растяжения» шума (чем больше, тем плавнее переходы) local step = 4 -- Шаг вокселей (размер блока при заливке). 4 - стандартный размер вокселя Roblox -- Очищаем старый ландшафт (если хотите сохранить старый - отключите эту строку) terrain:Clear() -- Функция генерации песчаного «блока» local function fillSandBlock(centerCFrame, size) terrain:FillBlock(centerCFrame, size, Enum.Material.Sand) end -- Генерация пустыни for x = 0, desertSizeX, step do for z = 0, desertSizeZ, step do -- Используем функцию шума для создания «дюн» local noiseValue = math.noise(x / scale, z / scale) -- Преобразуем значения шума (-1..1) к высоте (0..1), умножаем на maxHeight local duneHeight = (noiseValue + 1) / 2 * maxHeight -- Итоговая высота с учётом базового уровня local finalHeight = baseHeight + duneHeight -- Координаты центра блока local centerX = x + step/2 local centerY = finalHeight / 2 -- Чтобы блок «вырос» из нуля local centerZ = z + step/2 -- Создаём CFrame для блока local blockCFrame = CFrame.new(centerX, centerY, centerZ) -- Создаём воксельный блок размера (step x finalHeight x step) fillSandBlock(blockCFrame, Vector3.new(step, finalHeight, step)) end end print("Генерация пустыни завершена!")
math.noise
Roblox предоставляет встроенную функцию math.noise()
, которая возвращает значение «перлин-шум» (Perlin Noise) в диапазоне от -1 до 1. Мы используем её для создания плавных переходов высот, похожих на волны или дюны.
Перевод значения шума в высоту
(-1..1)
к (0..1)
, используя формулу:
lua(noiseValue + 1) / 2
maxHeight
, чтобы получить нужную нам максимальную высоту.Заполнение участка песком (FillBlock)
terrain:FillBlock(CFrame, Vector3, Material)
позволяет «заливать» регион указанного размера и формы в Terrain.finalHeight
и шириной/глубиной step
, чтобы постепенно выстраивать пустыню.Параметры
desertSizeX
и desertSizeZ
задают размеры пустыни. Если хотите больше – увеличивайте, но будьте осторожны с производительностью.baseHeight
– «базовый уровень», откуда начинается песок.maxHeight
– максимальная высота «дюн».scale
– определяет частоту шума: чем больше scale
, тем более «растянутым» будет шум (гладкие, большие дюны), чем меньше – тем более детализированный, но и более «рваный» рельеф.step
– шаг генерации. Обычно 4 соответствует одному «воxel» в террейне Roblox. Если уменьшать шаг, получите более детализированный ландшафт, но возрастёт время и ресурсы на генерацию.Чтобы пустыня выглядела более «живой», можно добавить случайно генерируемые объекты – например, кактусы или камни. Для этого:
ReplicatedStorage
или ServerStorage
.math.random() < 0.02
– 2% на клетку) «ставит» копию кактуса на сгенерированную точку.Пример кода для расстановки кактусов (в том же скрипте, после генерации):
lua-- Предположим, что в ServerStorage лежит модель кактуса под названием "Cactus" local ServerStorage = game:GetService("ServerStorage") local cactusModel = ServerStorage:FindFirstChild("Cactus") if cactusModel then for x = 0, desertSizeX, step do for z = 0, desertSizeZ, step do -- С небольшой вероятностью ставим кактус if math.random() < 0.02 then -- Ищем высоту террейна в этой точке local regionHeight = terrain:ReadVoxels( Region3.new( Vector3.new(x, 0, z), Vector3.new(x + step, 1000, z + step) ), 4 ) -- Этот метод вернёт массив вокселей, по которому можно приблизительно узнать, где заканчивается песок -- Однако, проще нередко просто использовать finalHeight из основной логики, -- если она не меняется после генерации. -- Упростим и скажем, что высота примерно равна baseHeight + "что-то" -- Допустим, что finalHeight из генерации известен: local approxHeight = baseHeight + ((math.noise(x / scale, z / scale) + 1) / 2 * maxHeight) -- Клонируем модель кактуса local newCactus = cactusModel:Clone() newCactus.Parent = workspace -- Ставим кактус в нужную точку newCactus:SetPrimaryPartCFrame(CFrame.new(x, approxHeight, z)) end end end else warn("Не найдена модель кактуса в ServerStorage!") end
Такой способ расстановки объектов крайне упрощён: мы берём высоту из того же шума, который использовался для террейна. При желании можно точно считать высоту террейна с помощью ReadVoxels
, но это чуть сложнее.
Надеюсь, данный пример поможет вам начать эксперименты с процедурной генерацией пустынного ландшафта в Roblox Studio! Если возникнут вопросы или захотите расширить функциональность, обязательно поэкспериментируйте с параметрами шума, высоты, вероятностей расстановки объектов и т. д. Удачи в разработке!
На генерацию мобов в роблокс студио
Ниже приведён пример базового скрипта на языке Lua (Roblox) для генерации (спауна) мобов в игре. Скрипт можно разместить в ServerScriptService или в любом другом месте на стороне сервера (чтобы все игроки видели одних и тех же мобов).
Суть скрипта:
Пусть модель моба в ServerStorage называется "Zombie"
.
Ниже – пример ServerScript, который:
spawnInterval
секунд проверяет, сколько мобов уже существует в Workspace.maxMobCount
, спаунит нового в случайной позиции в заданных границах.workspace
, делая его видимым для всех.Создайте обычный Script (ServerScript) в ServerScriptService и вставьте в него следующий код:
lua-- Ссылки на сервисы local ServerStorage = game:GetService("ServerStorage") local CollectionService = game:GetService("CollectionService") -- Настройки спауна local MOB_NAME = "Zombie" -- Название модели моба в ServerStorage local TAG_NAME = "Mob" -- Тег, которым помечаем сгенерированных мобов, чтобы легко их искать local maxMobCount = 10 -- Максимальное число мобов, которые мы хотим одновременно в игре local spawnInterval = 5 -- Период (в секундах) между проверками спауна local spawnRegionMin = Vector3.new(-50, 0, -50) -- Минимальная точка спауна (XYZ) local spawnRegionMax = Vector3.new( 50, 0, 50) -- Максимальная точка спауна (XYZ) -- Функция, возвращающая случайный вектор в заданных пределах local function getRandomSpawnPosition() local x = math.random(spawnRegionMin.X, spawnRegionMax.X) local y = math.random(spawnRegionMin.Y, spawnRegionMax.Y) local z = math.random(spawnRegionMin.Z, spawnRegionMax.Z) return Vector3.new(x, y, z) end -- Функция спауна одного моба local function spawnMob() local mobTemplate = ServerStorage:FindFirstChild(MOB_NAME) if not mobTemplate then warn("Не найдена модель моба: " .. MOB_NAME) return end -- Клонируем модель local newMob = mobTemplate:Clone() -- На всякий случай проверим, что у модели есть PrimaryPart if not newMob.PrimaryPart then -- Если PrimaryPart не задан, можно попытаться автоматически назначить его -- Или завершить функцию с ошибкой warn("У модели '" .. MOB_NAME .. "' не назначен PrimaryPart!") return end -- Помечаем модель тегом (удобно для поиска через CollectionService) CollectionService:AddTag(newMob, TAG_NAME) -- Задаём позицию PrimaryPart local spawnPos = getRandomSpawnPosition() newMob:SetPrimaryPartCFrame(CFrame.new(spawnPos)) -- Переносим модель в Workspace, чтобы она стала видимой newMob.Parent = workspace end -- Основной цикл спауна while true do -- Ищем всех мобов с тегом "Mob" local mobs = CollectionService:GetTagged(TAG_NAME) local countMobs = #mobs if countMobs < maxMobCount then -- Спауним столько, сколько "не хватает" до maxMobCount (можно и по одному) local needToSpawn = maxMobCount - countMobs -- Чтобы не спаунить сразу много за раз, зачастую создают 1 или 2 моба за цикл -- Но для примера спауним сразу все "недостающие" for i = 1, needToSpawn do spawnMob() end end wait(spawnInterval) -- Ждём несколько секунд и повторяем end
CollectionService и теги
"Mob"
уже в игре.maxMobCount
, мы создаём ещё.Случайная позиция
spawnRegionMin
и spawnRegionMax
задают диапазон координат, внутри которого будут появляться мобы.Raycast
(луч, идущий сверху вниз), чтобы точно определить высоту ландшафта. Или использовать заранее расставленные SpawnPart
-объекты.Настройка PrimaryPart
SetPrimaryPartCFrame
у модели обязательно должен быть назначен PrimaryPart
.Ограничение по числу мобов
maxMobCount
– сколько максимально мобов может находиться в Workspace.Отслеживание смерти или удаления мобов
Humanoid.Health
= 0) и удаляются из Workspace, их больше нет с тегом "Mob"
, значит, в следующем цикле появятся новые.Чтобы ваш моб не просто стоял, а, например, атаковал игрока, ему нужен скрипт внутри модели. Самая простая заготовка:
lua-- Вставьте этот скрипт в модель моба (например, внутрь "Zombie") в обычный Script. -- Предположим, что у нас R6 модель со стандартным Humanoid и HumanoidRootPart local mob = script.Parent local humanoid = mob:FindFirstChildOfClass("Humanoid") local rootPart = mob:FindFirstChild("HumanoidRootPart") if not humanoid or not rootPart then return end local wanderRadius = 20 -- Радиус, в пределах которого моб случайно двигается local followDistance = 30 -- Дистанция, на которой моб начинает преследовать игрока local attackDistance = 5 -- Дистанция, на которой моб "бьёт" игрока local attackDamage = 10 -- Поиск ближайшего игрока (простейший способ) local function getNearestPlayer() local nearest = nil local nearestDist = math.huge for _, player in pairs(game.Players:GetPlayers()) do local char = player.Character local hrp = char and char:FindFirstChild("HumanoidRootPart") local h = char and char:FindFirstChildOfClass("Humanoid") if hrp and h and h.Health > 0 then local dist = (hrp.Position - rootPart.Position).Magnitude if dist < nearestDist then nearestDist = dist nearest = char end end end return nearest, nearestDist end -- Простейший цикл поведения while humanoid.Health > 0 do local target, distance = getNearestPlayer() if target and distance <= followDistance then -- Идём к игроку humanoid:MoveTo(target.HumanoidRootPart.Position) if distance <= attackDistance then -- Наносим урон (простейший способ) local targetHumanoid = target:FindFirstChildOfClass("Humanoid") if targetHumanoid then targetHumanoid:TakeDamage(attackDamage) end end else -- Гуляем "бесцельно" в радиусе вокруг текущей позиции local randomPos = rootPart.Position + Vector3.new( math.random(-wanderRadius, wanderRadius), 0, math.random(-wanderRadius, wanderRadius) ) humanoid:MoveTo(randomPos) end wait(2) -- Небольшая пауза между циклами end
Это очень упрощённый пример. В реальном проекте можно/нужно:
PathfindingService
), чтобы мобы умели обходить препятствия.С таким базовым подходом вы получите простейших «вражеских» существ, которые появляются и исчезают по мере их смерти и снова спаунятся при необходимости. Далее можно улучшать механику и ИИ по своему вкусу.
Удачи в разработке!
На генерацию мобов в роблокс студио моба зовут Snake
Ниже приведён пример базового серверного скрипта, который будет периодически спаунить в игре моба по имени Snake (змею). Предположим, что модель Snake
лежит в ServerStorage. Скрипт нужно разместить в ServerScriptService в обычном Script
(серверном).
Snake
(змею).PrimaryPart
(обычно это может быть «HumanoidRootPart» для персонажа или любая другая деталь).Snake
в ServerStorage (чтобы она не отображалась в Workspace по умолчанию).lua-- Скрипт для периодического спауна змей (Snake) на сервере. -- Подключаем необходимые сервисы local ServerStorage = game:GetService("ServerStorage") local CollectionService = game:GetService("CollectionService") -- Настройки local SNAKE_NAME = "Snake" -- Имя модели змеи в ServerStorage local TAG_NAME = "SnakeMob" -- Тег, которым помечаем сгенерированных змеек (для удобного поиска) local maxSnakeCount = 10 -- Максимальное количество змеек local spawnInterval = 5 -- Период (в секундах) между проверками, нужно ли спаунить новую змею -- Диапазон координат, в которых появятся змейки local spawnRegionMin = Vector3.new(-50, 0, -50) local spawnRegionMax = Vector3.new( 50, 0, 50) -- Функция возвращает случайный вектор в заданных пределах local function getRandomSpawnPosition() local x = math.random(spawnRegionMin.X, spawnRegionMax.X) local y = math.random(spawnRegionMin.Y, spawnRegionMax.Y) local z = math.random(spawnRegionMin.Z, spawnRegionMax.Z) return Vector3.new(x, y, z) end -- Функция, которая создаёт одну «змею» local function spawnSnake() -- Ищем шаблон змеи в ServerStorage local snakeTemplate = ServerStorage:FindFirstChild(SNAKE_NAME) if not snakeTemplate then warn("Модель '" .. SNAKE_NAME .. "' не найдена в ServerStorage!") return end -- Клонируем шаблон local newSnake = snakeTemplate:Clone() -- Проверяем, назначен ли PrimaryPart (иначе SetPrimaryPartCFrame не сработает) if not newSnake.PrimaryPart then warn("У модели '" .. SNAKE_NAME .. "' не назначен PrimaryPart!") return end -- Добавляем тег (чтобы потом считать всех змей через CollectionService) CollectionService:AddTag(newSnake, TAG_NAME) -- Ставим змею в случайную позицию local spawnPos = getRandomSpawnPosition() newSnake:SetPrimaryPartCFrame(CFrame.new(spawnPos)) -- Переносим в Workspace, чтобы змея появилась в игре newSnake.Parent = workspace end -- Основной цикл: каждые spawnInterval секунд проверяем, нужно ли добавить змей while true do -- Ищем в игре все объекты, у которых есть тег SnakeMob local snakes = CollectionService:GetTagged(TAG_NAME) local currentSnakeCount = #snakes if currentSnakeCount < maxSnakeCount then -- Сколько «не хватает» до максимума local needToSpawn = maxSnakeCount - currentSnakeCount -- Можно спаунить всех сразу или по 1-2 за раз; здесь — все «нехватающие» for i = 1, needToSpawn do spawnSnake() end end wait(spawnInterval) end
Поиск модели в ServerStorage
Скрипт ищет модель Snake
, копирует её и вставляет в workspace
.
Ограничение на количество
Мы используем CollectionService
и тег SnakeMob
, чтобы легко посчитать, сколько змеек уже в игре (currentSnakeCount
), и не создавать новых сверх maxSnakeCount
.
Случайная позиция
getRandomSpawnPosition()
генерирует координаты от spawnRegionMin
до spawnRegionMax
. Если нужно, чтобы змея появлялась на определённой высоте, измените координаты y
или реализуйте Raycast
, чтобы змея появлялась на поверхности ландшафта.
Чтобы змея двигалась или реагировала на игрока, внутри самой модели Snake
можно добавить скрипт (обычный Script
). Например:
lua-- Скрипт внутри змеи (внутри модели Snake) -- Предположим, что у змеи есть Humanoid и HumanoidRootPart (R6 или R15) local snake = script.Parent local humanoid = snake:FindFirstChild("Humanoid") local rootPart = snake:FindFirstChild("HumanoidRootPart") local wanderRadius = 10 -- Радиус «гуляния» local followDistance = 15 -- Дистанция, на которой змея начинает «преследовать» игрока local attackDistance = 2 -- Дистанция, на которой змея наносит урон local attackDamage = 5 -- Функция поиска ближайшего игрока local function getNearestPlayer() local nearest = nil local nearestDist = math.huge for _, player in pairs(game.Players:GetPlayers()) do local char = player.Character local hrp = char and char:FindFirstChild("HumanoidRootPart") local h = char and char:FindFirstChildOfClass("Humanoid") if hrp and h and h.Health > 0 then local dist = (hrp.Position - rootPart.Position).Magnitude if dist < nearestDist then nearestDist = dist nearest = char end end end return nearest, nearestDist end while true do if humanoid and humanoid.Health > 0 then local target, distance = getNearestPlayer() if target and distance <= followDistance then -- Идём к игроку humanoid:MoveTo(target.HumanoidRootPart.Position) -- Если подошли близко, «кусаем» if distance <= attackDistance then local targetHumanoid = target:FindFirstChildOfClass("Humanoid") if targetHumanoid then targetHumanoid:TakeDamage(attackDamage) end end else -- Если игроков рядом нет, змея «ползает» в пределах wanderRadius local randomPos = rootPart.Position + Vector3.new( math.random(-wanderRadius, wanderRadius), 0, math.random(-wanderRadius, wanderRadius) ) humanoid:MoveTo(randomPos) end end wait(2) -- Интервал между «решениями» змеи end
Это очень упрощённый пример ИИ. В реальном проекте обычно используют PathfindingService
, анимации, разные состояния (Idle, Wander, Chase, Attack) и т.д. Но для старта такой скрипт уже позволит змее «искать» игрока, приближаться и наносить урон.
Snake
в ServerStorage, убедитесь, что у неё есть PrimaryPart
.Таким образом вы получите базовую систему «генерации мобов» (змей) в Roblox Studio. Дальше её можно развивать: добавлять анимации, более умный путь (Pathfinding) и т.п. Удачи в разработке!