Tutorial 2026-04-10

Desenvolvimento de Estúdios de Tatuagem e Barbearias em FiveM

TDYSKY

TDYSKY

Fundador & Lead Developer na Agency Scripts

Compreendendo os componentes de aparência do Ped

Construir um sistema de tatuagem e barbearia no FiveM requer um conhecimento sólido de como GTA V lida com a aparência do ped (personagem). O sistema de aparência é dividido em várias categorias de componentes: sobreposições de cabeça para características como manchas, pelos faciais, sobrancelhas e maquiagem, componentes desenháveis ​​para roupas e estilos de cabelo e decorações de tatuagem que são colocadas sobre o modelo ped. Cada tipo de componente utiliza diferentes funções nativas e segue seu próprio sistema de indexação. As sobreposições de cabeça usam índices de 0 a 12 para controlar recursos como manchas (0), pelos faciais (1), sobrancelhas (2), envelhecimento (3), maquiagem (4), blush (5) e batom (8). Os estilos de cabelo são definidos através do sistema de componentes desenháveis ​​no índice 2 para cabelos. As tatuagens usam um sistema de decoração completamente separado com nomes de coleções e valores hash. Antes de construir a UI, você precisa mapear todas as opções disponíveis para cada componente, incluindo o número de variações disponíveis para o modelo ped atual, porque personagens masculinos e femininos têm diferentes conjuntos de estilos disponíveis. Use GetNumHeadOverlayValues(overlayIndex) para consultar quantas opções existem para cada tipo de sobreposição em tempo de execução.

Sistema de câmera para visualização de personagens

Uma ótima experiência de barbeiro e tatuagem depende do jogador poder ver o que está selecionando em tempo real. Construa um sistema de câmera personalizado que foca na parte relevante do corpo enquanto o jogador navega pelas opções. Ao editar o cabelo, amplie a câmera na cabeça. Ao selecionar tatuagens para o tronco, puxe a câmera para trás para mostrar a parte superior do corpo. Ao trabalhar em tatuagens nas pernas, posicione a câmera para enquadrar a parte inferior do corpo. Use nativos de câmera com script para criar transições suaves entre pontos de vista enquanto o jogador alterna entre categorias. Aqui está um sistema de gerenciamento de câmera que lida com vários níveis de zoom e áreas de foco corporal:

local customCam = nil
local camActive = false

local CameraPresets = {
    head = {offset = vector3(0.0, 0.65, 0.65), fov = 35.0},
    face = {offset = vector3(0.0, 0.45, 0.62), fov = 25.0},
    torso = {offset = vector3(0.0, 1.2, 0.2), fov = 45.0},
    legs = {offset = vector3(0.0, 1.5, -0.5), fov = 50.0},
    full = {offset = vector3(0.0, 2.5, 0.2), fov = 50.0},
}

function SetupPreviewCamera(preset)
    local ped = PlayerPedId()
    local pedCoords = GetEntityCoords(ped)
    local pedHeading = GetEntityHeading(ped)
    local headingRad = math.rad(pedHeading)

    local cam = CameraPresets[preset] or CameraPresets.full
    local camX = pedCoords.x + cam.offset.y * math.sin(-headingRad)
    local camY = pedCoords.y + cam.offset.y * math.cos(-headingRad)
    local camZ = pedCoords.z + cam.offset.z

    if customCam then
        local newCam = CreateCam('DEFAULT_SCRIPTED_CAMERA', true)
        SetCamCoord(newCam, camX, camY, camZ)
        PointCamAtCoord(newCam, pedCoords.x, pedCoords.y, pedCoords.z + cam.offset.z)
        SetCamFov(newCam, cam.fov)
        SetCamActiveWithInterp(newCam, customCam, 800, 1, 1)

        Wait(800)
        DestroyCam(customCam, false)
        customCam = newCam
    else
        customCam = CreateCam('DEFAULT_SCRIPTED_CAMERA', true)
        SetCamCoord(customCam, camX, camY, camZ)
        PointCamAtCoord(customCam, pedCoords.x, pedCoords.y, pedCoords.z + cam.offset.z)
        SetCamFov(customCam, cam.fov)
        SetCamActive(customCam, true)
        RenderScriptCams(true, true, 500, true, false)
    end
    camActive = true
end

function DestroyPreviewCamera()
    if customCam then
        RenderScriptCams(false, true, 500, true, false)
        DestroyCam(customCam, false)
        customCam = nil
        camActive = false
    end
end

Adicione suporte à rotação do mouse ou do stick analógico para que os jogadores possam girar seu personagem enquanto visualizam as alterações. Capture o movimento do mouse quando o NUI não o estiver consumindo e aplique-o como rotação de direção ao ped do jogador. Isso permite que os jogadores examinem suas tatuagens de vários ângulos antes de se comprometerem com a compra, melhorando significativamente a experiência de compra. Congele o jogador no lugar durante a sessão de personalização e reproduza uma animação inativa para manter o personagem com aparência natural enquanto o jogador navega.

Personalização de cabelo e barba

A personalização do cabelo e da barba usa o componente desenhável e os sistemas de sobreposição de cabeça, respectivamente. Os estilos de cabelo são definidos com SetPedComponentVariation usando índice de componente 2 (cabelo) e índice 1 (variação de textura/cor). A cor do cabelo é aplicada separadamente usando SetPedHairColor que usa um índice de cores primárias e um índice de cores de realce. Os estilos de barba usam o sistema de sobreposição de cabeça no índice 1 com um valor de opacidade que controla a espessura ou a espessura dos pelos faciais. Construa o NUI para mostrar miniaturas ou nomes de cada estilo disponível, atualizando o ped em tempo real conforme o jogador clica nas opções. Aqui está a lógica Lua para aplicar alterações no cabelo e na barba com visualização em tempo real:

function ApplyHairStyle(ped, styleIndex, textureIndex, primaryColor, highlightColor)
    SetPedComponentVariation(ped, 2, styleIndex, textureIndex or 0, 0)
    SetPedHairColor(ped, primaryColor, highlightColor)
end

function ApplyBeardStyle(ped, styleIndex, opacity, color)
    SetPedHeadOverlay(ped, 1, styleIndex, opacity or 1.0)
    SetPedHeadOverlayColor(ped, 1, 1, color, color)
end

function ApplyEyebrows(ped, styleIndex, opacity, color)
    SetPedHeadOverlay(ped, 2, styleIndex, opacity or 1.0)
    SetPedHeadOverlayColor(ped, 2, 1, color, color)
end

function GetAvailableHairStyles(ped)
    local styles = {}
    local numStyles = GetNumberOfPedDrawableVariations(ped, 2)

    for i = 0, numStyles - 1 do
        local numTextures = GetNumberOfPedTextureVariations(ped, 2, i)
        table.insert(styles, {
            index = i,
            textures = numTextures,
            label = 'Style ' .. (i + 1)
        })
    end

    return styles
end

function GetAvailableBeardStyles(ped)
    local styles = {}
    local numStyles = GetNumHeadOverlayValues(1)

    for i = 0, numStyles - 1 do
        table.insert(styles, {
            index = i,
            label = 'Beard ' .. (i + 1)
        })
    end

    return styles
end

A interface NUI deve apresentar as cores dos cabelos como uma paleta visual em vez de índices numerados, mapeando os índices de cores internos do GTA para suas representações RGB reais. Inclui um controle deslizante para a opacidade da barba que permite aos jogadores ajustar a espessura de seus pelos faciais, desde uma barba rala até uma barba espessa e cheia. Armazene a aparência anterior do jogador antes de abrir o menu do barbeiro para que você possa reverter todas as alterações se clicar em cancelar, evitando que alterações acidentais custem dinheiro ao jogador.

Sistema de sobreposição de tatuagem

As tatuagens no GTA V usam o sistema de decoração, que coloca sobreposições de textura no modelo ped usando pares de hash de coleção e sobreposição. Cada tatuagem é definida por um nome de coleção (como "mpairraces_overlays") e um nome de sobreposição (como "MP_Airraces_Tattoo_000_M") que juntos identificam o ativo de tatuagem específico. Aplique tatuagens com AddPedDecorationFromHashes e remova todas as tatuagens com ClearPedDecorations. A parte complicada é que não existe um nativo para remover uma única tatuagem, então quando um jogador deseja remover uma tatuagem, você precisa limpar todas as decorações e reaplicar tudo, exceto a removida. Isso significa que você deve manter uma lista completa das tatuagens atuais do jogador em seu modelo de dados. Veja como gerenciar a coleta e aplicação de tatuagens:

-- Tattoo database structure
local TattooZones = {
    head = {label = 'Head', camera = 'face'},
    torso = {label = 'Torso', camera = 'torso'},
    left_arm = {label = 'Left Arm', camera = 'torso'},
    right_arm = {label = 'Right Arm', camera = 'torso'},
    left_leg = {label = 'Left Leg', camera = 'legs'},
    right_leg = {label = 'Right Leg', camera = 'legs'},
    back = {label = 'Back', camera = 'torso'}
}

-- Available tattoos per zone (abbreviated, real list has hundreds)
Config.Tattoos = {
    torso = {
        {collection = 'mpairraces_overlays', overlay = 'MP_Airraces_Tattoo_000_M',
         label = 'Wing Design', price = 500, zone = 'torso'},
        {collection = 'mpbiker_overlays', overlay = 'MP_MP_Biker_Tat_000_M',
         label = 'Flame Skull', price = 750, zone = 'torso'},
    },
    left_arm = {
        {collection = 'mpchristmas2_overlays', overlay = 'MP_Xmas2_M_Tat_000',
         label = 'Sleeve Art', price = 600, zone = 'left_arm'},
    }
}

function ApplyAllTattoos(ped, tattooList)
    ClearPedDecorations(ped)

    for _, tattoo in ipairs(tattooList) do
        local collectionHash = GetHashKey(tattoo.collection)
        local overlayHash = GetHashKey(tattoo.overlay)
        AddPedDecorationFromHashes(ped, collectionHash, overlayHash)
    end
end

function PreviewTattoo(ped, tattoo, currentTattoos)
    local previewList = {}
    for _, t in ipairs(currentTattoos) do
        table.insert(previewList, t)
    end
    table.insert(previewList, tattoo)
    ApplyAllTattoos(ped, previewList)
end

function RemoveTattoo(ped, tattooIndex, currentTattoos)
    local newList = {}
    for i, t in ipairs(currentTattoos) do
        if i ~= tattooIndex then
            table.insert(newList, t)
        end
    end
    ApplyAllTattoos(ped, newList)
    return newList
end

O catálogo de tatuagens do GTA V contém centenas de entradas espalhadas por várias coleções de DLC. Organize-os por zona corporal em sua configuração para que o NUI possa filtrar por área. Para cada tatuagem, verifique se a variante masculina ou feminina deve ser usada com base no modelo ped do jogador, já que a maioria das tatuagens tem nomes de ativos separados que terminam em _M ou _F. Mostre uma prévia quando o jogador passar o mouse sobre uma tatuagem no catálogo e só carregue quando ele confirmar a seleção.

Sistema de maquiagem e pintura facial

A maquiagem usa o sistema de sobreposição de cabeça em vários índices: blush (5), batom (8) e pelos no peito ou sobreposições de pele para efeitos adicionais. Cada tipo de maquiagem possui várias opções de estilo e um controle deslizante de opacidade que controla a intensidade. Crie uma seção de maquiagem na barbearia NUI que apresente cada categoria com amostras visuais mostrando as cores disponíveis. O sistema de cores para maquiagem utiliza SetPedHeadOverlayColor com um parâmetro de tipo de cor: tipo 0 para cores padrão, tipo 1 para cores de cabelo (usado para barbas e sobrancelhas) e tipo 2 para cores de maquiagem. A maquiagem usa especificamente o tipo de cor 2, que fornece uma paleta de cores cosméticas, incluindo vários tons de pele, vermelhos, rosas e cores dramáticas. Adicione um controle deslizante de opacidade para cada componente de maquiagem para que os jogadores possam obter looks naturais sutis ou estilos dramáticos ousados. Armazene todas as configurações de maquiagem junto com os dados de aparência do jogador para que persistam entre as sessões e ofereça uma interação de espelho na casa do jogador, onde ele pode ajustar a maquiagem sem visitar a loja.

Sistema de pagamento e preços

O sistema de pagamento precisa rastrear o que o jogador mudou durante a sessão e calcular o custo total com base nos serviços prestados. Quando um jogador abre o menu da loja, tire uma foto de sua aparência atual. À medida que eles fazem alterações, acompanhe cada modificação em um carrinho de sessão que acumula o total. Quando eles confirmarem e saírem, cobre o total de todas as alterações feitas. Se eles cancelarem, reverta para o instantâneo. Implemente preços diferenciados onde os cortes de cabelo básicos custam menos do que os estilos premium e onde os preços das tatuagens variam de acordo com o tamanho e a complexidade. Aqui está um sistema de rastreamento e pagamento de sessão:

local sessionChanges = {}
local originalAppearance = nil

function StartCustomizationSession()
    local ped = PlayerPedId()
    originalAppearance = CaptureFullAppearance(ped)
    sessionChanges = {}
end

function TrackChange(category, item, price)
    -- Remove previous change in same category if exists
    for i = #sessionChanges, 1, -1 do
        if sessionChanges[i].category == category then
            table.remove(sessionChanges, i)
        end
    end

    table.insert(sessionChanges, {
        category = category,
        item = item,
        price = price
    })

    UpdateCartUI()
end

function UpdateCartUI()
    local total = 0
    local items = {}

    for _, change in ipairs(sessionChanges) do
        total = total + change.price
        table.insert(items, {
            label = change.category .. ': ' .. change.item,
            price = change.price
        })
    end

    SendNUIMessage({
        action = 'updateCart',
        items = items,
        total = total
    })
end

function ConfirmAndPay()
    local total = 0
    for _, change in ipairs(sessionChanges) do
        total = total + change.price
    end

    TriggerServerEvent('appearance:server:pay', total, sessionChanges)
end

function CancelSession()
    if originalAppearance then
        RestoreFullAppearance(PlayerPedId(), originalAppearance)
    end
    sessionChanges = {}
    DestroyPreviewCamera()
end

No lado do servidor, valide se o jogador possui fundos suficientes antes de realizar as alterações de aparência. Caso o pagamento falhe, avise o cliente para reverter as alterações. Considere oferecer pacotes em que cortar o cabelo e aparar a barba juntos custe menos do que a soma dos serviços individuais, incentivando os jogadores a usar toda a gama de serviços em uma única visita.

Economia de roupa e integração de guarda-roupa

Amplie o sistema de barbeiro e tatuagem com um recurso de salvamento de roupas que permite aos jogadores armazenar configurações completas de aparência como predefinições nomeadas. Cada predefinição captura o estado completo da aparência do jogador, incluindo estilo e cor do cabelo, pelos faciais, maquiagem e todas as tatuagens ativas. Os jogadores podem então alternar entre os looks salvos no guarda-roupa de sua casa ou revisitar a loja. Armazene as roupas no banco de dados vinculadas ao ID de cidadão do jogador com um blob JSON contendo todos os dados de aparência. Limite o número de trajes salvos por jogador ou ofereça slots adicionais como recurso premium. A interação do guarda-roupa na casa do jogador deve apresentar um painel NUI simples listando os looks salvos com uma função de visualização que aplica temporariamente cada look para que o jogador possa vê-lo antes de comprometê-lo. Isto liga o sistema de aparência pessoal ao sistema de habitação, tornando ambas as características mais valiosas juntas do que separadamente.

Locais de lojas e integração com NPC Barber

Defina vários locais de lojas no mapa, cada um potencialmente com diferentes serviços disponíveis e multiplicadores de preços. Um barbeiro econômico na zona sul pode oferecer cortes básicos a preços baixos, enquanto um salão sofisticado em Vinewood cobra tarifas premium, mas oferece estilos e cores exclusivos. Use o sistema de alvo ou marcadores de proximidade para acionar o menu da loja quando um jogador se aproxima da cadeira de barbeiro ou da estação de tatuagem. Sente o jogador na cadeira usando TaskStartScenarioInPlace com um cenário sentado para barbearias, ou faça-o ficar em um local específico para sessões de tatuagem. Gere barbeiros ou tatuadores NPC em cada local usando modelos ped apropriados e atribua a eles animações ociosas que os façam parecer que estão trabalhando. Quando um jogador interage com a loja, o NPC pode reproduzir uma animação funcional perto do jogador para simular o serviço que está sendo executado, adicionando imersão visual à experiência. Após a sessão, o NPC retorna à posição inativa. Rastreie a receita por loja no banco de dados para apoiar a jogabilidade da loja de propriedade do jogador, onde os empreendedores compram e gerenciam suas próprias barbearias ou estúdios de tatuagem, definindo preços e contratando funcionários de NPCs ou até mesmo outros jogadores como funcionários.

Partilhar este artigo

Pronto para melhorar o teu servidor?

Explora os nossos scripts FiveM premium na loja Agency Scripts ou junta-te à nossa comunidade no Discord para suporte e atualizações.