Creazionidell'avatar nell'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.Quando acquistato, questi corpi personalizzati vengono salvati direttamente nell'Inventario, reportorioRoblox del Giocatore, consentendo ai giocatori di equipaggiare e indossare gli avatar personalizzati in altre esperienze.

I proprietari di esperienza che implementano la creazione di avatar nell'esperienza beneficiano di commissioni di mercato sia come creatore dell'oggetto avatar che come proprietario dell'esperienza .Se un'asset creata in-experience viene ispezionata, l'elemento fornisce un link all'esperienza originale in cui è stata creata.

Puoi testare la creazione in-experience nella demo di Creatore di Avatar di Roblox.

Come implementare la Creazioniin-experience

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

Prima di iniziare, familiarizzare con quanto Seguendo:

  • Modelli di avatar — La seguente implementazione richiede l'importazione di un corpo base che soddisfi le specifiche di 15 parti di Roblox.Questo Model serve come base per la personalizzazione e la modifica aggiuntiva dell'utente.
    • Il corpo base deve soddisfare le linee guida per il corpo dell'Avatar di Roblox, incluso il numero minimo di controllo FACS per il rigging facciale.
  • Token di creazione dell'avatar — Le esperienze che implementano la creazione dell'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 creazione dell'avatar e la richiesta di convalida.
    • EditableImage — Gestisce la creazione e la manipolazione del runtime delle texture.
    • EditableMesh — Gestisce la manipolazione del runtime della geometria mesh.
    • WrapDeformer — Gestisce la manipolazione del runtime della geometria della gabbia invisibile esterna che consente ai personaggi dell'avatar di equipaggiare abbigliamento 3D .

Importa un corpo base

Il corpo base funge da fondazione iniziale che gli utenti possono personalizzare e Modificare.Puoi usare il tuo proprio Model , o importare una risorsa personalizzata con il Importer 3-D e configurarla attraverso Avatar Setup .

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

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

Implementa le API di modifica

