Roblox · Doors · урок 3
В комнатах появляется мебель: тумбочки и столы с выдвижными ящиками, шкафы-гардеробы с дверцей. Ящики открываются по E. Где стоит мебель — решают невидимые локаторы в комнатах.
Синим — что добавляем на этом уроке.
ServerStorage ├─ FurnitureSamples (Folder) │ ├─ Bedside (Model) — тумбочка; PrimaryPart = Primary │ │ ├─ Primary (Part) — покрывает всю тумбочку: прозрачная, CanCollide и CanQuery выкл. │ │ ├─ Frame… (Part) — каркас, Anchored │ │ ├─ Bottoms (Folder) │ │ │ └─ Bottom (Part) — дно ящика: Anchored; передняя грань — к ручке │ │ │ ├─ Location (Attachment) — центр ящика │ │ │ └─ Handle (Attachment) — на ручке │ │ └─ Drawer… (Part) — стенки и ручка ящика: приварены к Bottom, Anchored выкл. │ ├─ Table (Model) — стол — как тумбочка │ └─ Wardrobe (Model) — гардероб с дверцей │ ├─ Spinner (Part) — петля дверцы, Anchored │ └─ Bottoms → Bottom (Part) — дно с Location и Handle (Handle — на ручке дверцы) └─ RoomSamples (Folder) └─ SmallRoom (Model) └─ Furniture (Folder) — локаторы └─ Bedside, Table, Wardrobe (Part) — имя = имя мебели; передняя грань — в комнату ServerScriptService └─ MainScript → Room (ModuleScript) └─ Furniture (ModuleScript)
Где: ServerScriptService → MainScript → Room · ModuleScript
Зачем: Ставит мебель на места локаторов и открывает ящики и дверцы.
-- плавное движение ящиков
local TS = game:GetService("TweenService")
-- здесь лежат образцы мебели
local SS = game:GetService("ServerStorage")
-- на сколько studs выдвигается ящик
local SLIDE = 1.5
-- таблица модуля
local furniture = {}
-- открыть или закрыть ящик / дверцу
function furniture.Open(bottom)
-- двигается — второе нажатие не примем
bottom:SetAttribute("Moving", true)
-- сейчас открыт?
local opened = bottom:GetAttribute("Open")
-- открыт — задвигаем (1), закрыт — выдвигаем (−1)
local direction = opened and 1 or -1
-- Bottom → папка Bottoms → модель мебели
local model = bottom.Parent.Parent
-- анимация
local tween
-- у мебели есть петля — это дверца (шкаф-гардероб)
if model:FindFirstChild("Spinner") then
-- поворот петли на 90°
local cframe = model.Spinner.CFrame * CFrame.Angles(0, math.rad(90 * direction), 0)
-- поворачиваем петлю
tween = TS:Create(model.Spinner, TweenInfo.new(0.5), {CFrame = cframe})
-- ящик
else
-- сдвиг вперёд или назад
local cframe = bottom.CFrame * CFrame.new(0, 0, SLIDE * direction)
-- двигаем дно — стенки приварены
tween = TS:Create(bottom, TweenInfo.new(0.5), {CFrame = cframe})
-- конец проверки
end
-- запускаем
tween:Play()
-- ждём конца
tween.Completed:Wait()
-- запоминаем новое положение
bottom:SetAttribute("Open", not opened)
-- можно нажимать снова
bottom:SetAttribute("Moving", false)
-- конец функции
end
-- ставит мебель на место локатора
function furniture.New(sample)
-- образец с тем же именем
local template = SS.FurnitureSamples:FindFirstChild(sample.Name)
-- образца нет
if not template then
-- подсказка в Output
warn("Нет мебели " .. sample.Name .. " в ServerStorage.FurnitureSamples")
-- ничего не ставим
return nil
-- конец проверки
end
-- копия мебели
local model = template:Clone()
-- на место и с поворотом локатора
model:PivotTo(sample.CFrame)
-- папка с донышками ящиков
local bottoms = model:FindFirstChild("Bottoms")
-- ящики есть
if bottoms then
-- каждый ящик
for _, bottom in ipairs(bottoms:GetChildren()) do
-- закрыт
bottom:SetAttribute("Open", false)
-- не двигается
bottom:SetAttribute("Moving", false)
-- надпись «Открыть» (E / тап / X)
local prompt = Instance.new("ProximityPrompt")
-- текст
prompt.ActionText = "Открыть"
-- с 5 studs
prompt.MaxActivationDistance = 5
-- невидимая деталь Primary не мешает
prompt.RequiresLineOfSight = false
-- на ручке ящика
prompt.Parent = bottom.Handle
-- нажали
prompt.Triggered:Connect(function()
-- ещё едет — ждём
if bottom:GetAttribute("Moving") then return end
-- открываем или закрываем
furniture.Open(bottom)
-- меняем надпись
prompt.ActionText = bottom:GetAttribute("Open") and "Закрыть" or "Открыть"
-- конец обработчика
end)
-- конец перебора
end
-- конец проверки
end
-- мебель в комнату
model.Parent = sample.Parent
-- локатор больше не нужен
sample:Destroy()
-- отдаём мебель
return model
-- конец функции
end
-- расставляет всю мебель комнаты
function furniture.Generate(roomModel)
-- папка с локаторами
local folder = roomModel:FindFirstChild("Furniture")
-- мебели в комнате нет
if not folder then return nil end
-- каждый локатор
for _, sample in ipairs(folder:GetChildren()) do
-- ставим мебель
furniture.New(sample)
-- конец перебора
end
-- конец функции
end
-- отдаём таблицу модуля
return furnitureГде: ServerScriptService → MainScript · ModuleScript
Зачем: Как раньше + мебель в каждой комнате.
-- здесь лежат образцы комнат
local SS = game:GetService("ServerStorage")
-- модуль дверей
local door = require(script.Door)
-- модуль мебели
local furniture = require(script.Furniture)
-- таблица модуля
local room = {}
-- редкость и правила комнат
room.info = require(script.RoomInfo)
-- генератор случайных чисел
room.random = Random.new()
-- куда был последний поворот
room.lastTurnDirection = nil
-- можно ли поставить эту комнату следующей
local function Allowed(name, info, prevRoom)
-- настройки предыдущей (у стартовой их нет)
local prevInfo = room.info[prevRoom.Name] or {}
-- образца нет — пропускаем
if not SS.RoomSamples:FindFirstChild(name) then return false end
-- две одинаковые подряд — скучно
if name == prevRoom.Name then return false end
-- два поворота в одну сторону — коридор замкнётся
if info.Direction and info.Direction == room.lastTurnDirection then return false end
-- две лестницы подряд — нельзя
if info.Stairs and prevInfo.Stairs then return false end
-- подходит
return true
-- конец функции
end
-- случайная комната с учётом редкости
function room.GetRandom(prevRoom)
-- сумма весов подходящих комнат
local totalRarity = 0
-- все комнаты из RoomInfo
for name, info in pairs(room.info) do
-- подходящие складываем
if Allowed(name, info, prevRoom) then totalRarity += info.Rarity end
-- конец перебора
end
-- понятная ошибка вместо зависания
if totalRarity == 0 then error("Нет подходящих комнат в ServerStorage.RoomSamples") end
-- случайное число от 1 до суммы
local randomRarity = room.random:NextInteger(1, totalRarity)
-- накопленный вес
local currentRarity = 0
-- снова по комнатам (порядок тот же)
for name, info in pairs(room.info) do
-- только подходящие
if Allowed(name, info, prevRoom) then
-- прибавляем вес
currentRarity += info.Rarity
-- число попало на эту комнату
if randomRarity <= currentRarity then
-- запоминаем поворот
if info.Direction then room.lastTurnDirection = info.Direction end
-- отдаём образец
return SS.RoomSamples[name]
-- конец проверки
end
-- конец проверки
end
-- конец перебора
end
-- конец функции
end
-- ставит новую комнату за предыдущей
function room.Generate(prevRoom, number)
-- копия случайной комнаты
local newRoom = room.GetRandom(prevRoom):Clone()
-- двигаем комнату за вход
newRoom.PrimaryPart = newRoom.Enter
-- вход новой — точно на выход предыдущей
newRoom:PivotTo(prevRoom.Exit.CFrame)
-- расставляем мебель по локаторам
furniture.Generate(newRoom)
-- дверь на выходе с номером
door.New(newRoom, number)
-- показываем комнату
newRoom.Parent = workspace.GeneratedRooms
-- она станет «предыдущей» для следующей
return newRoom
-- конец функции
end
-- отдаём таблицу модуля
return roomЗапусти Play (или Run) и убедись: