Présentation
Créer {itemType}
Monétiser
Politiques et directives

Création d'avatar en expérience

*Ce contenu est traduit en utilisant l'IA (Beta) et peut contenir des erreurs. Pour consulter cette page en anglais, clique ici.

Vous pouvez publier une expérience qui permet aux joueurs de créer, personnaliser et acheter des corps d'avatar en temps réel. Lorsqu'ils sont achetés, ces corps personnalisés sont sauvegardés directement dans l'inventaire Roblox du joueur, ce qui permet aux joueurs de les équiper et de porter les avatars personnalisés dans d'autres expériences.

Les propriétaires d'expérience qui mettent en œuvre la création d'avatar en expérience bénéficient des commissions de marché en tant que créateur de l'article d'avatar et propriétaire de l'expérience. Si un actif créé en expérience est inspecté, l'article fournit un lien vers l'expérience originale dans laquelle il a été créé.

Vous pouvez tester la création en expérience dans la démonstration d'Avatar Creator de Roblox.

Comment mettre en œuvre la création en expérience

Utilisez les instructions et références de code suivantes pour créer votre premier projet de création d'avatar en expérience. Les instructions suivantes utilisent un corps de base Model que les joueurs peuvent modifier et personnaliser avant de publier.

Avant de commencer, familiarisez-vous avec ce qui suit :

  • Modèles d'avatar — La mise en œuvre suivante nécessite d'importer un corps de base qui respecte les spécifications de 15 pièces de Roblox. Ce Model sert de base pour la personnalisation et la modification supplémentaires par l'utilisateur.
  • Jetons de création d'avatar — Les expériences mettant en œuvre la création d'avatar nécessitent au moins un jeton de création. Ces jetons nécessitent des Robux pour être achetés et vous permettent de définir les prix et d'autres paramètres de vente pour les achats effectués en expérience.
  • Classes d'API
    • AvatarCreationService — Gère la demande de création d'avatar et la validation.
    • EditableImage — Gère la création et la manipulation des textures à l'exécution.
    • EditableMesh — Gère la manipulation de la géométrie de maillage à l'exécution.
    • WrapDeformer — Gère la manipulation à l'exécution de la géométrie invisible de la cage extérieure qui permet aux personnages d'avatar d'équiper des vêtements 3D.

Importer un corps de base

Le corps de base sert de fondation initiale que les utilisateurs peuvent personnaliser et modifier. Vous pouvez utiliser votre propre Model, ou importer un actif personnalisé avec l'Importateur et le configurer via Avatar Setup.

Les corps de base doivent respecter les spécifications d'avatar de Roblox et doivent inclure des composants tels que les 15 instances de MeshPart qui composent 6 parties du corps : tête, torse, bras gauche, jambe gauche, bras droit et jambe droite, ainsi que d'autres composants d'avatar.

Pour des références et des exemples de corps d'avatar correctement configurés, consultez Références d'avatar.

Mettre en œuvre les API d'édition

Pour développer un système où les utilisateurs peuvent modifier les instances MeshPart sur un avatar dans votre expérience pour la création, utilisez EditableImage pour l'édition de texture, EditableMesh pour l'édition de maillage et WrapDeformer pour maintenir les données de skinning et FACS pendant les modifications de maillage.

  1. Après avoir importé votre corps de base, utilisez le script suivant pour configurer vos EditableImages, EditableMeshes et WrapDeformers.

    local AssetService = game:GetService("AssetService")
    local function setupBodyPart(meshPart, wrapTarget)
    -- Créer et attacher un WrapDeformer au MeshPart
    local wrapDeformer = Instance.new("WrapDeformer")
    wrapDeformer.Parent = meshPart
    -- Créer un maillage éditable pour le maillage de la cage de la cible
    local cageEditableMesh: EditableMesh =
    AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {
    FixedSize = true,
    })
    -- Assigner le maillage de la cage au WrapDeformer
    wrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))
    end
    local function setupRigidMesh(meshPart)
    -- Créer un maillage éditable à partir du MeshPart d'origine
    local editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {
    FixedSize = true,
    })
    -- Générer un nouveau MeshPart à partir du maillage éditable
    local newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))
    -- Copier la taille, la position et la texture du MeshPart d'origine
    newMeshPart.Size = meshPart.Size
    newMeshPart.CFrame = meshPart.CFrame
    newMeshPart.TextureContent = meshPart.TextureContent
    -- Appliquer le nouveau MeshPart au d'origine
    meshPart:ApplyMesh(newMeshPart)
    end
    local function setupMeshTexture(meshPart, textureIdToEditableImageMap)
    -- Si EditableImage existe déjà pour cet TextureID, le réutiliser plutôt que d'en créer un nouveau
    if textureIdToEditableImageMap[meshPart.TextureID] then
    meshPart.TextureContent =
    Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])
    return
    end
    -- Créer une nouvelle EditableImage et l'appliquer comme contenu de texture
    local editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))
    textureIdToEditableImageMap[meshPart.TextureID] = editableImage
    meshPart.TextureContent = Content.fromObject(editableImage)
    end
    local function setupModel(model)
    -- Carte pour réutiliser des instances EditableImage par ID de texture
    local textureIdToEditableImageMap = {}
    for _, descendant in model:GetDescendants() do
    if not descendant:IsA("MeshPart") then
    continue
    end
    -- Configurer le MeshPart en fonction de la présence de WrapTarget
    -- Si WrapTarget est présent, ajouter une WrapDeformer enfant avec un EditableMesh
    -- Sinon, appliquer EditableMesh directement au MeshPart
    local wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")
    if wrapTarget then
    setupBodyPart(descendant, wrapTarget)
    else
    setupRigidMesh(descendant)
    end
    -- Configurer l'EditableImage pour le MeshPart
    setupMeshTexture(descendant, textureIdToEditableImageMap)
    end
    end
  2. Créez des outils EditableImage qui permettent aux joueurs de recolorer, dessiner ou ajouter des autocollants à votre corps de base. Vous pouvez tirer parti des API comme DrawImage(), DrawRectangle(), WritePixelsBuffer().

    • Pour des transformations avancées, DrawImageTransformed() vous permet de spécifier la position, la rotation et l'échelle lors du dessin d'une EditableImage sur une autre. De même, DrawImageProjected() fonctionne de manière similaire à DrawImage() mais projette correctement l'image dessinée si l'instance EditableImage est utilisée avec un MeshPart.

      local function recolorTexture(
      meshPart: MeshPart,
      color: Color3
      )
      local bodyPartTexture = AssetService:CreateEditableImageAsync(meshPart.TextureID)
      meshPart.TextureContent = Content.fromObject(bodyPartTexture)
      bodyPartTexture:DrawRectangle(
      Vector2.new(0, 0),
      bodyPartTexture.Size,
      color,
      0,
      Enum.ImageCombineType.Overwrite
      )
      end
      local function applySticker(
      meshPart: MeshPart,
      textureCoordinate: Vector2,
      stickerId: TextureId
      )
      local bodyPartTexture = AssetService:CreateEditableImageAsync(meshPart.TextureID)
      meshPart.TextureContent = Content.fromObject(bodyPartTexture)
      local stickerTexture = AssetService:CreateEditableImageAsync(stickerId)
      bodyPartTexture:DrawImage(textureCoordinate, stickerTexture, Enum.ImageCombineType.BlendSourceOver)
      end
      local function applyStickerProjected(
      meshPart: MeshPart,
      targetMesh: EditableMesh,
      stickerId: TextureId,
      raycastHitPos: Vector3
      )
      local bodyPartTexture = AssetService:CreateEditableImageAsync(meshPart.TextureID)
      local relativePos = meshPart.CFrame:PointToWorldSpace(raycastHitPos)
      local direction = (workspace.CurrentCamera.CFrame.Position - relativePos).Unit
      local projectionParams: ProjectionParams = {
      Direction = meshPart.CFrame:VectorToObjectSpace(direction),
      Position = meshPart.CFrame:PointToObjectSpace(relativePos),
      Size = Vector3.new(1, 1, 1),
      Up = meshPart.CFrame:VectorToObjectSpace(Vector3.new(0, 1, 0)),
      }
      local stickerTexture = AssetService:CreateEditableImageAsync(stickerId)
      local localBrushConfig: BrushConfig = {
      Decal = stickerTexture,
      ColorBlendType = Enum.ImageCombineType.BlendSourceOver,
      AlphaBlendType = Enum.ImageAlphaType.Default,
      BlendIntensity = 1,
      FadeAngle = 90.0
      }
      bodyPartTexture:DrawImageProjected(targetMesh, projectionParams, localBrushConfig)
      end
  3. À l'aide de WrapDeformer et EditableMesh, créez des outils pour éditer les déformations de maillage sur votre corps.

    1. WrapDeformer gère les déformations en direct de la géométrie de MeshPart rendue tout en maintenant les données de skinning et FACS sous-jacentes.

    2. EditableMesh vous permet de modifier le maillage de cage auquel WrapDeformer répond.

      1. Utilisez WrapDeformer:SetCageMeshContent() pour appliquer l'instance EditableMesh qui représente le maillage de cage pertinent au WrapDeformer.
      2. Utilisez EditableMesh, comme SetPosition(), pour déformer les vertices et modifier la forme du MeshPart.
      local function deformBodyPart(
      meshPart: MeshPart,
      controlPointCenter: Vector3,
      controlPointRadius: number,
      controlPointDeformation: Vector3
      )
      local wrapTarget = meshPart:FindFirstChildWhichIsA("WrapTarget")
      local cageMeshId = wrapTarget.CageMeshId
      local wrapDeformer = Instance.new("WrapDeformer")
      wrapDeformer.Parent = meshPart
      local cageEditableMesh = AssetService:CreateEditableMeshAsync(cageMeshId)
      local verticesWithinSphere =
      cageEditableMesh:FindVerticesWithinSphere(controlPointCenter, controlPointRadius)
      for _, vertexId in verticesWithinSphere do
      local vertexPosition = cageEditableMesh:GetPosition(vertexId)
      cageEditableMesh:SetPosition(vertexId, vertexPosition + controlPointDeformation)
      end
      wrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))
      end

