Зоны ox_lib: lib.zones.box, sphere и poly с onEnter и onExit

Как использовать зоны ox_lib в FiveM: lib.zones.box, sphere и poly с координатами, размером, поворотом и отладкой, onEnter, onExit, inside, удаление зон и ox_target.

Вам нужно знать, когда игрок входит в магазин, гараж или запретную зону, без проверки расстояния в цикле каждый кадр. Зоны ox_lib это делают для вас: вы описываете фигуру, и она вызывает вашу функцию, когда игрок входит или выходит. Это руководство охватывает три фигуры, обратные вызовы, удаление и когда использовать ox_target.

Зоны нуждаются в ox_lib как зависимости, загруженной с @ox_lib/init.lua. Если она отсутствует, смотрите ox_lib init.lua not found.

Типы зон

Есть три, все под lib.zones и все на стороне клиента.

Box, прямоугольник с высотой, хорош для комнат и дверных проёмов:

lua
local zone = lib.zones.box({
    coords = vec3(441.0, -981.0, 30.7),
    size = vec3(4.0, 6.0, 3.0),
    rotation = 90.0,
    debug = true,
    onEnter = function(self)
        print('entered the box')
    end,
    onExit = function(self)
        print('left the box')
    end,
})

Sphere, радиус вокруг точки, хорош для открытых площадей:

lua
local zone = lib.zones.sphere({
    coords = vec3(441.0, -981.0, 30.7),
    radius = 3.0,
    debug = true,
    onEnter = function() print('in range') end,
    onExit = function() print('out of range') end,
})

Poly, контур точек для неправильных форм, таких как двор или парковка:

lua
local zone = lib.zones.poly({
    points = {
        vec3(400.0, -1000.0, 29.0),
        vec3(420.0, -1000.0, 29.0),
        vec3(420.0, -970.0, 29.0),
        vec3(400.0, -970.0, 29.0),
    },
    thickness = 4.0,
    debug = true,
    onEnter = function() print('in the yard') end,
    onExit = function() print('left the yard') end,
})

Для poly, thickness — это высота фигуры вокруг высоты точек. Держите точки на уровне земли и толщину достаточно большой, чтобы включить игроков на лестницах.

Координаты, размер и поворот

  • coords — это центр коробки или сферы. Получите его с GetEntityCoords(PlayerPedId()) при стоянии там, или из инструмента координат.
  • size для коробки — это ширина, длина и высота как vec3, центрированные на coords.
  • rotation поворачивает коробку вокруг её вертикальной оси в градусах. Используйте направление здания или двери.
  • radius предназначен для сфер.

Самый простой способ получить это правильно — debug = true: зона рисуется в мире, поэтому вы можете пройти сквозь неё, изменить число и перезагрузить ресурс, пока она не подойдёт. Выключите отладку перед выпуском, так как она рисует каждый кадр.

Обратные вызовы: onEnter, onExit, inside

Три обратных вызова охватывают случаи:

lua
local zone = lib.zones.sphere({
    coords = vec3(441.0, -981.0, 30.7),
    radius = 4.0,
    onEnter = function(self)
        lib.showTextUI('[E] Open shop')
    end,
    onExit = function(self)
        lib.hideTextUI()
    end,
    inside = function(self)
        if IsControlJustReleased(0, 38) then
            print('pressed E inside the zone')
        end
    end,
})
  • onEnter и onExit запускаются один раз за пересечение. Используйте их для уведомлений, текстового пользовательского интерфейса, загрузки или выгрузки чего-то.
  • inside запускается каждый тик пока игрок внутри. Всё, что должно быть проверено каждый кадр, как нажатие клавиши, идёт сюда, и ничто вне зоны вас не стоит.

Держите inside коротким: никаких вызовов базы данных, никаких lib.callback.await, никаких Wait в цикле. Для деталей нажатия клавиши смотрите маркеры и текстовый пользовательский интерфейс.

Удаление зон

lib.zones.box возвращает объект. Сохраняйте его и удаляйте, когда область больше не имеет значения:

