DrawMarker, помощь текста и lib.showTextUI без лага в FiveM

Рисуйте маркеры и показывайте подсказки 'Press E' в FiveM без тяжёлого цикла: DrawMarker только когда рядом, помощь текста native, lib.showTextUI и ox_lib точки для зон.

Вы рисуете маркер, подходите к нему и он мерцает, или никогда не показывается, или ваш скрипт сидит на 0.30 мс в resmon не делая ничего. Маркеры и подсказки «Press E» выглядят простыми, но они классический источник тяжёлых циклов. Эта статья показывает, как рисовать маркер правильно, как показывать подсказку, и как перестать платить за это, когда игрок далеко.

DrawMarker должна работать каждый кадр

Маркер рисуется в течение одного кадра каждый раз, когда вы вызываете DrawMarker. Чтобы держать это на экране, вы вызываете это снова каждый кадр, в цикле с Wait(0):

lua
local coords = vec3(441.2, -981.9, 30.7)

CreateThread(function()
    while true do
        DrawMarker(
            1,                                  -- type: cylinder
            coords.x, coords.y, coords.z - 1.0, -- position (on the ground)
            0.0, 0.0, 0.0,                      -- direction
            0.0, 0.0, 0.0,                      -- rotation
            1.5, 1.5, 0.5,                      -- scale
            50, 150, 255, 120,                  -- red, green, blue, alpha
            false, false, 2, false, nil, nil, false
        )
        Wait(0)
    end
end)

Это работает, но это работает каждый кадр для целого сеанса, даже когда игрок по всей карте. Исправьте это далее.

Рисуйте только когда игрок рядом

Измеряйте расстояние и спите дольше, когда игрок далеко. Только близкое состояние требует Wait(0):

lua
local coords = vec3(441.2, -981.9, 30.7)

CreateThread(function()
    while true do
        local sleep = 1000
        local pedCoords = GetEntityCoords(PlayerPedId())
        local distance = #(pedCoords - coords)

        if distance < 15.0 then
            sleep = 0
            DrawMarker(1, coords.x, coords.y, coords.z - 1.0,
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.5, 1.5, 0.5,
                50, 150, 255, 120, false, false, 2, false, nil, nil, false)

            if distance < 1.5 then
                -- show the prompt here (next section)
            end
        end

        Wait(sleep)
    end
end)

Далеко, цикл просыпается один раз в секунду и делает одно вычитание. Рядом маркера он работает за кадр, только пока ему требуется. Почему это имеет значение и как читать это в resmon находится в resmon high ms: как оптимизировать.

Совет: #(a - b) — это длина векторной разности, расстояние. Ему требуются значения vec3, которые GetEntityCoords уже возвращает.

Типы маркеров

Первый аргумент — это тип маркера, число. Несколько, которые серверы используют много:

Тип Выглядит как
1 Цилиндр
2 Стрелка шеврона (поверните его на 180 градусов на X, чтобы указать вниз)
23 Плоское кольцо на земле
25 Плоское кольцо на земле, тоньше

Полный список типов находится на сайте документации FiveM, под ссылками игры, маркеры. Аргументы масштаба меняют размер, и последнее значение цвета — это альфа (прозрачность). Поместите маркер земли на z - 1.0, чтобы он сидел на полу, а не плавал на талии игрока.

Помощь текста: встроенная подсказка

Игра имеет справочное сообщение вверху слева экрана. Вы определяете ярлык, затем отображаете его каждый кадр, пока игрок в диапазоне:

lua
AddTextEntry('MY_SCRIPT_HELP', 'Press ~INPUT_CONTEXT~ to open the garage')

local function showHelp()
    BeginTextCommandDisplayHelp('MY_SCRIPT_HELP')
    EndTextCommandDisplayHelp(0, false, true, -1)
end

