Je kunt een ervaring publiceren die spelers in staat stelt om avatars in realtime te maken, aan te passen en aan te schaffen, naast in-experience make-up creatie. Wanneer deze aangepaste items worden aangeschaft, worden ze direct opgeslagen in de Roblox-inventaris van de speler, waardoor spelers ze kunnen uitrusten en dragen in andere ervaringen.
Ervaringseigenaren die in-experience avatarcreatie implementeren, profiteren van Marketplace commissies als de uitgever van het avataritem, terwijl de speler die het maakt de maker van het item is. Als een asset die in-experience is gemaakt, wordt geïnspecteerd, biedt het item een link naar de oorspronkelijke ervaring waarin het is gemaakt.
Je kunt in-experience creatie testen in de Avatar Creator demo van Roblox.
Hoe in-experience creatie te implementeren
Gebruik de volgende instructies en codeverwijzingen om je eerste in-experience avatarcreatieproject te maken. De volgende instructies gebruiken een basislichaam Model dat spelers kunnen aanpassen en wijzigen voordat ze het publiceren.
Voordat je begint, maak jezelf vertrouwd met het volgende:
- Avatar modellen — De volgende implementatie vereist het importeren van een basislichaam dat voldoet aan de 15-deel specificaties van Roblox. Dit Model dient als basis voor aanvullende gebruikersaanpassing en -wijziging.
- Het basislichaam moet voldoen aan de Avatar lichaamsrichtlijnen van Roblox, inclusief het minimum aantal FACS-controles voor gezichtsrigging.
- Avatar creatietokens — Ervaringen die avatarcreatie implementeren, vereisen ten minste één creatietoken. Deze tokens vereisen Robux om aan te schaffen en stellen je in staat om prijzen en andere verkoopinstellingen voor aankopen in-experience in te stellen.
- API-klassen
- AvatarCreationService — Behandelt het vragen om avatarcreatie en validatie.
- EditableImage — Behandelt runtime creatie en manipulatie van texturen.
- EditableMesh — Behandelt runtime manipulatie van mesh-geometrie.
- WrapDeformer — Behandelt runtime manipulatie van onzichtbare buitenste kooi-geometrie die avatarpersonages in staat stelt om 3D-kleding te dragen.
Importeer een basislichaam
Het basislichaam fungeert als de initiële basis die gebruikers kunnen aanpassen en bewerken. Je kunt je eigen Model gebruiken of een aangepast asset importeren met de Importer en instellen via Avatar Setup.
Basislichamen moeten voldoen aan de avatar specificaties van Roblox en moeten componenten bevatten zoals de 15 MeshPart instanties die 6 lichaamsdelen vormen: hoofd, torso, linkerarm, linkerbeen, rechterarm en rechterbeen, evenals andere avatarcomponenten.
Voor referenties en voorbeelden van goed geconfigureerde avatarlichamen, zie Avatar referenties.
Implementeer bewerkings-API's
Om een systeem te ontwikkelen waarin gebruikers de MeshPart instanties op een avatar in jouw ervaring kunnen bewerken voor creatie, gebruik EditableImage voor textuurbewerking, EditableMesh voor mesh-bewerking, en WrapDeformer voor het behouden van skinning en FACS-gegevens tijdens mesh-bewerkingen.
Nadat je je basislichaam hebt geïmporteerd, gebruik je het volgende script om je EditableImages, EditableMeshes, en WrapDeformers in te stellen.
local AssetService = game:GetService("AssetService")local function setupBodyPart(meshPart, wrapTarget)-- Maak en koppel een WrapDeformer aan de MeshPartlocal wrapDeformer = Instance.new("WrapDeformer")wrapDeformer.Parent = meshPart-- Maak een bewerkbare mesh voor de kooi-mesh van het wrapdoellocal cageEditableMesh: EditableMesh =AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {FixedSize = true,})-- Wijs de kooi-mesh toe aan de WrapDeformerwrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))endlocal function setupRigidMesh(meshPart)-- Maak een bewerkbare mesh van de originele MeshPartlocal editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {FixedSize = true,})-- Genereer een nieuwe MeshPart van de bewerkbare meshlocal newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))-- Kopieer grootte, positie en textuur van de originele MeshPartnewMeshPart.Size = meshPart.SizenewMeshPart.CFrame = meshPart.CFramenewMeshPart.TextureContent = meshPart.TextureContent-- Pas de nieuwe MeshPart toe op de originelemeshPart:ApplyMesh(newMeshPart)endlocal function setupMeshTexture(meshPart, textureIdToEditableImageMap)-- Als EditableImage al bestaat voor deze TextureID, hergebruik deze in plaats van een nieuwe te makenif textureIdToEditableImageMap[meshPart.TextureID] thenmeshPart.TextureContent =Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])returnend-- Maak een nieuwe EditableImage en pas deze toe als de textuurinhoudlocal editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))textureIdToEditableImageMap[meshPart.TextureID] = editableImagemeshPart.TextureContent = Content.fromObject(editableImage)endlocal function setupModel(model)-- Kaart voor het hergebruiken van EditableImage-instanties op basis van textuur-IDlocal textureIdToEditableImageMap = {}for _, descendant in model:GetDescendants() doif not descendant:IsA("MeshPart") thencontinueend-- Configureer MeshPart op basis van de aanwezigheid van WrapTarget-- Als WrapTarget aanwezig is, voeg een WrapDeformer-kind toe met een EditableMesh-- Anders, pas EditableMesh direct toe op de MeshPartlocal wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")if wrapTarget thensetupBodyPart(descendant, wrapTarget)elsesetupRigidMesh(descendant)end-- Configureer de EditableImage voor de MeshPartsetupMeshTexture(descendant, textureIdToEditableImageMap)endendMaak EditableImage tools waarmee spelers de kleur kunnen wijzigen, tekenen of stickers aan je basislichaam kunnen toevoegen. Je kunt API's gebruiken zoals DrawImage(), DrawRectangle(), WritePixelsBuffer().
Voor geavanceerde transformaties, stelt DrawImageTransformed() je in staat om positie, rotatie en schaal op te geven bij het tekenen van de ene EditableImage op de andere. Evenzo werkt DrawImageProjected() veel zoals DrawImage(), maar projecteert de getekende afbeelding correct als de EditableImage instantie wordt gebruikt met een 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)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 = (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
Gebruik WrapDeformer en EditableMesh om tools te maken voor het bewerken van mesh-deformaties op je lichaam.
WrapDeformer behandelt de live deformaties van de weergegeven MeshPart geometrie terwijl de onderliggende skinning en FACS-gegevens behouden blijven.
EditableMesh stelt je in staat om de kooi-mesh te wijzigen waar de WrapDeformer op reageert.
- Gebruik WrapDeformer:SetCageMeshContent() om de EditableMesh instantie die de relevante kooi-mesh vertegenwoordigt toe te passen op de WrapDeformer.
- Gebruik EditableMesh, zoals SetPosition(), om de vertices te vervormen en de vorm van de MeshPart te bewerken.
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
Maak een creatieprompt
Nadat je je basislichaam en bewerkings-API's hebt ingesteld, maak je een prompt voor gebruikers om te creëren en aan te schaffen vanuit de ervaring met AvatarCreationService:PromptCreateAvatarAsync().
export type BodyPartInfo = {
bodyPart: Enum.BodyPart,
instance: Instance --Folder met gemaakte MeshParts
}
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("Succesvol geüpload met BundleId: ", bundleIdOrErrorMessage)
print("Succesvol geüpload met OutfitId: ", outfitId)
else
print("Onsuccesvol geüpload met foutmelding:", bundleIdOrErrorMessage)
end
else
print("Avatarcreatie niet succesvol")
end
endAvatarCreationService:PromptCreateAvatarAsync() neemt een HumanoidDescription parameter om de avatar voor aankoop of creatie weer te geven. Voor avatarcreatie moet de HumanoidDescription van het personage nieuwe assets bevatten die voor elk van de 6 lichaamsdelen moeten worden gemaakt (Head, Torso, RightLeg, LeftLeg, RightArm, LeftArm). Optioneel kan het ook een nieuwe Hair accessoire bevatten.
Om dit te ondersteunen, moet de HumanoidDescription 6 BodyPartDescription kinderen bevatten. Elke BodyPartDescription.Instance eigenschap verwijst naar een Folder die alle MeshPart instanties bevat die het lichaamsdeel vormen. Bijvoorbeeld, de LeftArm map bevat LeftHand, LeftUpperArm, en LeftLowerArm MeshParts. De BodyPartDescription.BodyPart eigenschap moet ook worden ingesteld op de relevante Enum.BodyPart.
Elk van de 15 MeshPart lichaamsdelen moet bevatten:
- Een EditableImage.
- Een WrapDeformer met een EditableMesh.
De geleverde HumanoidDescription mag geen bestaande asset-ID's bevatten om lichaamsdelen of accessoires op de bedoelde creatie weer te geven. Aan de andere kant kan de HumanoidDescription de humanoïde schalen van BodyTypeScale, HeadScale, HeightScale, WidthScale, en ProportionScale bevatten. Wees je bewust van de schalen waarmee een basislichaam is geïmporteerd, zodat ze overeenkomen met de schalen die aan de HumanoidDescription zijn verstrekt.

Inclusief accessoires
Als je een accessoire, zoals haar, wilt opnemen, moet de HumanoidDescription een kind AccessoryDescription bevatten waar:
- De AccessoryDescription.Instance eigenschap verwijst naar de Accessory instantie.
- De AccessoryDescription.AccessoryType eigenschap is ingesteld op de relevante Enum.AccessoryType.
- In het geval van het opnemen van Enum.AccessoryType.Hair in je creaties, moet de MeshPart een EditableImage bevatten. Het mag echter geen WrapDeformer kind bevatten, maar moet een EditableMesh bevatten die direct op de MeshPart is ingesteld.
Genereer een avatar creatietoken
AvatarCreationService:PromptCreateAvatarAsync() neemt een Avatar Creatie Token ID parameter. Dit token is de sleutel voor creaties uit jouw universum, en het is wat je kunt gebruiken om de prijs van avatarcreatie vanuit jouw ervaring in te stellen. Voor instructies en aanvullende details over het genereren van tokens, zie Avatar Creatie Tokens.
Na het kopen en genereren van je token, kun je het token inspecteren in de Creator Hub om de ID te vinden die je vervolgens kunt gebruiken voor de AvatarCreationService:PromptCreateAvatarAsync() API.

Reageer op spelers die zich aanmelden via attributie
Avatarbundels die in-experience zijn gemaakt, bevatten een attributielink naar de oorspronkelijke ervaring waarin de avatar is gemaakt. Als de avatar door een andere speler wordt geïnspecteerd, verschijnt er een prompt met de optie om de ervaring te bezoeken waar de avatar is gemaakt.

Om spelers die zich aanmelden bij jouw ervaring via deze attributielink te verwerken, gebruik je Player:GetJoinData() en parse je de geretourneerde tabel voor GameJoinContext.
GameJoinContext bevat de volgende tabelwaarden:
- JoinSource — Enum.JoinSource
- Een Player die zich aanmeldt bij jouw ervaring via deze attributielink zal Enum.JoinSource.CreatedItemAttribution hebben om aan te geven dat de toegang afkomstig is van een gemaakt item.
- ItemType — optionele Enum.AvatarItemType
- AssetId — optionele string
- OutfitId — optionele string
- AssetType — optionele Enum.AssetType