lua
local shopZone

local function createZone()
    shopZone = lib.zones.box({
        coords = vec3(441.0, -981.0, 30.7),
        size = vec3(4.0, 4.0, 3.0),
        onEnter = function() lib.showTextUI('[E] Shop') end,
        onExit = function() lib.hideTextUI() end,
    })
end

local function removeZone()
    if shopZone then
        shopZone:remove()
        shopZone = nil
    end
end

AddEventHandler('onResourceStop', function(resource)
    if resource == GetCurrentResourceName() then
        removeZone()
        lib.hideTextUI()
    end
end)

Помните скрыть любой пользовательский интерфейс, который показывала зона: если игрок внутри, когда вы её удаляете, onExit может не быть вызван для них.

Вы также можете спросить зону, находится ли точка внутри неё, с zone:contains(coords), например, чтобы проверить позицию игрока при открытии меню.

Зоны vs ox_target

Они решают разные проблемы:

lib.zones ox_target
Вопрос "Находится ли игрок в этой области?" "Смотрит ли игрок на это и нажимает кнопку?"
Результат Ваши обратные вызовы Список опций в меню цели
Используйте для Безопасные зоны, ограничения скорости, музыкальные области, спавнинг NPC-ов при близости Двери, банкоматы, прилавки магазинов, объекты

Если игрок должен выбрать взаимодействие, используйте зоны ox_target и сравните с более старыми системами в qb-target vs ox-target. Если что-то должно происходить автоматически при прибытии, используйте зону lib. Их комбинирование часто встречается: зона загружает ped при прибытии и ox_target даёт ped его опции.

Производительность

Зоны дёшевы по сравнению с ручным циклом #(coords - playerCoords) < 3.0, потому что ox_lib проверяет их в одном центральном цикле и только запускает вашу функцию inside, где это применимо. Несколько привычек держат это так:

  • Создавайте зоны один раз, не в цикле или каждый раз, когда открывается меню.
  • Не создавайте сотни крошечных зон, если одна больше подойдёт.
  • Поместите работу в onEnter и onExit вместо inside.
  • Выключите debug в production.

Проверьте результат с resmon, как в high resmon ms.

Контрольный список

Симптом Решение
Зона никогда не срабатывает Используйте центр coords, правильный size и rotation; установите debug = true чтобы видеть
lib равен nil Добавьте @ox_lib/init.lua в shared_scripts
Текстовый пользовательский интерфейс остаётся после выхода Вызовите lib.hideTextUI() в onExit и когда зона удаляется
Нажатие клавиши не обнаруживается Проверьте это в inside, а не в onEnter
Перезагрузка ресурса оставляет зоны позади Вызовите zone:remove() на onResourceStop
Высокий resmon Держите inside лёгким и отключите debug

Короткие ответы

В чём разница между lib.zones и ox_target?

lib.zones говорит вам, когда игрок находится внутри области, поэтому вы запускаете собственный код. ox_target добавляет взаимодействие (опцию посмотреть и щёлкнуть) на сущность или зону. Используйте зоны для областей, ox_target для вещей, которые игрок нажимает.

Как показать зону во время её построения?

Установите debug = true в параметрах зоны. Это рисует фигуру в мире, поэтому вы можете исправить координаты, размер и поворот. Выключите это, когда закончите.

Как удалить зону?

Сохраняйте объект, который возвращает lib.zones.box и вызовите zone:remove(). Сделайте это, когда ресурс останавливается или когда область больше не нужна.

Скрипты без этой проблемы

Shop CreatorМагазин меньше чем за минуту — владельцы, сотрудники, сейфы и ограбления в комплекте.Смотреть скрипт →Advanced BoostingУгон машин на заказ через планшет: контракты от класса D до S+, команды и живая очередь.Смотреть скрипт →CCTV Security CamerasУстанавливаемые камеры, планшет с мультиэкраном в реальном времени и распечатанные фото-улики.Смотреть скрипт →

Читайте также