{}const=>[]async()letfn</>var
LuaРазработка

ScreenGui в Roblox: адаптивное меню и кнопки для компьютера и телефона

Собираем ScreenGui с меню и TextButton в Roblox Studio, подключаем Activated, AnchorPoint, Scale, ограничения размера и плавное открытие через TweenService.

К

Кодик

Автор

7 мин чтения

Для меню Roblox создайте ScreenGui в StarterGui, добавьте Frame и TextButton, а обработчик кнопки поместите в LocalScript. Используйте событие Activated, размеры через Scale, AnchorPoint для привязки и UISizeConstraint, чтобы меню оставалось удобным на телефоне и компьютере.

Содержимое StarterGui копируется в PlayerGui каждого игрока, а экранный интерфейс работает на клиенте. Кнопка не должна сама менять монеты, выдавать предмет или подтверждать победу. Она управляет локальным видом и при необходимости отправляет серверу узкий запрос через RemoteEvent. Такое разделение делает меню быстрым, а игровые правила защищёнными.

1ScreenGui

Контейнер экранного интерфейса в PlayerGui.

2Activated

Единое событие клика и касания для TextButton и ImageButton.

3Scale + constraints

Гибкий размер с разумным минимумом и максимумом.

Путь от Activated на OpenButton до открытого Frame Menu через UIScale
Путь одного нажатия: TextButton OpenButton ловит Activated, LocalScript включает Frame с именем Menu и гонит UIScale от 0.92 к 1 через TweenService за 0.18 секунды, а на закрытии снимает Visible только после события Completed.

ScreenGui Roblox: меню и кнопки с плавным открытием

Создайте ScreenGui с именем MainGui, внутри Frame Menu и TextButton OpenButton. У Frame задайте AnchorPoint 0.5, 0.5 и Position 0.5, 0, 0.5, 0. Скрипт ниже находится внутри ScreenGui. Он меняет масштаб через UIScale, поэтому анимация не ломает рассчитанное положение.

local TweenService = game:GetService("TweenService")
local gui = script.Parent
local menu = gui:WaitForChild("Menu")
local button = gui:WaitForChild("OpenButton")
local scale = menu:FindFirstChildOfClass("UIScale") or Instance.new("UIScale")

scale.Parent = menu
menu.Visible = false

local function setMenuOpen(isOpen)
    menu.Visible = true
    scale.Scale = isOpen and 0.92 or 1

    local tween = TweenService:Create(
        scale,
        TweenInfo.new(0.18, Enum.EasingStyle.Quad),
        { Scale = isOpen and 1 or 0.92 }
    )
    tween:Play()

    if not isOpen then
        tween.Completed:Once(function()
            menu.Visible = false
        end)
    end
end

button.Activated:Connect(function()
    setMenuOpen(not menu.Visible)
end)
Ожидаемый результат
  • Первое нажатие: Frame появляется и увеличивается до 100%
  • Повторное нажатие: Frame уменьшается и скрывается

Для реального меню добавьте отдельную кнопку закрытия и флаг состояния, потому что Visible меняется только после завершения закрывающей анимации. Во время tween временно блокируйте повторное нажатие или отменяйте предыдущую анимацию. Если кнопка запускает покупку, LocalScript показывает ожидание и отправляет itemName через RemoteEvent, а успех получает обратно.

🔥 100 000+ учеников уже с нами

Устал читать теорию?
Пора кодить!

Кодик — приложение, где ты учишься программировать через практику. AI-наставник, интерактивные уроки, реальные проекты.

🤖 AI 24/7
🎓 Сертификаты
💰 Бесплатно
🚀 Начать учиться
Присоединились сегодня

Offset, Scale и ограничения

ЭлементЧто означаетЧто делать
ScaleДоля размера родителяОсновной адаптивный размер и позиция
OffsetФиксированные пикселиОтступы, тонкие линии, минимальные детали
AnchorPointТочка привязки 0..1Центрирование и привязка к краям
UISizeConstraintMinSize и MaxSizeЗащита от слишком маленького или большого окна
UIAspectRatioConstraintСоотношение сторонКарточки, квадратные иконки

Не пытайтесь сделать весь интерфейс только на Scale. На очень широком мониторе панель станет огромной, а на маленьком телефоне слишком тесной. Комбинируйте относительную основу с ограничениями и внутренними отступами. В Studio включайте эмуляцию разных устройств, затем проверяйте опубликованную версию на физическом телефоне.

Проверка меню: Scale, AnchorPoint, UISizeConstraint и запуск на телефоне
Что проверить в меню перед публикацией: доля Scale в Position и Size, AnchorPoint 0.5, 0.5 у Frame, заполненные MinSize и MaxSize в UISizeConstraint, эмуляция устройств в Studio и один запуск опубликованной версии на реальном телефоне.

Практика: соберите MainGui и добейтесь плавного открытия Menu

