Crea {itemType}
Monetizzazione
Politiche e linee guida

Creazione_avatar_in-esperienza

*Questo contenuto è tradotto usando AI (Beta) e potrebbe contenere errori. Per visualizzare questa pagina in inglese, clicca qui.

Puoi pubblicare un'esperienza che consente ai giocatori di creare, personalizzare e acquistare corpi di avatar in tempo reale. Una volta acquistati, questi corpi personalizzati vengono salvati direttamente nell'inventario di Roblox del giocatore, consentendo ai giocatori di equipaggiare e indossare gli avatar personalizzati in altre esperienze.

I proprietari di esperienze che implementano la creazione di avatar in esperienza beneficiano delle commissioni del mercato sia come creatori dell'oggetto avatar che come proprietari dell'esperienza. Se un oggetto creato in esperienza viene ispezionato, questo fornisce un link all'esperienza originale in cui è stato creato.

Puoi testare la creazione in esperienza nella demo dell'Avatar Creator di Roblox.

Come implementare la creazione in esperienza

Utilizza le seguenti istruzioni e riferimenti di codice per creare il tuo primo progetto di creazione avatar in esperienza. Le seguenti istruzioni utilizzano un corpo di base Model che i giocatori possono modificare e personalizzare prima della pubblicazione.

Prima di iniziare, familiarizzati con quanto segue:

  • Modelli di avatar — L'implementazione seguente richiede di importare un corpo di base che soddisfi le specifiche di 15 parti di Roblox. Questo Model funge da base per ulteriori personalizzazioni e modifiche degli utenti.
  • Token di creazione avatar — Le esperienze che implementano la creazione di avatar richiedono almeno un token di creazione. Questi token richiedono Robux per essere acquistati e ti consentono di impostare prezzi e altre impostazioni di vendita per gli acquisti effettuati in esperienza.
  • Classi API
    • AvatarCreationService — Gestisce la richiesta di creazione avatar e la validazione.
    • EditableImage — Gestisce la creazione e la manipolazione delle texture a runtime.
    • EditableMesh — Gestisce la manipolazione della geometria della mesh a runtime.
    • WrapDeformer — Gestisce la manipolazione della geometria della gabbia invisibile esterna che consente ai personaggi avatar di equipaggiare abbigliamento 3D.

Importa un corpo di base

Il corpo di base funge da fondazione iniziale che gli utenti possono personalizzare e modificare. Puoi utilizzare il tuo Model o importare un asset personalizzato con l'Importatore e configurarlo tramite la Configurazione Avatar.

I corpi di base devono aderire alle specifiche per avatar di Roblox e devono includere componenti come le 15 istanze MeshPart che compongono 6 parti del corpo: testa, torso, braccio sinistro, gamba sinistra, braccio destro e gamba destra, oltre ad altri componenti dell'avatar.

Per riferimenti e campioni di corpi avatar configurati correttamente, vedere Riferimenti avatar.

Implementa le API di editing

Per sviluppare un sistema in cui gli utenti possono modificare le istanze MeshPart su un avatar nella tua esperienza per la creazione, utilizza EditableImage per la modifica delle texture, EditableMesh per la modifica della mesh e WrapDeformer per mantenere i dati di skinning e FACS durante le modifiche alla mesh.

  1. Dopo aver importato il tuo corpo di base, utilizza il seguente script per impostare i tuoi EditableImages, EditableMeshes e WrapDeformers.


    local AssetService = game:GetService("AssetService")
    local function setupBodyPart(meshPart, wrapTarget)
    -- Crea e allega un WrapDeformer al MeshPart
    local wrapDeformer = Instance.new("WrapDeformer")
    wrapDeformer.Parent = meshPart
    -- Crea una mesh modificabile per la mesh gabbia del target di avvolgimento
    local cageEditableMesh: EditableMesh =
    AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {
    FixedSize = true,
    })
    -- Assegna la mesh gabbia al WrapDeformer
    wrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))
    end
    local function setupRigidMesh(meshPart)
    -- Crea una mesh modificabile dall'originale MeshPart
    local editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {
    FixedSize = true,
    })
    -- Genera un nuovo MeshPart dalla mesh modificabile
    local newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))
    -- Copia dimensione, posizione e texture dall'originale MeshPart
    newMeshPart.Size = meshPart.Size
    newMeshPart.CFrame = meshPart.CFrame
    newMeshPart.TextureContent = meshPart.TextureContent
    -- Applica il nuovo MeshPart all'originale
    meshPart:ApplyMesh(newMeshPart)
    end
    local function setupMeshTexture(meshPart, textureIdToEditableImageMap)
    -- Se esiste già un EditableImage per questo TextureID, riutilizzalo piuttosto che crearne uno nuovo
    if textureIdToEditableImageMap[meshPart.TextureID] then
    meshPart.TextureContent =
    Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])
    return
    end
    -- Crea un nuovo EditableImage e applicalo come contenuto della texture
    local editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))
    textureIdToEditableImageMap[meshPart.TextureID] = editableImage
    meshPart.TextureContent = Content.fromObject(editableImage)
    end
    local function setupModel(model)
    -- Mappa per riutilizzare le istanze EditableImage per ID texture
    local textureIdToEditableImageMap = {}
    for _, descendant in model:GetDescendants() do
    if not descendant:IsA("MeshPart") then
    continue
    end
    -- Configura il MeshPart in base alla presenza del WrapTarget
    -- Se è presente WrapTarget, aggiungi un figlio WrapDeformer con un EditableMesh
    -- Altrimenti, applica EditableMesh direttamente al MeshPart
    local wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")
    if wrapTarget then
    setupBodyPart(descendant, wrapTarget)
    else
    setupRigidMesh(descendant)
    end
    -- Configura l'EditableImage per il MeshPart
    setupMeshTexture(descendant, textureIdToEditableImageMap)
    end
    end
  2. Crea strumenti EditableImage che consentano ai giocatori di ricolorare, disegnare o aggiungere adesivi al tuo corpo di base. Puoi sfruttare le API come DrawImage(), DrawRectangle(), WritePixelsBuffer().

    • Per trasformazioni avanzate, DrawImageTransformed() consente di specificare posizione, rotazione e scala quando si disegna un EditableImage su un altro. Allo stesso modo, DrawImageProjected() funziona molto come DrawImage(), ma proietta correttamente l'immagine disegnata se l'istanza EditableImage è utilizzata con 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. Utilizzando WrapDeformer e EditableMesh, crea strumenti per modificare le deformazioni della mesh sul tuo corpo.

    1. WrapDeformer gestisce le deformazioni in tempo reale della geometria del MeshPart renderizzato mantenendo i dati di skinning e FACS sottostanti.

    2. EditableMesh ti consente di modificare la mesh gabbia a cui il WrapDeformer risponde.

      1. Usa WrapDeformer:SetCageMeshContent() per applicare l'istanza EditableMesh che rappresenta la mesh gabbia pertinente al WrapDeformer.
      2. Usa EditableMesh, come SetPosition(), per deformare i vertici e modificare la forma del 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