Per sviluppare un sistema in cui gli utenti possono modificare le istanze MeshPart su un avatar nella tua esperienza per la Creazioni, usa EditableImage per l'editing della texture, EditableMesh per l'editing del mesh e WrapDeformer per mantenere i dati di skinning e FACS durante l'editing del mesh.

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


    local AssetService = game:GetService("AssetService")
    local function setupBodyPart(meshPart, wrapTarget)
    -- Crea e allega un WrapDeformer alla MeshPart
    local wrapDeformer = Instance.new("WrapDeformer")
    wrapDeformer.Parent = meshPart
    -- Crea una mesh modificabile per la Mesh, magliadella gabbia del bersaglio avvolgente
    local cageEditableMesh: EditableMesh =
    AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {
    FixedSize = true,
    })
    -- Assegnare la grata della 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 una nuova MeshPart dalla Mesh, magliamodificabile
    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 la nuova MeshPart al originale
    meshPart:ApplyMesh(newMeshPart)
    end
    local function setupMeshTexture(meshPart, textureIdToEditableImageMap)
    -- Se EditableImage esiste già per questo TextureID, riutilizzarlo piuttosto che crearne uno nuovo
    if textureIdToEditableImageMap[meshPart.TextureID] then
    meshPart.TextureContent =
    Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])
    return
    end
    -- Crea una nuova immagine modificabile e applicala 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 di EditableImage con l'ID della texture
    local textureIdToEditableImageMap = {}
    for _, descendant in model:GetDescendants() do
    if not descendant:IsA("MeshPart") then
    continue
    end
    -- Configura MeshPart in base alla presenza di WrapTarget
    -- Se WrapTarget è presente, aggiungi un figlio WrapDeformer con un EditableMesh
    -- Altrimenti, applica EditableMesh alla MeshPart direttamente
    local wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")
    if wrapTarget then
    setupBodyPart(descendant, wrapTarget)
    else
    setupRigidMesh(descendant)
    end
    -- Configura l'immagine modificabile per la parte mesh
    setupMeshTexture(descendant, textureIdToEditableImageMap)
    end
    end
  2. Crea EditableImage strumenti che consentono ai giocatori di ricolorare, disegnare o aggiungere adesivi al tuo corpo base.Puoi sfruttare le API in like DrawImage() , DrawRectangle() , WritePixelsBuffer() .

    • Per le trasformazioni avanzate, DrawImageTransformed() ti consente di specificare posizione, rotazione e scala quando disegni un'immagine modificabile su un'altra.Allo stesso modo, DrawImageProjected() lavora molto come DrawImage() ma proietta l'immagine disegnata correttamente se l'istanza EditableImage viene 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 = (game.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. Usando WrapDeformer e EditableMesh, crea strumenti per modificare le deformazioni della mesh sul tuo corpo.

    1. WrapDeformer gestisce le deformazioni dal vivo della geometria renderta MeshPart mantenendo i dati di skinning e FACS sottostanti.

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

      1. Usa WrapDeformer:SetCageMeshContent() per applicare l'istanza EditableMesh che rappresenta la grata pertinente alla 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 prompt di creazione

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


export type BodyPartInfo = {
bodyPart: Enum.BodyPart,
instance: Instance --Cartella con parti mesh create
}
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("Successfully uploaded with BundleId: ", bundleIdOrErrorMessage)
print("Successfully uploaded with OutfitId: ", outfitId)
else
print("Unsuccessfully uploaded with error message:", bundleIdOrErrorMessage)
end
else
print("Avatar creation unsuccessful")
end
end

AvatarCreationService:PromptCreateAvatarAsync() prende un parametro HumanoidDescription per rappresentare l'avatar destinato all'acquisto o alla Creazioni.Per la Creazionidell'avatar, il personaggio di HumanoidDescription deve includere nuove risorse da creare per ciascuna delle 6 parti del corpo ( Head , Torso , RightLeg , LeftLeg , RightArm , LeftArm ).Opzionalmente, può anche includere un nuovo Hair Accessorio.

Per supportarlo, il HumanoidDescription dovrebbe includere 6 BodyPartDescription bambini.Ogni proprietà fa riferimento a una che include tutte le istanze che compongono la parte del corpo.Ad esempio, la cartella LeftArm contiene LeftHand , LeftUpperArm , e LeftLowerArm``Class.MeshPart|MeshParts .La proprietà BodyPartDescription.BodyPart dovrebbe anche essere impostata sul pertinente Enum.BodyPart.

Ognuna delle 15 parti del corpo MeshPart deve includere:

Il fornito HumanoidDescription non dovrebbe includere alcun ID risorsa preesistente per rappresentare parti del corpo o accessori nella Creazioniprevista.D'altra parte, il HumanoidDescription può includere le scale umanoidi di BodyTypeScale , HeadScale , HeightScale , WidthScale , e ProportionScale .Tieni presente le scale con cui un corpo base viene importato in modo che corrispondano alle scale fornite al HumanoidDescription .

Includi accessori

Se includi un Accessorio, come i capelli, il HumanoidDescription dovrebbe includere un figlio AccessoryDescription dove:

Genera un token di creazione dell'avatar

AvatarCreationService:PromptCreateAvatarAsync() richiede un parametro ID di creazione dell'Avatar .Questo token è la chiave per le creazioni del tuo universo, e è ciò che puoi usare per impostare il prezzo della creazione dell'avatar dalla tua esperienza.Per le istruzioni e i dettagli aggiuntivi sulla generazione di token, vedi Gettoni di creazione dell'Avatar.

Dopo l'acquisto e la generazione del tuo token, puoi ispezionare il token nel Creator Hub per trovare l'ID che puoi quindi utilizzare per l'AvatarCreationService:PromptCreateAvatarAsync().

Rispondi ai giocatori che si uniscono per attribuzione

I pacchetti di avatar creati in-experience includono un link di attribuzione all'esperienza originale in cui è stato creato l'avatar.Se l'avatar viene ispezionato da un altro Giocatore, viene visualizzata una richiesta che fornisce un'opzione per visitare l'esperienza in cui l'avatar è stato creato.

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

GameJoinContext include i seguenti valori della tabella: