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 consenta ai giocatori di creare, personalizzare e acquistare corpi avatar in tempo reale. Quando vengono acquistati, questi corpi personalizzati vengono salvati direttamente nell'inventario Roblox del giocatore, consentendo ai giocatori di equipaggiare e indossare gli avatar personalizzati in altre esperienze.

I proprietari dell'esperienza che implementano la creazione di avatar in esperienza beneficiano delle commissioni di mercato sia come creatore dell'oggetto avatar che come proprietario dell'esperienza. Se un asset creato nell'esperienza viene ispezionato, l'oggetto fornisce un collegamento all'esperienza originale in cui è stato creato.

Puoi testare la creazione in esperienza nella demo 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 base Model che i giocatori possono modificare e personalizzare prima della pubblicazione.

Prima di iniziare, familiarizza con i seguenti aspetti:

  • Modelli avatar — La seguente implementazione richiede l'importazione di un corpo base che soddisfi le specifiche di 15 parti di Roblox. Questo Model funge da base per ulteriore personalizzazione e modifica da parte degli utenti.
    • Il corpo base deve soddisfare le linee guida sui corpi avatar di Roblox, inclusi il numero minimo di controlli FACS per il rigging facciale.
  • Token di creazione avatar — Le esperienze che implementano la creazione avatar richiedono almeno un token di creazione. Questi token richiedono Robux per l'acquisto e ti consentono di impostare prezzi e altre impostazioni di vendita per gli acquisti effettuati nell'esperienza.
  • Classi API
    • AvatarCreationService — Gestisce la richiesta di creazione avatar e la validazione.
    • EditableImage — Gestisce la creazione e la manipolazione runtime delle texture.
    • EditableMesh — Gestisce la manipolazione runtime della geometria dei mesh.
    • WrapDeformer — Gestisce la manipolazione runtime della geometria della gabbia esterna invisibile che consente ai personaggi avatar di equipaggiare abbigliamento 3D.

Importare un corpo base

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

I corpi base devono rispettare le specifiche dell'avatar di Roblox e devono includere componenti come le 15 istanze di MeshPart che compongono 6 parti del corpo: testa, torso, braccio sinistro, gamba sinistra, braccio destro e gamba destra, così come altre componenti avatar.

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

Implementare le API di modifica

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

  1. Dopo aver importato il tuo corpo base, utilizza il seguente script per configurare il tuo EditableImages, EditableMeshes e WrapDeformers.

    local AssetService = game:GetService("AssetService")
    local function setupBodyPart(meshPart, wrapTarget)
    -- Crea e attacca un WrapDeformer al MeshPart
    local wrapDeformer = Instance.new("WrapDeformer")
    wrapDeformer.Parent = meshPart
    -- Crea un mesh modificabile per il mesh della gabbia del target di avvolgimento
    local cageEditableMesh: EditableMesh =
    AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {
    FixedSize = true,
    })
    -- Assegna il mesh della gabbia al WrapDeformer
    wrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))
    end
    local function setupRigidMesh(meshPart)
    -- Crea un mesh modificabile dall'originale MeshPart
    local editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {
    FixedSize = true,
    })
    -- Genera un nuovo MeshPart dal mesh modificabile
    local newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))
    -- Copia dimensioni, 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 EditableImage esiste già 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 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 istanze di 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 di WrapTarget
    -- Se WrapTarget è presente, 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 cambiare colore, disegnare o aggiungere adesivi al tuo corpo base. Puoi sfruttare le API come DrawImage(), DrawRectangle(), WritePixelsBuffer().

    • Per trasformazioni avanzate, DrawImageTransformed() ti consente di specificare posizione, rotazione e scala quando disegni un EditableImage su un altro. Analogamente, DrawImageProjected() funziona molto simile a 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 del mesh sul tuo corpo.

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

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

      1. Usa WrapDeformer:SetCageMeshContent() per applicare l'istanza EditableMesh che rappresenta il mesh della 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

Creare il prompt di creazione

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

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

AvatarCreationService:PromptCreateAvatarAsync() prende un parametro HumanoidDescription per rappresentare l'avatar destinato all'acquisto o alla creazione. Per la creazione dell'avatar, la 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 nuovo accessorio Hair.

Per supportare ciò, la HumanoidDescription dovrebbe includere 6 bambini 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 sulla relativa Enum.BodyPart.

Ciascuna delle 15 parti del corpo MeshPart deve includere:

La HumanoidDescription fornita non dovrebbe includere alcun ID di asset preesistenti per rappresentare le parti del corpo o gli accessori sulla creazione destinata. D'altra parte, la HumanoidDescription può includere le scale umane di BodyTypeScale, HeadScale, HeightScale, WidthScale, e ProportionScale. Fai attenzione alle scale con cui un corpo base è importato affinché corrispondano alle scale fornite alla HumanoidDescription.

Includere accessori

Se stai includendo un accessorio, come capelli, la HumanoidDescription dovrebbe includere una descrizione di accessorio figlio AccessoryDescription dove:

Generare un token di creazione avatar

AvatarCreationService:PromptCreateAvatarAsync() prende un parametro ID Token di Creazione Avatar. Questo token è la chiave per le creazioni dal tuo universo e può essere utilizzato per impostare il prezzo della creazione di avatar dalla tua esperienza. Per istruzioni e dettagli aggiuntivi sulla generazione di token, consulta 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 quindi utilizzare per l'API AvatarCreationService:PromptCreateAvatarAsync().

Rispondere all'ingresso dei giocatori tramite attribuzione

I pacchetti avatar creati in esperienza includono un collegamento di attribuzione all'esperienza originale in cui è stato creato l'avatar. Se l'avatar viene ispezionato da un altro giocatore, viene visualizzato un prompt che offre un'opzione per visitare l'esperienza in cui è stato creato l'avatar.

Per gestire l'ingresso dei giocatori nella tua esperienza utilizzando questo collegamento di attribuzione, utilizza Player:GetJoinData() e analizza la tabella restituita per GameJoinContext.

GameJoinContext include i seguenti valori di 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.