Avatar-Erstellung in Schöpfung

*Dieser Inhalt wurde mit KI (Beta) übersetzt und kann Fehler enthalten. Um diese Seite auf Englisch zu sehen, klicke hier.

Du kannst ein Erlebnis veröffentlichen, das es Spielern ermöglicht, Avatar-Körper in Echtzeit zu erstellen, gestalten/anpassenund zu kaufen.Wenn sie gekauft werden, werden diese benutzerdefinierten Körper direkt in das Roblox-Inventar des Spieler:ingespeichert, so dass Spieler die benutzerdefinierten Avatare in anderen Erlebnissen ausrüsten und tragen können.

Erfahrungsbesitzer, die In-Experience-Avatarerstellung implementieren, profitieren von Marktplatzgebühren sowohl als Ersteller des Avatarartikels als auch als Erfahrungsbesitzer .Wenn ein Asset, das in der Erfahrung erstellt wurde, inspiziert wird, bietet der Artikel einen Link zur ursprünglichen Erfahrung, die es erstellt wurde.

Du kannst die Erstellungserfahrung in der Demo von Roblox' Avatar-Creator testen.

Wie Schöpfungimplementiert wird

Verwende die folgenden Anweisungen und Code-Referenzen, um dein erstes Erlebnis-Avatar-Schaffungsprojekt zu erstellen.Die folgenden Anweisungen verwenden einen Basiskörper Model, den Spieler vor der Veröffentlichung modifizieren und anpassen können.

Bevor du loslegst, vertraut dich mit dem gefolgte Profilean:

  • Avatar-Modelle — Die folgende Implementierung erfordert das Importieren eines Basiskörpers, der Roblox' 15 Teilspezifikationen erfüllt.Diese Model dient als Basis für zusätzliche Benutzeranpassung und Änderung.
    • Der Basiskörper muss die Richtlinien für Avatarkörper von Roblox erfüllen, einschließlich der Mindestanzahl von FACS-Steuerelementen für Rigging.
  • Avatar-Erstellungs-Token — Erlebnisse, die die Erstellung eines Avatars implementieren, benötigen mindestens ein Erstellungs-Token.Diese Token erfordern Robux zum Kauf und ermöglichen es dir, Preise und andere Verkaufsoptionen für Einkäufe im Erlebnis festzulegen.
  • API-Klassen

Importiere einen Körper

Der Basiskörper fungiert als anfängliche Grundlage, die Benutzer anpassen und bearbeiten können.Du kannst dein eigenes Model verwenden oder ein benutzerdefiniertes Asset mit dem 3D-Importeur importieren und über Avatar-Einstellungen einrichten.

Basis-Körper müssen sich an die Avatar-Spezifikationen von Roblox halten und müssen Komponenten wie die 15 MeshPart Instanzen enthalten, die 6 Körperteile ausmachen: Kopf, Torso, linker Arm, linkes Bein, rechter Arm und rechtes Bein, sowie andere Avatar-Komponenten.

Für Referenzen und Beispiele richtig konfigurierter Avatar-Körper siehe Avatar-Referenzen.

Implementiere Bearbeitungs-APIs

Um ein System zu entwickeln, in dem Benutzer die MeshPart Instanzen auf einem Avatar in deiner Erfahrung zum Schöpfungbearbeiten können, verwende EditableImage für die Texturbearbeitung, EditableMesh für die Netzwerkbearbeitung und WrapDeformer für die Aufrechterhaltung von Skinning- und FACS-Daten während der Netzwerkbearbeitung.

  1. Nach dem Import deines Körperverwende das folgende Skript, um deine EditableImages, EditableMeshes und WrapDeformers einzurichten.


    local AssetService = game:GetService("AssetService")
    local function setupBodyPart(meshPart, wrapTarget)
    -- Erstelle und füge einen WrapDeformer dem MeshPart hinzu
    local wrapDeformer = Instance.new("WrapDeformer")
    wrapDeformer.Parent = meshPart
    -- Erstellen Sie ein bearbeitbares Mesh für das Käfignetz des Umfassungsziels
    local cageEditableMesh: EditableMesh =
    AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {
    FixedSize = true,
    })
    -- Weisen Sie das Käfignetz dem WrapDeformer zu
    wrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))
    end
    local function setupRigidMesh(meshPart)
    -- Erstelle ein bearbeitbares Mesh aus dem ursprünglichen MeshPart
    local editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {
    FixedSize = true,
    })
    -- Erstelle ein neues MeshPart aus dem bearbeitbaren Mesh
    local newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))
    -- Kopiere Größe, Position und Textur vom ursprünglichen MeshPart
    newMeshPart.Size = meshPart.Size
    newMeshPart.CFrame = meshPart.CFrame
    newMeshPart.TextureContent = meshPart.TextureContent
    -- Wenden Sie das neue MeshPart zurück auf das Original an
    meshPart:ApplyMesh(newMeshPart)
    end
    local function setupMeshTexture(meshPart, textureIdToEditableImageMap)
    -- Wenn EditableImage bereits für diese Textur-ID existiert, verwende es erneut, anstatt eine neue zu erstellen
    if textureIdToEditableImageMap[meshPart.TextureID] then
    meshPart.TextureContent =
    Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])
    return
    end
    -- Erstellen Sie ein neues bearbeitbares Bild und wenden Sie es als Texturinhalt an
    local editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))
    textureIdToEditableImageMap[meshPart.TextureID] = editableImage
    meshPart.TextureContent = Content.fromObject(editableImage)
    end
    local function setupModel(model)
    -- Karte für die Wiederverwendung von bearbeitbaren Bildinstanzen durch Textur-ID
    local textureIdToEditableImageMap = {}
    for _, descendant in model:GetDescendants() do
    if not descendant:IsA("MeshPart") then
    continue
    end
    -- Konfiguriere MeshPart basierend auf der Präsenz von WrapTarget
    -- Wenn WrapTarget vorhanden ist, füge ein WrapDeformer-Kind mit einer bearbeitbaren Mesh hinzu
    -- Ansonsten, wenden Sie EditableMesh direkt auf das MeshPart an
    local wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")
    if wrapTarget then
    setupBodyPart(descendant, wrapTarget)
    else
    setupRigidMesh(descendant)
    end
    -- Konfigurieren Sie das bearbeitbare Bild für das MeshPart
    setupMeshTexture(descendant, textureIdToEditableImageMap)
    end
    end
  2. Erstelle EditableImage Werkzeuge, mit denen Spieler deinen Körperneu färben, zeichnen oder Sticker hinzufügen können.Du kannst APIs wie DrawImage(), DrawRectangle(), WritePixelsBuffer() nutzen.

    • Für erweiterte Transformationen ermöglicht DrawImageTransformed() es dir, Position, Drehung und Skalierung anzugeben, wenn du ein bearbeitbares Bild auf ein anderes zeichnest.Ebenso funktioniert DrawImageProjected() sehr ähnlich wie DrawImage(), projiziert aber das gezeichnete Bild richtig, wenn die EditableImage Instanz mit einem MeshPart verwendet wird.


      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. Mit WrapDeformer und EditableMesh erstellen Sie Werkzeuge zum Bearbeiten von Netzdeformationen auf Ihrem Körper.

    1. WrapDeformer behandelt die lebenden Verformungen der rendierten MeshPart Geometrie, während die darunterliegenden Skinning- und FACS-Daten erhalten bleiben.

    2. EditableMesh ermöglicht es ihnen, das käfignetz zu modifizieren, auf das die WrapDeformer antwortet.

      1. Verwende WrapDeformer:SetCageMeshContent(), um die Instanz EditableMesh, die das relevante Käfignetz darstellt, auf die WrapDeformer anzuwenden.
      2. Verwende EditableMesh, wie SetPosition(), um Vertexte zu deformieren und die Form des MeshPart zu bearbeiten.

      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

