Arquitetura do sistema de trabalho de táxi
Um sistema de trabalho de táxi é um recurso fundamental para qualquer servidor de RPG que deseja oferecer aos jogadores um trabalho de nível básico acessível com interação genuína do jogador. Ao contrário de muitos outros trabalhos que podem parecer enfadonhos e repetitivos, um sistema de táxi bem projetado cria encontros orgânicos de roleplay enquanto os motoristas pegam passageiros, negociam tarifas e navegam pela cidade sob pressão de tempo. A arquitetura se divide em dois modos distintos: transporte de jogador para jogador, onde passageiros reais solicitam caronas, e modo de missão NPC, onde o sistema gera locais de embarque e desembarque para jogo solo fora dos horários de pico. Ambos os modos compartilham o mesmo mecanismo de cálculo de tarifas, interface de usuário do taxímetro e sistema de gerenciamento de veículos. A principal decisão de projeto é usar um sistema de despacho centralizado, onde as solicitações de viagem vão para uma fila compartilhada visível para todos os motoristas em serviço, ou um sistema baseado em proximidade, onde o motorista mais próximo tem prioridade. A maioria das implementações bem-sucedidas utiliza uma abordagem híbrida com um quadro de despacho que mostra todas as solicitações pendentes, mas destaca as próximas, dando aos motoristas a liberdade de escolher seus trabalhos e ao mesmo tempo garantindo que os passageiros sejam recolhidos rapidamente.
Implementação de taxímetro
O taxímetro é o coração do sistema tarifário e precisa parecer autêntico e, ao mesmo tempo, permanecer transparente tanto para o motorista quanto para o passageiro. Um medidor adequado rastreia dois componentes: uma tarifa básica cobrada no início de cada viagem e uma tarifa por distância que aumenta à medida que o veículo se move. Alguns servidores também adicionam uma taxa de tempo de espera que cobra uma taxa menor por segundo quando o táxi está parado, simulando a prática real de cobrar pelo tempo gasto no trânsito. O medidor deve ser visível tanto para o motorista quanto para qualquer passageiro no veículo através de um elemento NUI persistente posicionado no canto da tela. Aqui está uma implementação de medidor do lado do cliente que calcula a tarifa com base na distância percorrida:
local meterActive = false
local currentFare = 0.0
local lastPosition = nil
local baseFare = 50
local ratePerMile = 15
local waitRatePerSecond = 0.5
local totalDistance = 0.0
function StartMeter()
meterActive = true
currentFare = baseFare
totalDistance = 0.0
lastPosition = GetEntityCoords(PlayerPedId())
SendNUIMessage({action = 'showMeter', fare = currentFare, distance = 0.0})
CreateThread(function()
while meterActive do
Wait(500)
local currentPos = GetEntityCoords(PlayerPedId())
local speed = GetEntitySpeed(PlayerPedId())
if speed > 1.0 then
local dist = #(currentPos - lastPosition)
totalDistance = totalDistance + dist
local miles = totalDistance / 1609.34
currentFare = baseFare + (miles * ratePerMile)
else
currentFare = currentFare + (waitRatePerSecond * 0.5)
end
lastPosition = currentPos
SendNUIMessage({
action = 'updateMeter',
fare = math.floor(currentFare),
distance = math.floor(totalDistance),
speed = math.floor(speed * 2.236936)
})
end
end)
end
function StopMeter()
meterActive = false
local finalFare = math.floor(currentFare)
SendNUIMessage({action = 'stopMeter', fare = finalFare})
return finalFare
endO componente NUI do medidor deve ser compacto, mas legível, mostrando a tarifa atual de forma destacada, juntamente com a distância percorrida e a tarifa atual aplicada. Use uma fonte monoespaçada para a exibição da tarifa para imitar a aparência de um taxímetro real e adicione uma animação sutil cada vez que a tarifa aumenta para fornecer feedback visual de que o taxímetro está funcionando. Considere adicionar um recurso de estimativa de tarifa que calcule o custo aproximado com base na distância em linha reta até o destino antes do início da viagem, para que os passageiros possam decidir se desejam prosseguir.
Sistema de missão de coleta de NPC
As missões NPC mantêm os motoristas de táxi ocupados quando não há passageiros reais suficientes no servidor. O sistema gera locais aleatórios de coleta e entrega a partir de uma lista selecionada de pontos de interesse ao redor do mapa, cria um NPC no local de coleta e orienta o motorista durante todo o ciclo tarifário. A qualidade da experiência da missão do NPC depende muito dos dados de localização: usar apenas coordenadas aleatórias produz coletas não naturais no meio do nada, portanto, manter uma lista selecionada manualmente de locais realistas, como hospitais, restaurantes, hotéis e shopping centers, faz com que as missões pareçam genuínas. Aqui está a lógica do lado do servidor para gerar e despachar missões NPC:
local MissionLocations = {
{coords = vector3(-240.49, -987.78, 29.29), label = 'Pillbox Medical Center'},
{coords = vector3(228.28, -790.70, 30.58), label = 'Legion Square'},
{coords = vector3(-1044.57, -2739.76, 13.85), label = 'Los Santos Airport'},
{coords = vector3(126.19, -1282.72, 29.27), label = 'Strawberry Avenue'},
{coords = vector3(-556.18, -196.17, 38.22), label = 'Rockford Hills'},
{coords = vector3(1159.56, -314.45, 69.21), label = 'Vinewood Hills'},
{coords = vector3(-1222.08, -906.82, 12.32), label = 'Del Perro Pier'},
{coords = vector3(373.58, 325.71, 103.57), label = 'Downtown Vinewood'},
}
RegisterNetEvent('taxi:server:requestNPCMission', function()
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player or Player.PlayerData.job.name ~= 'taxi' then return end
local pickup = MissionLocations[math.random(#MissionLocations)]
local dropoff = MissionLocations[math.random(#MissionLocations)]
while pickup.label == dropoff.label do
dropoff = MissionLocations[math.random(#MissionLocations)]
end
local estimatedDistance = #(pickup.coords - dropoff.coords)
local basePay = 50
local distancePay = math.floor(estimatedDistance / 1609.34 * 15)
local totalPay = basePay + distancePay
TriggerClientEvent('taxi:client:startNPCMission', src, {
pickup = pickup,
dropoff = dropoff,
estimatedPay = totalPay,
npcModel = Config.NPCModels[math.random(#Config.NPCModels)],
missionId = 'TAXI-' .. os.time() .. '-' .. math.random(1000, 9999)
})
end)No lado do cliente, crie o NPC no local de coleta com uma animação de espera, adicione um sinal para guiar o motorista e reproduza uma animação de entrada do veículo quando o motorista chegar. Durante a viagem, o NPC deve usar comportamentos naturais, como olhar ao redor e ocasionalmente comentar sobre a direção através de balões de bate-papo. Quando o veículo chega ao destino, o NPC sai e a tarifa é paga automaticamente através de um evento no servidor. Adicione variedade gerando ocasionalmente missões especiais com pagamentos mais elevados, como transferências de aeroporto ou clientes VIP que exigem uma condução cuidadosa e sem colisões.
Cálculo de tarifas e preços dinâmicos
Além do cálculo básico baseado na distância, um sistema tarifário sofisticado leva em conta a hora do dia, as condições do trânsito e o tipo de veículo. Implemente preços dinâmicos durante horários de pico no servidor, quando muitos jogadores estão online e a demanda de táxi excede a oferta. O multiplicador de pico deve ser comunicado de forma transparente aos passageiros antes de confirmarem a viagem, para que não haja surpresas no final. Você pode calcular a demanda dinamicamente rastreando a proporção de solicitações de viagem pendentes em relação aos motoristas disponíveis. Aqui está um mecanismo de cálculo de tarifa que incorpora estas variáveis:
function CalculateFare(pickupCoords, dropoffCoords, vehicleClass)
local distance = #(pickupCoords - dropoffCoords)
local miles = distance / 1609.34
local rates = Config.FareRates
local baseFare = rates.base
local perMile = rates.perMile
-- Vehicle class multiplier
local classMultiplier = {
[0] = 0.8, -- Compacts (budget)
[1] = 1.0, -- Sedans (standard)
[2] = 1.0, -- SUVs
[3] = 1.2, -- Coupes (comfort)
[18] = 1.5, -- Super (luxury)
}
local vehMultiplier = classMultiplier[vehicleClass] or 1.0
-- Time-of-day multiplier (night premium)
local hour = GetClockHours()
local timeMultiplier = 1.0
if hour >= 22 or hour <= 5 then
timeMultiplier = 1.3 -- 30% night surcharge
end
-- Surge pricing based on demand
local surgeMultiplier = GetCurrentSurgeMultiplier()
local totalFare = (baseFare + (miles * perMile)) * vehMultiplier * timeMultiplier * surgeMultiplier
return {
total = math.floor(totalFare),
breakdown = {
base = baseFare,
distance = math.floor(miles * perMile),
vehicleClass = vehMultiplier,
nightSurcharge = timeMultiplier > 1.0,
surgeActive = surgeMultiplier > 1.0,
surgeRate = surgeMultiplier
}
}
endExiba o detalhamento da tarifa ao passageiro quando ele solicitar uma viagem, para que ele entenda o que está pagando. Se o preço dinâmico estiver ativo, mostre o multiplicador claramente com um indicador de cor diferente na IU. Esta transparência cria confiança entre motoristas e passageiros e reduz disputas sobre valores de tarifas. Permita que os passageiros selecionem sua classe de veículo preferida no momento da reserva, com opções econômicas usando carros compactos e opções de luxo usando sedãs ou SUVs de alta qualidade com tarifas premium.
Exibição de rota e navegação GPS
Fornecer orientação visual de rota torna a experiência do táxi mais tranquila para motoristas novos e experientes. FiveM fornece o SetNewWaypoint nativo para roteamento GPS básico, mas uma abordagem mais refinada desenha a rota diretamente no minimapa e, opcionalmente, renderiza um caminho 3D no mundo. Use a função SetBlipRoute nas mensagens de destino para ativar o caminho GPS integrado e aprimorá-lo com mensagens personalizadas nos principais pontos de referência ao longo da rota. Para benefício do passageiro, exiba o tempo estimado de chegada e a distância restante na IU do medidor, atualizando em tempo real conforme o veículo avança. Veja como configurar o sistema de exibição de rota com rastreamento de waypoint:
local routeBlip = nil
local checkpointBlips = {}
function SetTaxiRoute(destination, checkpoints)
ClearTaxiRoute()
routeBlip = AddBlipForCoord(destination.x, destination.y, destination.z)
SetBlipSprite(routeBlip, 198)
SetBlipColour(routeBlip, 5)
SetBlipScale(routeBlip, 1.0)
SetBlipRoute(routeBlip, true)
SetBlipRouteColour(routeBlip, 5)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName('Destination')
EndTextCommandSetBlipName(routeBlip)
if checkpoints then
for i, cp in ipairs(checkpoints) do
local cpBlip = AddBlipForCoord(cp.x, cp.y, cp.z)
SetBlipSprite(cpBlip, 1)
SetBlipColour(cpBlip, 3)
SetBlipScale(cpBlip, 0.6)
table.insert(checkpointBlips, cpBlip)
end
end
end
function ClearTaxiRoute()
if routeBlip then
SetBlipRoute(routeBlip, false)
RemoveBlip(routeBlip)
routeBlip = nil
end
for _, blip in ipairs(checkpointBlips) do
RemoveBlip(blip)
end
checkpointBlips = {}
end
function UpdateETADisplay(destination)
CreateThread(function()
while routeBlip do
Wait(2000)
local pos = GetEntityCoords(PlayerPedId())
local remaining = #(pos - destination)
local speed = GetEntitySpeed(PlayerPedId())
local etaSeconds = speed > 2.0 and (remaining / speed) or 0
local etaMinutes = math.floor(etaSeconds / 60)
SendNUIMessage({
action = 'updateETA',
distance = math.floor(remaining),
eta = etaMinutes > 0 and (etaMinutes .. ' min') or 'Arriving'
})
end
end)
endPara uma camada extra de imersão, implemente um sistema de classificação onde os passageiros avaliam sua viagem com base em fatores como tempo de viagem comparado à estimativa, número de colisões durante a viagem e se o motorista seguiu as leis de trânsito. Exiba a classificação média do motorista em seu perfil de táxi para que os passageiros possam vê-la antes de aceitar a corrida, criando um incentivo para que os motoristas prestem um bom serviço.
Sistema de dicas e classificações de motorista
Um sistema de gorjetas adiciona uma mecânica social gratificante que incentiva os motoristas a prestar um serviço excelente. Depois que a tarifa for paga e o passageiro sair do veículo, exiba um aviso de gorjeta ao passageiro com opções predefinidas como 10%, 15%, 20% ou um valor personalizado. A gorjeta vai diretamente para o motorista, além da tarifa base e qualquer comissão da empresa de táxi. Acompanhe dicas cumulativas por motorista no banco de dados para criar tabelas de classificação e desbloquear bônus para os pilotos mais bem avaliados. No lado do servidor, processe as gorjetas através do mesmo sistema de transação das tarifas para garantir consistência e evitar duplicação. Os motoristas que mantêm uma classificação alta e uma média de gorjetas ao longo do tempo podem desbloquear vantagens como acesso a veículos premium, taxas de comissão reduzidas da empresa ou prioridade na fila de despacho. Combine o sistema de gorjetas com um sistema de revisão onde os passageiros deixam uma breve revisão de texto visível para o motorista, criando um ciclo de feedback que melhora a qualidade geral do serviço de táxi no servidor.
Solicitações de embarque e passeio
O quadro de despacho é o ponto central onde os motoristas de táxi encontram seu próximo emprego. Construa-o como um painel NUI acessível a partir da sede da empresa de táxi ou através de uma tecla de atalho durante o serviço. O quadro deve exibir todas as solicitações de viagem pendentes classificadas por proximidade, com cada entrada mostrando o nome do passageiro, local de retirada, destino, tarifa estimada e distância estimada. Quando um motorista aceita um trabalho, remova-o do quadro para todos os outros motoristas e inicie uma contagem regressiva, caso o motorista não chegue à coleta no prazo, o trabalho retorna ao quadro e o motorista recebe uma penalidade de confiabilidade. Para o lado voltado para o passageiro, crie um aplicativo ou comando de telefone simples que permita solicitar uma viagem especificando sua localização e destino atuais. A solicitação entra na fila de despacho e o passageiro recebe atualizações conforme o motorista aceita e se aproxima. Implemente um sistema de cancelamento com uma pequena taxa para cancelamentos tardios para evitar que os passageiros solicitem e cancelem viagens repetidamente, o que desperdiça o tempo do motorista e cria uma experiência frustrante.
Sistema de Gestão de Veículos e Frota
Um sistema de táxi completo necessita de um gerenciamento adequado de veículos para que os motoristas utilizem veículos adequados e a empresa mantenha sua frota. Crie um sistema de check-out de veículos na garagem de táxis onde os motoristas selecionam os veículos disponíveis da empresa. Cada veículo deve ter um contador de quilometragem rastreado, nível de combustível e status de condição, e os motoristas são responsáveis por devolver os veículos em condições aceitáveis ou enfrentar deduções de reparos de seus ganhos. A garagem deve estocar diferentes níveis de veículos: sedãs econômicos para tarifas padrão, SUVs confortáveis para serviço premium e veículos de luxo para reservas VIP. Acompanhe as estatísticas de uso de cada veículo, incluindo o total de tarifas concluídas, receitas geradas e custos de manutenção. Implementar um sistema de consumo de combustível que exija que os motoristas reabasteçam nos postos de gasolina durante o seu turno, acrescentando um custo operacional realista que os motoristas experientes aprendam a gerir de forma eficiente. No final do turno, o motorista devolve o veículo à garagem, seus ganhos totais são calculados menos a comissão da empresa e quaisquer custos com danos ao veículo, e o pagamento líquido é depositado em sua conta bancária. Esse ciclo completo cria uma experiência de trabalho realista que reflete as operações reais da empresa de táxi.