Créer une invite de création

Après avoir configuré votre corps de base et les API d'édition, créez une invite pour les utilisateurs afin de créer et d'acheter depuis l'expérience en utilisant AvatarCreationService:PromptCreateAvatarAsync().

export type BodyPartInfo = {
bodyPart: Enum.BodyPart,
instance: Instance --Dossier avec les MeshParts créés
}
export type BodyPartList = {BodyPartInfo}
local function publishAvatar(bodyPartInstances: BodyPartList, player: Player, tokenId: string)
local humanoidDescription = Instance.new("HumanoidDescription")
for _, bodyPartInfo in bodyPartInstances do
local bodyPartDescription = Instance.new("BodyPartDescription")
bodyPartDescription.Instance = bodyPartInfo.instance
bodyPartDescription.BodyPart = bodyPartInfo.bodyPart
bodyPartDescription.Parent = humanoidDescription
end
local success, result, bundleIdOrErrorMessage, outfitId = pcall(function()
return AvatarCreationService:PromptCreateAvatarAsync(tokenId, player, humanoidDescription)
end)
if success then
if result == Enum.PromptCreateAvatarResult.Success then
print("Téléchargement réussi avec BundleId : ", bundleIdOrErrorMessage)
print("Téléchargement réussi avec OutfitId : ", outfitId)
else
print("Téléchargement échoué avec le message d'erreur :", bundleIdOrErrorMessage)
end
else
print("Création d'avatar échouée")
end
end

AvatarCreationService:PromptCreateAvatarAsync() prend un paramètre HumanoidDescription pour représenter l'avatar destiné à l'achat ou à la création. Pour la création d'avatar, la HumanoidDescription du personnage doit inclure de nouveaux actifs à créer pour chacune des 6 parties du corps (Head, Torso, RightLeg, LeftLeg, RightArm, LeftArm). En option, elle peut également inclure un nouvel accessoire de type Hair.

Pour supporter cela, la HumanoidDescription doit inclure 6 enfants BodyPartDescription. Chaque propriété BodyPartDescription.Instance fait référence à un Folder qui contient toutes les instances de MeshPart qui composent la partie du corps. Par exemple, le dossier LeftArm contient LeftHand, LeftUpperArm et LeftLowerArm MeshParts. La propriété BodyPartDescription.BodyPart doit également être définie sur le Enum.BodyPart pertinent.

Chacune des 15 parties du corps MeshPart doit inclure :

La HumanoidDescription fournie ne doit pas inclure d'ID d'actifs préexistants pour représenter les parties du corps ou les accessoires sur la création prévue. En revanche, la HumanoidDescription peut inclure les échelles humanoïdes de BodyTypeScale, HeadScale, HeightScale, WidthScale, et ProportionScale. Faites attention aux échelles avec lesquelles un corps de base est importé afin qu'elles correspondent aux échelles fournies à la HumanoidDescription.

Inclure des accessoires

Si vous incluez un accessoire, tel que des cheveux, la HumanoidDescription doit inclure un enfant AccessoryDescription où :

Générer un jeton de création d'avatar

AvatarCreationService:PromptCreateAvatarAsync() prend un paramètre ID de jeton de création d'avatar. Ce jeton est la clé pour les créations de votre univers, et il est ce que vous pouvez utiliser pour définir le prix de création d'avatar depuis votre expérience. Pour des instructions et des détails supplémentaires sur la génération de jetons, consultez Jetons de création d'avatar.

Après avoir acheté et généré votre jeton, vous pouvez inspecter le jeton dans le Creator Hub pour trouver l'ID que vous pouvez ensuite utiliser pour le AvatarCreationService:PromptCreateAvatarAsync() API.

Répondre aux joueurs qui rejoignent par attribution

Les paquets d'avatar créés en expérience incluent un lien d'attribution vers l'expérience originale où l'avatar a été créé. Si l'avatar est inspecté par un autre joueur, une invite s'affiche offrant une option de visiter l'expérience où l'avatar a été créé.

Pour gérer les joueurs rejoignant votre expérience en utilisant ce lien d'attribution, utilisez Player:GetJoinData() et analysez la table renvoyée pour GameJoinContext.

GameJoinContext inclut les valeurs de table suivantes :

©2026 Société Roblox. Roblox, le logo Roblox et Powering Imagination font partie de nos marques déposées aux États-Unis et dans d'autres pays.