Откройте пустой Baseplate и соберите меню с нуля: ScreenGui с именем MainGui в StarterGui, внутри Frame Menu и TextButton OpenButton. Успех выглядит так: первое нажатие показывает Frame и растягивает его с 0.92 до полного размера за 0.18 секунды, повторное нажатие сжимает и прячет. Весь код лежит в LocalScript внутри MainGui, серверный Script здесь не нужен.

  1. ScreenGui MainGui в StarterGui. Вставьте ScreenGui в StarterGui, переименуйте в MainGui и положите внутрь Frame с именем Menu и TextButton с именем OpenButton. Нажмите Play и найдите в проводнике копию MainGui внутри Players, вашего игрока и PlayerGui.
  2. AnchorPoint и Position у Frame. Задайте у Menu AnchorPoint 0.5, 0.5 и Position 0.5, 0, 0.5, 0, а размер наберите долями Scale, не пикселями Offset. Потяните окно Studio за угол: Frame остаётся по центру и меняет размер вместе с окном.
  3. LocalScript и событие Activated. Положите в MainGui LocalScript, подпишитесь на button.Activated и переключайте в обработчике menu.Visible. Запустите игру и нажмите OpenButton: Frame появляется и пропадает мгновенно, анимации пока нет.
  4. UIScale через TweenService. Добавьте в Menu объект UIScale и анимируйте его свойство Scale от 0.92 к 1 вызовом TweenService:Create с TweenInfo.new(0.18, Enum.EasingStyle.Quad). Открытие превращается в рост из центра, а рассчитанное положение Frame не сдвигается.
  5. Скрытие по tween.Completed. На закрытии переносите menu.Visible = false внутрь tween.Completed:Once, иначе Frame исчезнет в первом же кадре анимации. Нажмите кнопку два раза подряд: меню сначала досжимается до 0.92, потом пропадает.

Теперь сломайте меню намеренно. Замените Scale в Position и Size на крупные значения Offset и включите в Studio эмуляцию телефона: панель, собранная под окно ноутбука, вылезет за край экрана или займёт его целиком, потому что пиксели не пересчитываются под другое разрешение. Второй эксперимент: жмите OpenButton несколько раз подряд, пока идёт закрывающий tween. Функция setMenuOpen читает menu.Visible, а он ещё равен true, поэтому состояние собьётся: реальному меню нужен отдельный флаг и блокировка кнопки на время анимации.

Критерий готовности. Готово, когда вы можете объяснить, почему обработчик живёт в LocalScript, откуда в PlayerGui берётся копия MainGui и почему анимацию ведёт UIScale, а не свойство Size. Подтверждение простое: Frame открывается и закрывается по Activated и на компьютере, и в эмуляции телефона, а UISizeConstraint держит меню между MinSize и MaxSize.

Дальше добавьте в Menu отдельный CloseButton и флаг состояния, чтобы открытие и закрытие не зависели от текущего значения Visible. Повесьте UIAspectRatioConstraint на карточки внутри меню, тогда квадратные иконки не расплющатся на широком мониторе. Если кнопка запускает покупку, пусть LocalScript показывает ожидание и отправляет itemName через RemoteEvent, а результат подтверждает сервер.

Частые ошибки и почему они появляются

Интерфейс часто выглядит хорошо только в том окне, где его собирали. Причина обычно в больших Offset для Position и Size. Вторая проблема появляется, когда один LocalScript знает обо всех экранах и серверных правилах сразу. Третья связана с кнопками: MouseButton1Click работает для мыши, а Activated удобнее для нескольких способов ввода.

Скрипт на сервере двигает UI

Экранное меню принадлежит конкретному клиенту. Анимацию и локальное состояние держите в LocalScript.

Кнопка выдаёт награду локально

Клиент отправляет запрос, но изменение общего состояния подтверждает сервер.

Нет проверки маленького экрана

Эмуляция и реальный телефон должны входить в критерий готовности, а не быть последней случайной проверкой.

Самопроверка

Чем Activated лучше MouseButton1Click для кнопки в Roblox?

Activated срабатывает на клик мышью, на тап по экрану и на другие способы активации TextButton или ImageButton. MouseButton1Click ловит только мышь, поэтому на телефоне и геймпаде такая кнопка останется мёртвой.

Где искать ScreenGui во время игры, если он лежит в StarterGui?

Во время игры ScreenGui лежит в PlayerGui конкретного игрока: содержимое StarterGui копируется туда для каждого. В проводнике при запущенном тесте ищите MainGui по пути Players, ваш игрок, PlayerGui.

Что ограничивает максимальный размер меню на широком мониторе?

Максимальный размер меню ограничивает UISizeConstraint со свойством MaxSize, а MinSize не даёт панели схлопнуться на маленьком телефоне. Один только Scale так не умеет: доля от родителя растёт вместе с монитором.

Почему интерфейс разъезжается на телефоне, хотя в Studio выглядел нормально?

Интерфейс разъезжается, когда Position и Size набраны большими значениями Offset: фиксированные пиксели не пересчитываются под другое разрешение. Соберите основу на Scale, оставьте Offset для отступов и тонких линий, затем проверьте макет в эмуляции устройств и на физическом телефоне.

Можно ли двигать элементы ScreenGui серверным скриптом?

Двигать элементы ScreenGui серверным Script не нужно: экранное меню принадлежит конкретному клиенту, а анимация и локальное состояние живут в LocalScript. Сервер подключают, только когда кнопка меняет общее состояние игры, и запрос к нему идёт через RemoteEvent.

Почему меню исчезает раньше, чем доигрывает анимация закрытия?

Меню исчезает раньше времени, когда menu.Visible = false стоит сразу после tween:Play(): Frame пропадает в том же кадре, а анимация доигрывает уже невидимый объект. Перенесите эту строку в tween.Completed:Once, и меню сначала сожмётся до 0.92, а потом скроется.

Что делать дальше

Соберите одно меню из Frame, заголовка, кнопки закрытия и действия. Проверьте четыре размера экрана и навигацию с клавиатуры или геймпада, если она нужна игре. Логику функций и событий можно повторить на курсе Lua. Для серверного действия подключите RemoteEvent, а для награды изучите выдачу Tool.

🎯Хватит откладывать

Понравилась статья?
Пора применять на практике!

В Кодик ты не просто читаешь — ты сразу пишешь код. Теория + практика = реальный скилл.

Мгновенная практика
🧠AI объяснит код
🏆Сертификат

Без регистрации • Без карты