Erstellungsaufforderung erstellen

Nachdem du deinen Basiskörper eingerichtet und APIs bearbeitet hast, erstelle eine Aufforderung für Benutzer, die Erfahrung mit AvatarCreationService:PromptCreateAvatarAsync() zu erstellen und zu kaufen.


export type BodyPartInfo = {
bodyPart: Enum.BodyPart,
instance: Instance --Ordner mit erstellten Mesh-Teilen
}
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() nimmt einen HumanoidDescription Parameter an, um den Avatar zu repräsentieren, der zum Kauf oder zur Schöpfungbestimmt ist.Für die Schöpfungmuss der Charakter von HumanoidDescription neue Assets enthalten, die für jede der 6 Körperteile erstellt werden müssen (Head , Torso , RightLeg , LeftLeg , RightArm , LeftArm ).Optional kann es auch ein neues Hair Accessoireenthalten.

Um dies zu unterstützen, sollte die HumanoidDescription 6 Kinder enthalten 6 BodyPartDescription .Jede Eigenschaft referenziert eine , die alle Instanzen enthält, die den Körperteil bilden.Zum Beispiel enthält der Ordner LeftArm``LeftHand , LeftUpperArm und LeftLowerArm``Class.MeshPart|MeshParts.Die Eigenschaft BodyPartDescription.BodyPart sollte auch auf die entsprechende Enum.BodyPart festgelegt werden.

Jede der 15 MeshPart Körperteile muss enthalten:

Die bereitgestellte HumanoidDescription sollte keine vorhandenen Asset-IDs enthalten, um Körperteile oder Zubehör bei der beabsichtigten Schöpfungzu repräsentieren.Auf der anderen Seite kann die die menschlichen Skalierungen von , , und enthalten.Achten Sie auf die Skalierungen, mit denen ein Basiskörper importiert wird, damit sie den Skalierungen entsprechen, die für den HumanoidDescription bereitgestellt wurden.

Zubehör einbeziehen

Wenn ein Accessoire, wie Haare, enthalten ist, sollte die ein Kind enthalten, wo:

Erstelle ein Avatar-Erstellungs-Token

AvatarCreationService:PromptCreateAvatarAsync() nimmt einen Avatar-Erstellungs-Token-ID Parameter an.Dieses Token ist der Schlüssel für Kreationen aus deinem Universum, und es ist das, was du verwenden kannst, um den Preis der Avatarerstellung aus deiner Erlebnisfestzulegen.Für Anweisungen und zusätzliche Details zur Generierung von Tokens siehe Avatar-Erstellungs-Token.

Nach dem Kauf und der Generierung deines Tokens kannst du das Token im Creator-Hub inspizieren, um die ID zu finden, die du dann für die AvatarCreationService:PromptCreateAvatarAsync() verwenden kannst.

Reagiere auf Spieler, die sich durch Zuordnung beitreten

Avatar-Bündel, die in der Erfahrung erstellt wurden, enthalten einen Verweis auf das ursprüngliche Erlebnis, für das der Avatar erstellt wurde.Wenn der Avatar von einem anderen Spieler:ininspiziert wird, wird eine Eingabeaufforderung angezeigt, die eine Option bietet, die Erfahrung zu besuchen, in der der Avatar erstellt wurde.

Um Spieler, die deiner Erfahrung beitreten, mit diesem verlinkenbeizutreiben, verwende Player:GetJoinData() und parse die zurückgegebene Tabelle für GameJoinContext.

GameJoinContext enthält die folgenden tabellwerte: