DrawMarker, помощь текста и lib.showTextUI без лага в FiveM
Рисуйте маркеры и показывайте подсказки 'Press E' в FiveM без тяжёлого цикла: DrawMarker только когда рядом, помощь текста native, lib.showTextUI и ox_lib точки для зон.
Вы рисуете маркер, подходите к нему и он мерцает, или никогда не показывается, или ваш скрипт сидит на 0.30 мс в resmon не делая ничего. Маркеры и подсказки «Press E» выглядят простыми, но они классический источник тяжёлых циклов. Эта статья показывает, как рисовать маркер правильно, как показывать подсказку, и как перестать платить за это, когда игрок далеко.
DrawMarker должна работать каждый кадр
Маркер рисуется в течение одного кадра каждый раз, когда вы вызываете DrawMarker. Чтобы держать это на экране, вы вызываете это снова каждый кадр, в цикле с Wait(0):
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):
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, чтобы он сидел на полу, а не плавал на талии игрока.
Помощь текста: встроенная подсказка
Игра имеет справочное сообщение вверху слева экрана. Вы определяете ярлык, затем отображаете его каждый кадр, пока игрок в диапазоне:
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 выше, затем проверьте ключ:
if distance < 1.5 then
showHelp()
if IsControlJustReleased(0, 38) then
print('opened')
end
endЗарегистрируйте ярлык один раз вверху файла, не внутри цикла.
lib.showTextUI и lib.hideTextUI
С ox_lib вы можете показать стилизованную подсказку, и вы вызываете её один раз когда игрок входит, не каждый кадр:
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 проверяет расстояние игрока ко всем точкам вместе, и только запускает ваш код рядом с ними:
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 — узел за узлом прямо в игре.Смотреть скрипт →