Roblox · Doors · урок 8
За последней дверью — финальная комната. Камера разворачивается, дверь за спиной медленно захлопывается, экран темнеет, появляется надпись. Публикуем игру.
Синим — что добавляем на этом уроке.
Workspace └─ EndRoom (Model) — как StartRoom, но с Enter и без Exit ├─ Build → Lights (Model) ├─ Enter (Part) └─ CameraPart (Part) — точка камеры: прозрачная, лицом вглубь комнаты ReplicatedStorage └─ EndEvent (RemoteEvent) — сервер → игроки StarterGui └─ EndGui (ScreenGui) — IgnoreGuiInset вкл. └─ Frame (Frame) — на весь экран, чёрный ├─ EndText (TextLabel) — «Ты выбрался!» └─ EndLocal (LocalScript)
Где: ServerScriptService → MainScript → Room · ModuleScript
Зачем: + медленное закрытие двери.
-- плавный поворот двери
local TS = game:GetService("TweenService")
-- здесь лежит образец двери
local SS = game:GetService("ServerStorage")
-- сообщает главному скрипту номер открытой двери
local enterEvent = SS:WaitForChild("EnterEvent")
-- таблица модуля
local door = {}
-- открывает дверь
function door.Open(doorModel, number)
-- отмечаем: открыта
doorModel:SetAttribute("Open", true)
-- петля повёрнута на 90°
local cframe = doorModel.Spinner.CFrame * CFrame.Angles(0, math.rad(90), 0)
-- за полсекунды
local tweenInfo = TweenInfo.new(0.5, Enum.EasingStyle.Linear)
-- поворачиваем петлю — дверь приварена и едет следом
TS:Create(doorModel.Spinner, tweenInfo, {CFrame = cframe}):Play()
-- скрип двери
doorModel.Door.Open:Play()
-- игрок вошёл в комнату number + 1
enterEvent:Fire(number)
-- конец функции
end
-- медленно захлопывает дверь (финал)
function door.Close(doorModel)
-- обратно на 90°
local cframe = doorModel.Spinner.CFrame * CFrame.Angles(0, math.rad(-90), 0)
-- 10 секунд, с отскоком в конце
local tweenInfo = TweenInfo.new(10, Enum.EasingStyle.Bounce, Enum.EasingDirection.Out)
-- закрываем
TS:Create(doorModel.Spinner, tweenInfo, {CFrame = cframe}):Play()
-- конец функции
end
-- ключ в руках или в рюкзаке
local function FindKey(character)
-- чей это персонаж
local player = game.Players:GetPlayerFromCharacter(character)
-- Tool «Key» или nil
return character:FindFirstChild("Key") or (player and player.Backpack:FindFirstChild("Key"))
-- конец функции
end
-- ставит дверь на выход комнаты
function door.New(roomModel, number, locked)
-- копия образца
local doorModel = SS.Door:Clone()
-- в дверной проём
doorModel:PivotTo(roomModel.Exit.CFrame)
-- закрыта
doorModel:SetAttribute("Open", false)
-- номер на табличке: 01, 02…
doorModel.Label.NumberGui.Number.Text = string.format("%02d", number)
-- замок виден, только если дверь заперта
doorModel.Lock.Transparency = locked and 0 or 1
-- кто-то подошёл к двери
doorModel.Trigger.Touched:Connect(function(otherPart)
-- модель, которой принадлежит деталь
local character = otherPart.Parent
-- это персонаж?
local humanoid = character:FindFirstChildOfClass("Humanoid")
-- не персонаж или уже открыта
if not humanoid or doorModel:GetAttribute("Open") then return end
-- замка нет
if not locked then
-- просто открываем
door.Open(doorModel, number)
-- готово
return
-- конец проверки
end
-- есть ли у игрока ключ
local key = FindKey(character)
-- есть
if key then
-- дверь больше не заперта
locked = false
-- ключ тратится
key:Destroy()
-- замок исчезает
doorModel.Lock:Destroy()
-- щелчок замка
doorModel.Door.Unlock:Play()
-- открываем
door.Open(doorModel, number)
-- конец проверки
end
-- конец обработчика
end)
-- дверь — часть комнаты
doorModel.Parent = roomModel
-- отдаём дверь
return doorModel
-- конец функции
end
-- отдаём таблицу модуля
return doorГде: ServerScriptService · Script
Зачем: Финальная комната и катсцена после последней двери.
-- модуль комнат
local room = require(script.Room)
-- модуль дверей
local door = require(script.Room.Door)
-- модуль монстра
local monster = require(script.Monster)
-- номер открытой двери
local enterEvent = game.ServerStorage:WaitForChild("EnterEvent")
-- финал — всем игрокам
local endEvent = game.ReplicatedStorage:WaitForChild("EndEvent")
-- сколько комнат вместе со стартовой
local ROOMS = 10
-- монстр после каждой 3-й двери
local MONSTER_EVERY = 3
-- первая «предыдущая» — стартовая
local prevRoom = workspace.StartRoom
-- финальная комната
local endRoom = workspace.EndRoom
-- все комнаты по номерам: 1 — стартовая
local generatedRooms = {prevRoom}
-- дверь 01 в стартовой комнате
door.New(prevRoom, 1, false)
-- комнаты 2…10
for i = 2, ROOMS do
-- новая комната с дверью номер i
prevRoom = room.Generate(prevRoom, i)
-- запоминаем под номером
generatedRooms[i] = prevRoom
-- конец цикла
end
-- двигаем финальную комнату за вход
endRoom.PrimaryPart = endRoom.Enter
-- ставим за последней комнатой
endRoom:PivotTo(prevRoom.Exit.CFrame)
-- финал уже показан?
local finished = false
-- открыта дверь number
enterEvent.Event:Connect(function(number)
-- открыта последняя дверь — финал
if number == #generatedRooms then
-- уже показали
if finished then return end
-- больше не показываем
finished = true
-- игрок заходит в финальную комнату
task.wait(2)
-- катсцена у всех игроков
endEvent:FireAllClients()
-- камера разворачивается
task.wait(2)
-- дверь за спиной медленно закрывается
door.Close(prevRoom.Door)
-- свет мигает
room.Lights(endRoom)
-- номер делится на 3 — монстр
elseif number % MONSTER_EVERY == 0 then
-- комната, куда вошёл игрок
local nextRoom = generatedRooms[number + 1]
-- звук мигания
local sound = workspace:FindFirstChild("Sounds") and workspace.Sounds:FindFirstChild("Lights")
-- играем, если есть
if sound then sound:Play() end
-- лампы мигают — предупреждение
room.Lights(nextRoom)
-- 2 секунды, чтобы спрятаться
task.wait(2)
-- монстр пролетает комнаты
monster.New(number, generatedRooms)
-- конец проверки
end
-- конец обработчика
end)Где: StarterGui → EndGui → Frame · LocalScript
Зачем: Камера, затемнение и надпись.
-- плавные изменения
local TS = game:GetService("TweenService")
-- чёрный экран
local frame = script.Parent
-- надпись
local text = frame:WaitForChild("EndText")
-- камера игрока
local camera = workspace.CurrentCamera
-- сигнал финала
local endEvent = game.ReplicatedStorage:WaitForChild("EndEvent")
-- 2 секунды, ровно
local tweenInfo = TweenInfo.new(2, Enum.EasingStyle.Linear)
-- экран пока прозрачный
frame.BackgroundTransparency = 1
-- текст тоже
text.TextTransparency = 1
-- сервер прислал финал
endEvent.OnClientEvent:Connect(function()
-- точка камеры — берём сейчас, когда комната уже на месте
local cameraPart = workspace.EndRoom:WaitForChild("CameraPart")
-- развернуться к двери
local goal = cameraPart.CFrame * CFrame.Angles(0, math.rad(180), 0)
-- камерой управляет скрипт
camera.CameraType = Enum.CameraType.Scriptable
-- камера плывёт и разворачивается
TS:Create(camera, tweenInfo, {CFrame = goal}):Play()
-- смотрим, как закрывается дверь
task.wait(10)
-- экран темнеет
TS:Create(frame, tweenInfo, {BackgroundTransparency = 0}):Play()
-- чуть позже
task.wait(0.4)
-- появляется надпись
TS:Create(text, tweenInfo, {TextTransparency = 0}):Play()
-- конец обработчика
end)Запусти Play (или Run) и убедись: