Comprendre les composants d'apparence Ped
Construire un système de salon de tatouage et de coiffure dans FiveM nécessite une solide compréhension de la façon dont GTA V gère l'apparence des peds (personnages). Le système d'apparence est divisé en plusieurs catégories de composants : des superpositions de tête pour des caractéristiques telles que les imperfections, les poils du visage, les sourcils et le maquillage, des composants dessinables pour les vêtements et les coiffures, et des décorations de tatouage superposées au modèle pédiculaire. Chaque type de composant utilise différentes fonctions natives et suit son propre système d'indexation. Les superpositions de tête utilisent les indices 0 à 12 pour contrôler des caractéristiques telles que les imperfections (0), les poils du visage (1), les sourcils (2), le vieillissement (3), le maquillage (4), le fard à joues (5) et le rouge à lèvres (8). Les coiffures sont définies via le système de composants étirables à l'indice 2 pour les cheveux. Les tatouages utilisent un système de décoration complètement séparé avec des noms de collection et des valeurs de hachage. Avant de créer l'interface utilisateur, tu dois cartographier toutes les options disponibles pour chaque composant, y compris le nombre de variantes disponibles pour le modèle pédagogique actuel, car les personnages masculins et féminins ont des ensembles de styles disponibles différents. Utiliser GetNumHeadOverlayValues(overlayIndex) pour demander combien d'options existent pour chaque type de superposition au moment de l'exécution.
Système de caméra pour prévisualiser les personnages
Une bonne expérience de barbier et de tatouage dépend de la capacité du joueur à voir ce qu'il sélectionne en temps réel. Créez un système de caméra personnalisé qui se concentre sur la partie du corps concernée pendant que le joueur parcourt les options. Lors de la modification des cheveux, zoomez avec la caméra sur la tête. Lorsque tu sélectionnes des tatouages pour le torse, tirez l'appareil photo vers l'arrière pour afficher le haut du corps. Lorsque tu travailles sur des tatouages de jambes, positionnez la caméra pour cadrer le bas du corps. Utilisez des caméras natives scriptées pour créer des transitions fluides entre les points de vue lorsque le joueur passe d'une catégorie à l'autre. Voici un système de gestion de caméra qui gère plusieurs niveaux de zoom et zones de mise au point du corps :
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
Ajoutez la prise en charge de la rotation de la souris ou du stick analogique pour que les joueurs puissent faire tourner leur personnage tout en prévisualisant les modifications. Capturez le mouvement de la souris lorsque le NUI ne le consomme pas et appliquez-le comme rotation de cap au joueur. Cela permet aux joueurs d’examiner leur tatouage sous plusieurs angles avant de s’engager dans l’achat, améliorant ainsi considérablement l’expérience d’achat. Gelez le lecteur sur place pendant la session de personnalisation et jouez une animation inactive pour garder le personnage naturel pendant que le joueur navigue.
Personnalisation des cheveux et de la barbe
La personnalisation des cheveux et de la barbe utilise respectivement les systèmes de composants amovibles et de superposition de tête. Les coiffures sont définies avec SetPedComponentVariation en utilisant les composants indice 2 (cheveux) et indice 1 (texture/variation de couleur). La couleur des cheveux est appliquée séparément à l'aide SetPedHairColor qui prend un indice de couleurs primaires et un indice de couleurs de surbrillance. Les styles de barbe utilisent le système de superposition de tête à l'indice 1 avec une valeur d'opacité qui contrôle l'épaisseur ou la finesse des poils du visage. Construisez le NUI pour afficher des vignettes ou des noms pour chaque style disponible, mettant à jour le péd en temps réel lorsque le joueur clique sur les options. Voici la logique Lua pour appliquer les modifications de cheveux et de barbe avec aperçu en temps réel :
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
L'interface NUI devrait présenter les couleurs de cheveux sous la forme d'une palette visuelle plutôt que d'indices numérotés, mappant les indices de couleurs internes de GTA à leurs représentations RVB réelles. Incluez un curseur pour l’opacité de la barbe qui permet aux joueurs d’affiner l’épaisseur de leurs poils du visage, d’une barbe légère à une barbe épaisse. Enregistrez l'apparence précédente du joueur avant d'ouvrir le menu du coiffeur afin de pouvoir annuler toutes les modifications s'il clique sur Annuler, empêchant ainsi les modifications accidentelles de coûter de l'argent au joueur.
Système de superposition de tatouage
Les tatouages dans GTA V utilisent le système de décoration, qui superpose des superpositions de textures sur le modèle ped à l'aide de paires de hachage de collection et de superposition. Chaque tatouage est défini par un nom de collection (comme "mpairraces_overlays") et un nom de superposition (comme "MP_Airraces_Tattoo_000_M") qui identifient ensemble l'élément de tatouage spécifique. Appliquer des tatouages avec AddPedDecorationFromHashes et enlevez tous les tatouages avec ClearPedDecorations. La partie délicate est qu'il n'y a pas de natif pour supprimer un seul tatouage, donc lorsqu'un joueur souhaite supprimer un tatouage, tu dois effacer toutes les décorations et tout réappliquer sauf celle supprimée. Cela signifie que tu dois conserver une liste complète des tatouages actuels du joueur dans ton modèle de données. Voici comment gérer la collection et l’application des tatouages :
-- 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
Le catalogue de tatouage de GTA V contient des centaines d'entrées réparties dans plusieurs collections DLC. Organisez-les par zone corporelle dans ton configuration afin que le NUI puisse filtrer par zone. Pour chaque tatouage, vérifiez si la variante masculine ou féminine doit être utilisée en fonction du modèle pédagogique du joueur, car la plupart des tatouages ont des noms d'éléments distincts se terminant par _M ou _F. Affichez un aperçu lorsque le joueur survole un tatouage dans le catalogue et ne le facturez que lorsqu'il confirme la sélection.
Système de maquillage et de peinture pour le visage
Le maquillage utilise le système de superposition de tête sur plusieurs indices : blush (5), rouge à lèvres (8) et superpositions de poils de poitrine ou de teint pour des effets supplémentaires. Chaque type de maquillage dispose de plusieurs options de style et d'un curseur d'opacité qui contrôle l'intensité. Créez une section de maquillage dans le salon de coiffure NUI qui présente chaque catégorie avec des échantillons visuels montrant les couleurs disponibles. Le système de couleurs pour les utilisations du maquillage SetPedHeadOverlayColor avec un paramètre de type de couleur : tapez 0 pour les couleurs par défaut, tapez 1 pour les couleurs de cheveux (utilisées pour la barbe et les sourcils) et tapez 2 pour les couleurs de maquillage. Le maquillage utilise spécifiquement le type de couleur 2 qui fournit une palette de couleurs cosmétiques comprenant différents tons chair, rouges, roses et couleurs dramatiques. Ajoutez un curseur d'opacité pour chaque composant de maquillage afin que les joueurs puissent obtenir des looks naturels subtils ou des styles dramatiques audacieux. Stockez tous les paramètres de maquillage avec les données d'apparence du joueur afin qu'ils persistent entre les sessions et offrez une interaction miroir dans la maison du joueur où il peut ajuster son maquillage sans se rendre au magasin.
Système de paiement et tarification
Le système de paiement doit suivre ce que le joueur a modifié au cours de sa session et calculer le coût total en fonction des services rendus. Lorsqu'un joueur ouvre le menu de la boutique, prenez un instantané de son apparence actuelle. Au fur et à mesure qu'ils apportent des modifications, suivez chaque modification dans un panier de session qui cumule le total. Lorsqu'ils confirment et quittent, facturez-leur le total de toutes les modifications apportées. S'ils annulent, revenez à l'instantané. Mettez en œuvre une tarification échelonnée où les coupes de cheveux de base coûtent moins cher que les styles haut de gamme et où les prix des tatouages varient en fonction de la taille et de la complexité. Voici un système de suivi de session et de paiement :
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
Côté serveur, vérifiez que le joueur dispose de fonds suffisants avant de valider les changements d'apparence. Si le paiement échoue, informez le client d'annuler les modifications. Envisagez de proposer des forfaits dans lesquels une coupe de cheveux et une coupe de barbe coûtent moins cher que la somme des services individuels, incitant ainsi les joueurs à utiliser la gamme complète de services en une seule visite.
Sauvegarde des tenues et intégration de la garde-robe
Étendez le système de barbier et de tatouage avec une fonction de sauvegarde de tenue qui permet aux joueurs de stocker des configurations d'apparence complètes sous forme de préréglages nommés. Chaque préréglage capture l'état complet de l'apparence du joueur, y compris la coiffure et la couleur, la pilosité faciale, le maquillage et tous les tatouages actifs. Les joueurs peuvent ensuite basculer entre les looks enregistrés dans leur garde-robe ou en revisitant la boutique. Stockez les tenues dans la base de données liée à l'identifiant de citoyen du joueur avec un blob JSON contenant toutes les données d'apparence. Limitez le nombre de tenues enregistrées par joueur ou proposez des emplacements supplémentaires en tant que fonctionnalité premium. L'interaction avec la garde-robe au domicile du joueur devrait présenter un simple panneau NUI répertoriant les tenues enregistrées avec une fonction de prévisualisation qui applique temporairement chaque look afin que le joueur puisse le voir avant de s'engager. Cela lie le système d’apparence personnelle au système de logement, ce qui rend les deux caractéristiques plus précieuses ensemble que séparément.
Emplacements des magasins et intégration des PNJ Barber
Définissez plusieurs emplacements de magasins sur la carte, chacun potentiellement avec différents services disponibles et multiplicateurs de prix. Un coiffeur économique du sud peut proposer des coupes de base à bas prix, tandis qu'un salon haut de gamme à Vinewood facture des tarifs plus élevés mais propose des styles et des couleurs exclusifs. Utilisez le système de cibles ou les marqueurs de proximité pour déclencher le menu de la boutique lorsqu'un joueur s'approche du fauteuil de barbier ou de la station de tatouage. Asseyez le joueur sur la chaise en utilisant TaskStartScenarioInPlace avec un scénario assis pour les salons de coiffure, ou placez-les à un endroit précis pour les séances de tatouage. Générez des barbiers ou des tatoueurs PNJ à chaque endroit en utilisant des modèles pédagogiques appropriés et attribuez-leur des animations inactives qui leur donnent l'impression qu'ils travaillent. Lorsqu'un joueur interagit avec la boutique, le PNJ peut jouer une animation de travail à proximité du joueur pour simuler le service effectué, ajoutant ainsi une immersion visuelle à l'expérience. Après la session, le PNJ retourne à sa position inactive. Suivez les revenus par magasin dans la base de données pour prendre en charge le jeu dans les magasins appartenant aux joueurs, où les entrepreneurs achètent et gèrent leurs propres salons de coiffure ou de tatouage, fixant les prix et embauchant du personnel PNJ ou même d'autres joueurs en tant qu'employés.