~INPUT_CONTEXT~ заменяется на ключ, который игрок использует для действия контекста, по умолчанию E. Вызовите showHelp() внутри ветки distance < 1.5 выше, затем проверьте ключ:

lua
if distance < 1.5 then
    showHelp()
    if IsControlJustReleased(0, 38) then
        print('opened')
    end
end

Зарегистрируйте ярлык один раз вверху файла, не внутри цикла.

lib.showTextUI и lib.hideTextUI

С ox_lib вы можете показать стилизованную подсказку, и вы вызываете её один раз когда игрок входит, не каждый кадр:

lua
lib.showTextUI('[E] Open the garage', {
    position = 'right-center',
    icon = 'warehouse',
})

-- when the player leaves:
lib.hideTextUI()

lib.isTextUIOpen() говорит вам, если один уже на экране. Ему требуется shared_script '@ox_lib/init.lua' в вашем манифесте (см. ox_lib menu guide). Текст не привязан к ключу: вы всё ещё проверяете ключ сами, или используете привязку ключей.

ox_lib точки: вообще никакого цикла расстояния

Написание цикла расстояния вручную для каждой зоны накапливается. lib.points делает это для вас: ox_lib проверяет расстояние игрока ко всем точкам вместе, и только запускает ваш код рядом с ними:

lua
local point = lib.points.new({
    coords = vec3(441.2, -981.9, 30.7),
    distance = 15.0,
})

function point:onEnter()
    lib.showTextUI('[E] Open the garage')
end

function point:onExit()
    lib.hideTextUI()
end

function point:nearby()
    DrawMarker(1, self.coords.x, self.coords.y, self.coords.z - 1.0,
        0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.5, 1.5, 0.5,
        50, 150, 255, 120, false, false, 2, false, nil, nil, false)

    if self.currentDistance < 1.5 and IsControlJustReleased(0, 38) then
        print('opened')
    end
end

Как это работает:

  • onEnter работает один раз, когда игрок входит в distance.
  • onExit работает один раз, когда они уходят.
  • nearby работает каждый кадр, пока они находятся внутри distance, и вообще не иначе. Это где идёт DrawMarker.
  • self.currentDistance — это текущее расстояние к точке.

Вы можете создать сотни точек и только те, рядом с которыми игрок стоит, стоят что-то. Удалите точку, которую вам больше не нужны с point:remove().

Какой использовать

  • Одна или две зоны: цикл расстояния со сном хорошо.
  • Много зон, или скрипт, который создаёт зоны из конфига: используйте lib.points.
  • Взаимодействия на объектах и персонажах: target лучше чем маркер. См. ox_target: как добавить targets.

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

Проблема Решение
Маркер мерцает или показывает один кадр Вызовите DrawMarker каждый кадр в цикле Wait(0)
Скрипт стоит resmon времени в режиме ожидания Спите 500 на 1000 мс когда далеко, Wait(0) только когда рядом
Маркер плавает в воздухе Рисуйте это на z - 1.0
Текст подсказки никогда не показывается Определите его с AddTextEntry, затем отображайте каждый кадр
lib.showTextUI остаётся на экране Вызовите lib.hideTextUI() при выходе
Много зон медленно Используйте lib.points.new с onEnter, onExit и nearby

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

Почему мой маркер исчезает после одного кадра?

DrawMarker должен быть вызван каждый кадр, в цикле с Wait(0). Вызовите его один раз и он показывает один кадр.

Почему мой скрипт использует так много времени resmon?

Цикл Wait(0), который измеряет расстояние к каждому маркеру, работает каждый кадр всё время. Спите дольше, когда игрок далеко, или используйте ox_lib точки, чтобы цикл работал только рядом с зоной.

Что лучше, помощь текста или lib.showTextUI?

Помощь текста встроена в игру и требует никакого ресурса. lib.showTextUI — стилизованная подсказка из ox_lib и легко показывать и скрывать из кода. Выберите один стиль и сохраняйте его для вашего целого сервера.

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

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

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