Crea un prompt di creazione

Dopo aver impostato il tuo corpo di base e le API di editing, crea un prompt per consentire agli utenti di creare e acquistare dall'esperienza utilizzando AvatarCreationService:PromptCreateAvatarAsync().


export type BodyPartInfo = {
bodyPart: Enum.BodyPart,
instance: Instance --Cartella con MeshParts Creati
}
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("Caricamento avvenuto con successo con BundleId: ", bundleIdOrErrorMessage)
print("Caricamento avvenuto con successo con OutfitId: ", outfitId)
else
print("Caricamento non avvenuto con messaggio di errore:", bundleIdOrErrorMessage)
end
else
print("Creazione avatar non riuscita")
end
end

AvatarCreationService:PromptCreateAvatarAsync() accetta un parametro HumanoidDescription per rappresentare l'avatar destinato all'acquisto o alla creazione. Per la creazione avatar, il HumanoidDescription del personaggio deve includere nuovi asset da creare per ciascuna delle 6 parti del corpo (Head, Torso, RightLeg, LeftLeg, RightArm, LeftArm). Facoltativamente, può anche includere un accessorio nuovo di Hair.

Per supportare questo, il HumanoidDescription dovrebbe includere 6 figli di BodyPartDescription. Ogni proprietà BodyPartDescription.Instance fa riferimento a una Folder che include tutte le istanze di MeshPart che compongono la parte del corpo. Ad esempio, la cartella LeftArm contiene LeftHand, LeftUpperArm e LeftLowerArm MeshParts. La proprietà BodyPartDescription.BodyPart dovrebbe anche essere impostata sul relevante Enum.BodyPart.

Ognuna delle 15 parti del corpo MeshPart deve includere:

Il HumanoidDescription fornito non dovrebbe includere alcun ID asset preesistente per rappresentare le parti del corpo o gli accessori sulla creazione prevista. D'altra parte, il HumanoidDescription può includere le scale umanoidi di BodyTypeScale, HeadScale, HeightScale, WidthScale, e ProportionScale. Fai attenzione alle scale con cui è importato un corpo di base affinché corrispondano alle scale fornite al HumanoidDescription.

Includi accessori

Se includi un accessorio, come i capelli, il HumanoidDescription dovrebbe includere un figlio AccessoryDescription in cui:

Genera un token di creazione avatar

AvatarCreationService:PromptCreateAvatarAsync() accetta un parametro ID Token di Creazione Avatar. Questo token è la chiave per le creazioni dal tuo universo ed è quello che puoi usare per impostare il prezzo della creazione dell'avatar dalla tua esperienza. Per istruzioni e dettagli aggiuntivi sulla generazione dei token, vedi Token di Creazione Avatar.

Dopo aver acquistato e generato il tuo token, puoi ispezionare il token nel Creator Hub per trovare l'ID che puoi poi utilizzare per il API AvatarCreationService:PromptCreateAvatarAsync().

Rispondi ai giocatori che si uniscono tramite attribuzione

I pacchetti avatar creati in esperienza includono un link di attribuzione all'esperienza originale in cui l'avatar è stato creato. Se l'avatar viene ispezionato da un altro giocatore, viene visualizzato un prompt che fornisce la possibilità di visitare l'esperienza in cui è stato creato l'avatar.

Per gestire i giocatori che si uniscono alla tua esperienza utilizzando questo link di attribuzione, utilizza Player:GetJoinData() e analizza la tabella restituita per GameJoinContext.

GameJoinContext include i seguenti valori della tabella:

© 2026 Roblox Corporation. Roblox, il logo Roblox e Powering Imagination sono tra i nostri marchi registrati e non registrati negli Stati Uniti. e altri paesi.