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
- AvatarCreationService — Handhabt die Avatarerstellung zur Eingabe und Validierung.
- EditableImage — Handhabt die Laufzeit-Erstellung und Manipulation von Texturen.
- EditableMesh — Handhabt die Laufzeit-Manipulation der Mesh-Geometrie.
- WrapDeformer — Handhabt die Laufzeit-Manipulation der unsichtbaren äußeren Käfiggeometrie, die es Avatar-Charaktern ermöglicht, 3D-Kleidung auszurüsten .
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.
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 hinzulocal wrapDeformer = Instance.new("WrapDeformer")wrapDeformer.Parent = meshPart-- Erstellen Sie ein bearbeitbares Mesh für das Käfignetz des Umfassungszielslocal cageEditableMesh: EditableMesh =AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {FixedSize = true,})-- Weisen Sie das Käfignetz dem WrapDeformer zuwrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))endlocal function setupRigidMesh(meshPart)-- Erstelle ein bearbeitbares Mesh aus dem ursprünglichen MeshPartlocal editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {FixedSize = true,})-- Erstelle ein neues MeshPart aus dem bearbeitbaren Meshlocal newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))-- Kopiere Größe, Position und Textur vom ursprünglichen MeshPartnewMeshPart.Size = meshPart.SizenewMeshPart.CFrame = meshPart.CFramenewMeshPart.TextureContent = meshPart.TextureContent-- Wenden Sie das neue MeshPart zurück auf das Original anmeshPart:ApplyMesh(newMeshPart)endlocal function setupMeshTexture(meshPart, textureIdToEditableImageMap)-- Wenn EditableImage bereits für diese Textur-ID existiert, verwende es erneut, anstatt eine neue zu erstellenif textureIdToEditableImageMap[meshPart.TextureID] thenmeshPart.TextureContent =Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])returnend-- Erstellen Sie ein neues bearbeitbares Bild und wenden Sie es als Texturinhalt anlocal editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))textureIdToEditableImageMap[meshPart.TextureID] = editableImagemeshPart.TextureContent = Content.fromObject(editableImage)endlocal function setupModel(model)-- Karte für die Wiederverwendung von bearbeitbaren Bildinstanzen durch Textur-IDlocal textureIdToEditableImageMap = {}for _, descendant in model:GetDescendants() doif not descendant:IsA("MeshPart") thencontinueend-- 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 anlocal wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")if wrapTarget thensetupBodyPart(descendant, wrapTarget)elsesetupRigidMesh(descendant)end-- Konfigurieren Sie das bearbeitbare Bild für das MeshPartsetupMeshTexture(descendant, textureIdToEditableImageMap)endendErstelle 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)endlocal 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)endlocal 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).Unitlocal 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
Mit WrapDeformer und EditableMesh erstellen Sie Werkzeuge zum Bearbeiten von Netzdeformationen auf Ihrem Körper.
WrapDeformer behandelt die lebenden Verformungen der rendierten MeshPart Geometrie, während die darunterliegenden Skinning- und FACS-Daten erhalten bleiben.
EditableMesh ermöglicht es ihnen, das käfignetz zu modifizieren, auf das die WrapDeformer antwortet.
- Verwende WrapDeformer:SetCageMeshContent(), um die Instanz EditableMesh, die das relevante Käfignetz darstellt, auf die WrapDeformer anzuwenden.
- 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.CageMeshIdlocal wrapDeformer = Instance.new("WrapDeformer")wrapDeformer.Parent = meshPartlocal cageEditableMesh = AssetService:CreateEditableMeshAsync(cageMeshId)local verticesWithinSphere =cageEditableMesh:FindVerticesWithinSphere(controlPointCenter, controlPointRadius)for _, vertexId in verticesWithinSphere dolocal vertexPosition = cageEditableMesh:GetPosition(vertexId)cageEditableMesh:SetPosition(vertexId, vertexPosition + controlPointDeformation)endwrapDeformer: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:
- An EditableImage .
- Ein WrapDeformer mit einem EditableMesh.
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:
- Die Eigenschaft AccessoryDescription.Instance verweist auf die Accessory Instanz.
- Die Eigenschaft AccessoryDescription.AccessoryType wird auf den relevanten Enum.AccessoryType festgelegt.
- Im Fall der Einbeziehung von Enum.AccessoryType.Hair in deine Kreationen sollte die MeshPart einen EditableImage enthalten.Es sollte jedoch kein WrapDeformer Kind enthalten, aber es sollte ein EditableMesh Set auf der MeshPart direkt enthalten.
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:
- JoinSource — Enum.JoinSource
- Ein Player Beitritt zu deiner Erfahrung von diesem Attributionslink wird Enum.JoinSource.CreatedItemAttribution anzeigen, dass der Eintrag aus einem erstellten Artikelstammt.
- ItemType — optional Enum.AvatarItemType
- AssetId — optional string
- OutfitId — optional string
- AssetType — optional Enum.AssetType