DrawMarker, help text e lib.showTextUI sem lag em FiveM

Desenhe markers e mostre prompts 'Press E' em FiveM sem um loop pesado: DrawMarker apenas quando próximo, nativos de help text, lib.showTextUI e pontos ox_lib para zonas.

Você desenha um marker, anda até ele e ele pisca, ou nunca mostra, ou seu script fica em 0.30 ms em resmon fazendo nada. Markers e prompts "Press E" parecem simples, mas são a fonte clássica de loops pesados. Este artigo mostra como desenhar um marker corretamente, como mostrar um prompt, e como parar de pagar por isso quando o jogador está longe.

DrawMarker tem que rodar cada frame

Um marker é desenhado por um frame cada vez que você chama DrawMarker. Para mantê-lo na tela você o chama novamente cada frame, em um loop com 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)

Isso funciona, mas roda cada frame para a sessão inteira, mesmo quando o jogador está do outro lado do mapa. Corrija isso a seguir.

Desenhe apenas quando o jogador está próximo

Meça a distância e durma mais quando o jogador está longe. Apenas o estado próximo precisa 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)

Longe, o loop acorda uma vez por segundo e faz uma subtração. Perto do marker roda por frame, apenas enquanto precisa. Por que isto importa, e como ler em resmon, está em resmon high ms: how to optimize.

Dica: #(a - b) é o comprimento de uma diferença de vetor, a distância. Precisa de valores vec3, que GetEntityCoords já retorna.

Tipos de marker

O primeiro argumento é o tipo de marker, um número. Alguns que servidores usam muito:

Tipo Parece
1 Um cilindro
2 Uma seta chevron (rotacione 180 graus em X para apontar para baixo)
23 Um anel plano no chão
25 Um anel plano no chão, mais fino

A lista completa de tipos está no site de documentação do FiveM, em game references, markers. Os argumentos de escala mudam o tamanho, e o último valor de cor é o alpha (transparência). Coloque um marker de chão em z - 1.0 para que fique no chão, não flutuando na cintura do jogador.

Help text: o prompt integrado

O jogo tem uma mensagem de ajuda no topo esquerdo da tela. Você define um rótulo, depois a exibe cada frame enquanto o jogador está em alcance:

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~ é substituído pela chave que o jogador usa para a ação de contexto, que é E por padrão. Chame showHelp() dentro do branch distance < 1.5 acima, depois verifique a chave:

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

Registre o rótulo uma vez no topo do arquivo, não dentro do loop.

lib.showTextUI e lib.hideTextUI

Com ox_lib você pode mostrar um prompt estilizado, e você o chama uma vez quando o jogador entra, não cada frame:

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

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

lib.isTextUIOpen() diz se um já está na tela. Precisa de shared_script '@ox_lib/init.lua' no seu manifesto (veja the ox_lib menu guide). O texto não é vinculado a uma chave: você ainda verifica a chave, ou usa um keybind.

ox_lib points: nenhum loop de distância em tudo

Escrever o loop de distância à mão para cada zona se acumula. lib.points faz para você: ox_lib verifica a distância do jogador para todos os pontos juntos, e apenas roda seu código perto deles:

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

Como funciona:

  • onEnter roda uma vez quando o jogador vem dentro de distance.
  • onExit roda uma vez quando sai.
  • nearby roda cada frame enquanto eles estão dentro de distance, e não em tudo caso contrário. É onde DrawMarker vai.
  • self.currentDistance é a distância atual para o ponto.

Você pode criar centenas de pontos e apenas os que o jogador está perto custam qualquer coisa. Remova um ponto que você não precisa mais com point:remove().

Qual usar

  • Uma ou duas zonas: o loop de distância com um sleep é bem.
  • Muitas zonas, ou um script que cria zonas de config: use lib.points.
  • Interações em objetos e peds: um target é melhor que um marker. Veja ox_target: how to add targets.

Checklist

Sintoma Solução
Marker pisca ou mostra por um frame Chame DrawMarker cada frame em um loop Wait(0)
Script custa tempo de resmon quando ocioso Durma 500 a 1000 ms quando longe, Wait(0) apenas quando perto
Marker flutua no ar Desenhe em z - 1.0
Texto de prompt nunca mostra Defina com AddTextEntry, depois exiba cada frame
lib.showTextUI fica na tela Chame lib.hideTextUI() ao sair
Muitas zonas são lentas Use lib.points.new com onEnter, onExit e nearby

Respostas rápidas

Por que meu marker desaparece após um frame?

DrawMarker tem que ser chamado a cada frame, em um loop com Wait(0). Chame uma vez e ele mostra por um único frame.

Por que meu script usa tanto tempo de resmon?

Um loop Wait(0) que mede distância para cada marker roda cada frame o tempo todo. Durma mais quando o jogador está longe, ou use pontos ox_lib para que o loop apenas rode perto da zona.

Qual é melhor, help text ou lib.showTextUI?

Help text é integrado ao jogo e não precisa de recurso. lib.showTextUI é um prompt estilizado de ox_lib e é fácil de mostrar e esconder do código. Escolha um estilo e mantenha para seu servidor inteiro.

Scripts sem esse problema

Advanced BoostingBoosting de veículos pelo tablet: contratos da classe D à S+, crews e fila ao vivo.Ver script →Shop CreatorMonte uma loja em menos de um minuto — donos, funcionários, cofres e assaltos inclusos.Ver script →Quest CreatorUm editor visual de missões e diálogos com NPCs, montado nó por nó dentro do jogo.Ver script →

Continue lendo