Puedes publicar una experiencia que permita a los jugadores crear, personalizar y comprar cuerpos de avatar en tiempo real.Al comprar, estos cuerpos personalizados se guardan directamente en el inventario de Roblox del jugador, permitiendo a los jugadores equipar y usar los avatares personalizados en otras experiencias.
Los propietarios de experiencia que implementan la creación de avatares en experiencia se benefician de comisiones de mercado tanto como creador del artículo de avatar como propietario de experiencia .Si se inspecciona un activo creado en la experiencia, el artículo proporciona un enlace a la experiencia original en la que se creó.
Puedes probar la creación en experiencia en la demostración de Creador de avatar de Roblox.
Cómo implementar la creacionesen experiencia
Sigue las instrucciones y referencias de código siguientes para crear tu primer proyecto de creación de avatar en experiencia.Las siguientes instrucciones utilizan un cuerpo base Model que los jugadores pueden modificar y personalizar antes de publicar.
Antes de comenzar, familiarízate con lo siguiendo:
- Modelos de avatar — La siguiente implementación requiere la importación de un cuerpo base que cumpla con las especificaciones de 15 partes de Roblox.Este Model sirve como base para la personalización y modificación adicional de usuarios.
- El cuerpo base debe cumplir con las directrices del cuerpo de avatar de Roblox Avatar body guidelines, incluyendo el número mínimo de control de FACS para la riggingfacial.
- Fichas de creación de avatar — Las experiencias que implementan la creación de avatares requieren al menos una ficha de creación.Estas fichas requieren Robux para comprar y te permiten establecer precios y otras configuraciones de venta para las compras realizadas en la experiencia.
- Clases de API
- AvatarCreationService — Maneja la creación del avatar que solicita y valida.
- EditableImage — Maneja la creación y manipulación de la ejecución de texturas.
- EditableMesh — Manipula la ejecución de la geometría de malla.
- WrapDeformer — Maneja la manipulación de tiempo de ejecución de la geometría de la jaula externa invisible que permite a los personajes de avatar equipar ropa 3D.
Importar un cuerpo base
El cuerpo base actúa como la base inicial que los usuarios pueden personalizar y editar.Puedes usar tu propio Model , o importar un recurso personalizado con el 3-D Importer y configurarlo a través de Configuración de avatar .
Los cuerpos base deben adherirse a las especificaciones de avatar de Roblox y deben incluir componentes como las 15 MeshPart que constituyen 6 partes del cuerpo: cabeza, torso, brazo izquierdo, pierna izquierda, brazo derecho y pierna derecha, así como otros componentes de avatar como.
Para referencias y muestras de cuerpos de avatar correctamente configurados, vea Referencias de avatar.
Implementar API de edición
Para desarrollar un sistema donde los usuarios puedan editar las instancias MeshPart en un avatar en tu experiencia para la creaciones, usa EditableImage para editar texturas, EditableMesh para editar mallas y WrapDeformer para mantener los datos de piel y FACS durante las ediciones de mallas.
Después de importar tu cuerpo base, usa el siguiente script para configurar tu EditableImages, EditableMeshes y WrapDeformers.
local AssetService = game:GetService("AssetService")local function setupBodyPart(meshPart, wrapTarget)-- Crear y adjuntar un WrapDeformer a la MeshPartlocal wrapDeformer = Instance.new("WrapDeformer")wrapDeformer.Parent = meshPart-- Crea una malla editable para la malla de la jaula del objetivo de envolturalocal cageEditableMesh: EditableMesh =AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {FixedSize = true,})-- Asigna la malla de la jaula al WrapDeformerwrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))endlocal function setupRigidMesh(meshPart)-- Crear una malla editable a partir de la malla original de MeshPartlocal editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {FixedSize = true,})-- Generar una nueva pieza de malla desde la malla editablelocal newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))-- Copiar el tamaño, la posición y la textura de la pieza original de mallanewMeshPart.Size = meshPart.SizenewMeshPart.CFrame = meshPart.CFramenewMeshPart.TextureContent = meshPart.TextureContent-- Aplica la nueva MeshPart de vuelta al originalmeshPart:ApplyMesh(newMeshPart)endlocal function setupMeshTexture(meshPart, textureIdToEditableImageMap)-- Si EditableImage ya existe para este ID de textura, úselo de nuevo en lugar de crear uno nuevoif textureIdToEditableImageMap[meshPart.TextureID] thenmeshPart.TextureContent =Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])returnend-- Crea una nueva imagen editable y aplícala como contenido de texturalocal editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))textureIdToEditableImageMap[meshPart.TextureID] = editableImagemeshPart.TextureContent = Content.fromObject(editableImage)endlocal function setupModel(model)-- Mapa para reutilizar instancias de EditableImage por ID de texturalocal textureIdToEditableImageMap = {}for _, descendant in model:GetDescendants() doif not descendant:IsA("MeshPart") thencontinueend-- Configurar MeshPart en función de la presencia de WrapTarget-- Si WrapTarget está presente, agregue un hijo de WrapDeformer con un EditableMesh-- De lo contrario, aplique EditableMesh a la pieza de malla directamentelocal wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")if wrapTarget thensetupBodyPart(descendant, wrapTarget)elsesetupRigidMesh(descendant)end-- Configurar la imagen editable para la pieza de mallasetupMeshTexture(descendant, textureIdToEditableImageMap)endendCrea EditableImage herramientas que permitan a los jugadores recolorar, dibujar o agregar pegatinas a tu cuerpo base.Puedes aprovechar las API en como DrawImage() , DrawRectangle() , WritePixelsBuffer() .
Para transformaciones avanzadas, DrawImageTransformed() te permite especificar posición, rotación y escala al dibujar una imagen editable sobre otra.Del mismo modo, DrawImageProjected() funciona mucho como DrawImage() pero proyecta la imagen dibujada correctamente si la instancia EditableImage se usa 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)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
Usando WrapDeformer y EditableMesh, crea herramientas para editar deformaciones de malla en tu cuerpo.
WrapDeformer maneja las deformaciones en vivo de la geometría renderizada MeshPart mientras mantiene los datos de skinning y FACS subyacentes.
EditableMesh te permite modificar la malla de la jaula a la que responde el WrapDeformer.
- Usa WrapDeformer:SetCageMeshContent() para aplicar la instancia EditableMesh que representa la malla relevante de la jaula al WrapDeformer.
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
Crear aviso de creación
Después de configurar tu cuerpo base y editar API, crea una solicitud para que los usuarios creen y compren de la experiencia usando AvatarCreationService:PromptCreateAvatarAsync() .
export type BodyPartInfo = {
bodyPart: Enum.BodyPart,
instance: Instance --Carpeta con piezas de malla creadas
}
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() toma un parámetro HumanoidDescription para representar el avatar destinado a la compra o creaciones.Para la creacionesde avatares, el personaje de HumanoidDescription debe incluir nuevos recursos para crear para cada una de las 6 partes del cuerpo (Head , Torso , RightLeg , LeftLeg , RightArm , LeftArm).Opcionalmente, también puede incluir un nuevo accesorio Hair.
Para apoyar esto, el HumanoidDescription debe incluir 6 BodyPartDescription hijos.Cada propiedad BodyPartDescription.Instance se refiere a una Folder que incluye todas las instancias MeshPart que componen la parte del cuerpo.Por ejemplo, la carpeta LeftArm contiene LeftHand , LeftUpperArm , y LeftLowerArm``Class.MeshPart|MeshParts .La propiedad BodyPartDescription.BodyPart debe establecerse también al Enum.BodyPart relevante.
Cada una de las 15 MeshPart partes del cuerpo debe incluir:
- An EditableImage .
- Un WrapDeformer con un EditableMesh.
El proporcionado HumanoidDescription no debe incluir ninguna ID de activo preexistente para representar partes del cuerpo o accesorios en la creacionespretendida.Por otro lado, el HumanoidDescription puede incluir las escalas humanoides de BodyTypeScale , HeadScale , HeightScale , WidthScale , y ProportionScale .Tenga en cuenta las escalas con las que se importa un cuerpo base para que coincidan con las escalas proporcionadas al HumanoidDescription.

Incluir accesorios
Si se incluye un accesorio, como el pelo, el HumanoidDescription debe incluir un hijo AccessoryDescription donde:
- La propiedad AccessoryDescription.Instance se refiere a la instancia Accessory.
- La propiedad AccessoryDescription.AccessoryType se establece en el relevante Enum.AccessoryType.
- En el caso de incluir Enum.AccessoryType.Hair en tus creaciones, el MeshPart debe incluir un EditableImage .Sin embargo, no debe incluir un WrapDeformer hijo, pero debe incluir un EditableMesh conjunto en el MeshPart directamente.
Generar una ficha de creación de avatar
AvatarCreationService:PromptCreateAvatarAsync() toma un parámetro ID de creación de avatar .Esta ficha es la clave para las creaciones de tu universo, y es lo que puedes usar para establecer el precio de la creación de avatares desde tu experiencia.Para instrucciones y detalles adicionales sobre la generación de tokens, vea Fichas de creación de avatares.
Después de comprar y generar tu token, puedes inspeccionar el token en el Hub de creadores para encontrar el ID que puedes usar luego para la API de AvatarCreationService:PromptCreateAvatarAsync().

Responder a los jugadores que se unen por atribución
Los paquetes de avatares creados en la experiencia incluyen un enlace de atribución a la experiencia original en la que se creó el avatar.Si el avatar es inspeccionado por otro jugador, se muestra un mensaje que proporciona una opción para visitar la experiencia en la que se creó el avatar.

Para manejar a los jugadores que se unen a tu experiencia usando este enlazarde atribución, usa Player:GetJoinData() y parsea la tabla devuelta para GameJoinContext .
GameJoinContext incluye los siguientes valores de tabla:
- JoinSource — Enum.JoinSource
- Unirse a tu experiencia desde este enlace de atribución Player tendrá Enum.JoinSource.CreatedItemAttribution para indicar la entrada de un objetocreado.
- ItemType — opcional Enum.AvatarItemType
- AssetId — opcional string
- OutfitId — opcional string
- AssetType — opcional Enum.AssetType