Перейти к содержимому

Соглашения UI / NUI

У каждого ресурса своя страница NUI (ui_page 'html/index.html'). bs_ui - это HUD, уведомления и общие части.

Когда ваша панель открывается, вы объявляете об этом. Все остальные панели это слышат и закрываются. Когда ваша закрывается, вы тоже объявляете. Реальный код из bs_config:

local function close()
if not isOpen then return end
isOpen = false
SetNuiFocus(false, false)
SendNUIMessage({ action = 'close' })
TriggerEvent('bs:ui:closed', 'config')
end
local function open()
if isOpen then return close() end
isOpen = true
SetNuiFocus(true, true)
SendNUIMessage({ action = 'open', data = data })
TriggerEvent('bs:ui:opened', 'config')
end
-- another UI took over: step aside
AddEventHandler('bs:ui:opened', function(what)
if what ~= 'config' and isOpen then close() end
end)
AddEventHandler('onResourceStop', function(res)
if res == GetCurrentResourceName() and isOpen then
SetNuiFocus(false, false)
TriggerEvent('bs:ui:closed', 'config')
end
end)

Правила:

  • Передавайте имя своей панели в обоих событиях. Обработчики его проверяют, а обработчик, реагировавший на любое закрытие, месяцами ломал карту местности.
  • Объявляйте пару на каждом выходе: кнопка закрытия, Esc, клавиша переключения, открытие другого UI, остановка ресурса. Пропустите один, и игрок останется с курсором мыши и без игры.
  • Объявляйте opened после открытия и закрывайтесь из собственного обработчика, не рассчитывайте на других.

/refreshui (bs_ui) - кнопка паники: закрывает всё, снимает фокус и вызывает bs:ui:closed с nil.

-- client
TriggerEvent('bs:ui:notify', { type = 'info', title = 'Radio', message = 'Signal found.', duration = 3000 })
-- server
TriggerClientEvent('bs:ui:notify', src, { type = 'error', title = 'Denied', message = 'Nope.' })

Типы, которые используются в коде: info, success, error.

Страницы вёрстаются под 1920x1080. Подключите общий скейлер, чтобы они подходили под любое разрешение:

<script src="https://cfx-nui-bs_ui/html/shared/scale.js"></script>

Он масштабирует <body> через transform: --ui-scale = clamp(min(w/1920, h/1080), 0.6, 1.25). Игроки могут переопределить его (0.6-1.4) в настройках.

Что нужно знать при использовании:

  • В CSS страницы пишите vh/vw как calc(Nvh / var(--ui-scale, 1)), чтобы они оставались реальными долями окна.
  • JS, который задаёт style.left/top из clientX/clientY или bounding rect, должен делить на BSScale.get(). BSScale.w() / BSScale.h() дают локальный вьюпорт.
  • Отказ через <html data-bs-noscale>.
  • html, body { background: transparent !important; } на каждой странице. Иначе поверх игры будет чёрный экран.
  • Никаких сообщений NUI на каждом кадре в простое. Отправляйте при изменении или с ограничением частоты (HUD дрона отправляет каждые 150 мс в полёте, это примерно максимум).
  • Палитра: янтарь / ржавчина / кость / пыль на почти чёрном. Используйте CSS-токены bs_ui и bs_menu/html/css/faction-hub.css. Никаких внешних шрифтов и CDN: у игроков может не быть к ним доступа, да и это вопрос приватности.
  • Иконки: линейные иконки в bs_ui/html/js/icons.js.
  • Звуки: bs_ui/html/js/sound.js обрабатывает позиционные звуки (maxDistance, панорамирование).