Стартовое меню состоит из ScreenGui, отдельной точки камеры и одного LocalScript. До клика Play камера смотрит на карту из заданной точки, после клика интерфейс исчезает, а камера возвращается к персонажу.
Меню не должно помещать игрока в отдельную локацию. Игрок уже на карте, но клиентская камера временно становится Scriptable. Поэтому другие игроки не замечают меню, а серверу не нужно знать о его анимации.
Переводим CurrentCamera в Scriptable и берём CFrame из MenuCamera.
ScreenGui перекрывает экран и предлагает одну ясную кнопку.
После Play камера переходит в Custom, а ScreenGui выключается.
Собираем объекты стартового меню
В Workspace создайте Part с именем MenuCamera. Поверните его к центру сцены, включите Anchored и выключите CanCollide. В StarterGui нужен ScreenGui с Frame, TextLabel и TextButton. Скрипт лежит внутри ScreenGui, потому что камера и UI принадлежат клиенту.
| Объект | Где лежит | Зачем нужен |
|---|---|---|
| MenuCamera | Workspace | Хранит позицию и направление |
| StartMenu | StarterGui | Копируется каждому игроку |
| PlayButton | StartMenu | Запускает переход в игру |
| LocalScript | StartMenu | Меняет UI и камеру только на этом клиенте |
После этого шага у каждой части есть одна роль. Интерфейс собирает действие, логика меняет состояние, а вывод показывает признак успеха. Это проще отлаживать, чем один большой обработчик.

Камера и UI меняются на клиенте. Серверная логика игры не затрагивается
Пишем LocalScript для кнопки Play
Перед установкой CameraSubject дождитесь Character и Humanoid. Кнопка может быть нажата до полной загрузки аватара, поэтому WaitForChild здесь защищает реальный сценарий, а не маскирует ошибку.
local Players = game:GetService("Players")
local TweenService = game:GetService("TweenService")
local player = Players.LocalPlayer
local camera = workspace.CurrentCamera
local cameraPoint = workspace:WaitForChild("MenuCamera")
local screenGui = script.Parent
local panel = screenGui:WaitForChild("Panel")
local playButton = panel:WaitForChild("PlayButton")
camera.CameraType = Enum.CameraType.Scriptable
camera.CFrame = cameraPoint.CFrame
local started = false
playButton.Activated:Connect(function()
if started then return end
started = true
playButton.Active = false
local tween = TweenService:Create(
panel,
TweenInfo.new(0.35, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
{ BackgroundTransparency = 1 }
)
tween:Play()
tween.Completed:Wait()
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
camera.CameraSubject = humanoid
camera.CameraType = Enum.CameraType.Custom
screenGui.Enabled = false
end)Меню видит только локальный игрок. Позиция камеры редактируется перемещением MenuCamera. Повторный клик отсекается флагом started. После анимации CameraType снова Custom.

Нужно явно переключиться между ними. Сравнение показывает, какой вариант легче поддерживать и проверять.
Как Scriptable камера возвращается к игроку
CameraType Scriptable отключает обычное управление камерой. Поэтому нельзя только скрыть ScreenGui. Если забыть Custom, игрок увидит карту, но не сможет поворачивать обзор. CameraSubject указывает, за каким Humanoid нужно следовать.
| Этап | CameraType | ScreenGui |
|---|---|---|
| До загрузки | Scriptable | Enabled |
| Клик Play | Scriptable | Анимация |
| Игра | Custom | Disabled |
| Респавн | Custom | Disabled |
Сохраняйте в одном месте то, что может измениться. Если одно и то же значение скопировано в три функции, после первой правки они начнут расходиться. Один объект состояния и одна функция отрисовки снимают эту проблему.
Практика: тестируем старт и респавн
Проверяйте меню в режиме Play, а не только в редакторе. CurrentCamera существует на клиенте, а событие Activated работает и с мышью, и с касанием, и с геймпадом. Отдельно сделайте Reset Character, чтобы убедиться, что меню не возвращается случайно.
- Установите MenuCamera над картой и поверните его к главной сцене.
- Запустите Play и не трогайте кнопку 5 секунд.
- Нажмите Play один раз и подождите исчезновения.
- Поверните камеру мышью и пройдите несколько шагов.
- Нажмите Reset Character и дождитесь нового Humanoid.
- Проверьте кнопку в мобильной эмуляции Device.
Меню появляется до первого клика. Камера не дрожит и не перемещается за аватаром. После Play игрок полностью контролирует обзор. Повторный клик и респавн не ломают состояние.

Четыре точки до публикации. Пройдите все четыре сценария перед публикацией проекта.
Доводим стартовый экран до релиза
На финальном экране оставьте одну главную кнопку. Настройки, титры и выбор слота можно добавить позже, когда переход к игре надёжен. Выдерживайте контраст текста, а кнопку делайте достаточно крупной для пальца. На маленьком экране выводите название в две строки, а не уменьшайте шрифт до нечитаемого.
CurrentCamera и GUI нужно менять на клиенте.
Интерфейс исчезнет, но камера останется фиксированной.
Part упадёт под действием физики и изменит CFrame.
Флаг started должен срабать до ожидания.
Что получится в итоге

В итоге игрок видит чистый стартовый экран на фоне карты, а после Play сразу получает управление.
Где должен лежать скрипт?
Внутри ScreenGui в StarterGui как LocalScript.
Зачем нужен MenuCamera?
Это Anchored Part, из CFrame которого берутся позиция и направление камеры.
Почему Activated, а не MouseButton1Click?
Activated удобнее для мыши, касания и геймпада.
Как понять, что проект готов?
Он повторяет целевой сценарий несколько раз подряд, понятно реагирует на ошибочный ввод и не теряет состояние при обычных действиях.
Можно ли копировать код целиком?
Можно как стартовую точку, но сначала замените значения из примера, затем запустите проект по шагам. Если вы не можете объяснить одну строку, её лучше разобрать до следующего шага.
Работу с GUI, событиями и Luau можно закрепить в курсе Lua. Более общая схема интерфейса есть в гайде про ScreenGui.
Дальше добавьте точку спавна и телепорт. Так меню станет входом в настоящий игровой цикл, а не отдельной декорацией.