Bạn có thể xuất bản một trải nghiệm cho phép người chơi tạo, tùy chỉnh và mua các hình đại diện trong thời gian thực. Khi được mua, những hình đại diện tùy chỉnh này sẽ ngay lập tức lưu vào kho đồ của người chơi trên Roblox, cho phép người chơi trang bị và mặc các hình đại diện tùy chỉnh trong các trải nghiệm khác.
Các chủ sở hữu trải nghiệm thực hiện việc tạo hình đại diện trong trải nghiệm sẽ được hưởng lợi từ hoa hồng Thị Trường như cả nhà phát triển của mặt hàng hình đại diện và chủ sở hữu trải nghiệm. Nếu một tài sản được tạo ra trong trải nghiệm được kiểm tra, mặt hàng đó sẽ cung cấp một liên kết đến trải nghiệm gốc mà nó được tạo ra.
Bạn có thể thử nghiệm việc tạo trong trải nghiệm trong bản demo Avatar Creator của Roblox.
Cách thực hiện tạo trong trải nghiệm
Sử dụng các hướng dẫn và mã tham chiếu sau để tạo dự án tạo hình đại diện trong trải nghiệm đầu tiên của bạn. Các hướng dẫn sau sử dụng một cơ thể cơ bản Model mà người chơi có thể chỉnh sửa và tùy chỉnh trước khi xuất bản.
Trước khi bắt đầu, hãy làm quen với các thông tin sau:
- Mô hình hình đại diện — Việc thực hiện sau đây yêu cầu nhập một cơ thể cơ bản đáp ứng các thông số kỹ thuật 15 phần của Roblox. Model này phục vụ như một cơ sở cho việc tùy chỉnh và chỉnh sửa của người dùng.
- Cơ thể cơ bản phải đáp ứng các hướng dẫn hình đại diện của Roblox, bao gồm số lượng tối thiểu các điều khiển FACS cho rigging khuôn mặt.
- Mã thông báo tạo hình đại diện — Các trải nghiệm thực hiện việc tạo hình đại diện yêu cầu ít nhất một mã thông báo tạo. Các mã thông báo này yêu cầu Robux để mua và cho phép bạn thiết lập giá cả và các cài đặt bán khác cho các giao dịch được thực hiện trong trải nghiệm.
- Các lớp API
- AvatarCreationService — Xử lý việc yêu cầu và xác thực tạo hình đại diện.
- EditableImage — Xử lý việc tạo và thao tác các kết cấu trong thời gian thực.
- EditableMesh — Xử lý việc thao tác hình học mesh trong thời gian thực.
- WrapDeformer — Xử lý việc thao tác hình học lồng cage vô hình cho phép các nhân vật hình đại diện trang bị quần áo 3D.
Nhập một cơ thể cơ bản
Cơ thể cơ bản hoạt động như nền tảng ban đầu mà người dùng có thể tùy chỉnh và chỉnh sửa. Bạn có thể sử dụng Model riêng của mình, hoặc nhập một tài sản tùy chỉnh bằng cách sử dụng Importer và thiết lập thông qua Avatar Setup.
Các cơ thể cơ bản phải tuân thủ các thông số kỹ thuật hình đại diện của Roblox và phải bao gồm các thành phần như 15 MeshPart mà tạo thành 6 bộ phận cơ thể: đầu, thân, cánh tay trái, chân trái, cánh tay phải, và chân phải, cũng như các thành phần hình đại diện.
Để tham khảo và mẫu về các cơ thể hình đại diện được cấu hình chính xác, xem Avatar references.
Thực hiện các API chỉnh sửa
Để phát triển một hệ thống nơi người dùng có thể chỉnh sửa các MeshPart trên một hình đại diện trong trải nghiệm của bạn để tạo ra, hãy sử dụng EditableImage để chỉnh sửa chất liệu, EditableMesh để chỉnh sửa mesh, và WrapDeformer để duy trì dữ liệu skinning và FACS trong quá trình chỉnh sửa mesh.
Sau khi nhập cơ thể cơ bản của bạn, sử dụng đoạn mã sau để thiết lập EditableImages, EditableMeshes, và WrapDeformers.
local AssetService = game:GetService("AssetService")local function setupBodyPart(meshPart, wrapTarget)-- Tạo và gắn một WrapDeformer vào MeshPartlocal wrapDeformer = Instance.new("WrapDeformer")wrapDeformer.Parent = meshPart-- Tạo một mesh có thể chỉnh sửa cho mesh lồng cage của wrapTargetlocal cageEditableMesh: EditableMesh =AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {FixedSize = true,})-- Gán mesh cage cho WrapDeformerwrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))endlocal function setupRigidMesh(meshPart)-- Tạo một mesh có thể chỉnh sửa từ MeshPart gốclocal editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {FixedSize = true,})-- Tạo một MeshPart mới từ mesh có thể chỉnh sửalocal newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))-- Sao chép kích thước, vị trí, và kết cấu từ MeshPart gốcnewMeshPart.Size = meshPart.SizenewMeshPart.CFrame = meshPart.CFramenewMeshPart.TextureContent = meshPart.TextureContent-- Áp dụng MeshPart mới trở lại cho phần gốcmeshPart:ApplyMesh(newMeshPart)endlocal function setupMeshTexture(meshPart, textureIdToEditableImageMap)-- Nếu EditableImage đã tồn tại cho TextureID này, hãy tái sử dụng nó thay vì tạo một cái mớiif textureIdToEditableImageMap[meshPart.TextureID] thenmeshPart.TextureContent =Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])returnend-- Tạo một EditableImage mới và áp dụng nó như nội dung kết cấulocal editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))textureIdToEditableImageMap[meshPart.TextureID] = editableImagemeshPart.TextureContent = Content.fromObject(editableImage)endlocal function setupModel(model)-- Bản đồ để tái sử dụng các thể hiện EditableImage theo ID kết cấulocal textureIdToEditableImageMap = {}for _, descendant in model:GetDescendants() doif not descendant:IsA("MeshPart") thencontinueend-- Cấu hình MeshPart dựa trên sự hiện diện của WrapTarget-- Nếu WrapTarget có mặt, thêm một WrapDeformer con với một EditableMesh-- Nếu không, áp dụng EditableMesh trực tiếp vào MeshPartlocal wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")if wrapTarget thensetupBodyPart(descendant, wrapTarget)elsesetupRigidMesh(descendant)end-- Cấu hình EditableImage cho MeshPartsetupMeshTexture(descendant, textureIdToEditableImageMap)endendTạo các công cụ EditableImage cho phép người chơi tô màu, vẽ, hoặc thêm nhãn dán vào cơ thể cơ bản của bạn. Bạn có thể tận dụng các API như DrawImage(), DrawRectangle(), WritePixelsBuffer().
Đối với các biến đổi nâng cao, DrawImageTransformed() cho phép bạn xác định vị trí, góc xoay, và tỷ lệ khi vẽ một EditableImage lên một cái khác. Tương tự, DrawImageProjected() hoạt động giống như DrawImage() nhưng chiếu đúng hình ảnh được vẽ nếu thể hiện EditableImage được sử dụng với một 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
Sử dụng WrapDeformer và EditableMesh, tạo các công cụ để chỉnh sửa sự biến dạng của mesh trên cơ thể của bạn.
WrapDeformer xử lý các biến dạng trực tiếp của hình học MeshPart được render trong khi duy trì dữ liệu skinning và FACS cơ bản.
EditableMesh cho phép bạn chỉnh sửa mesh cage mà WrapDeformer phản hồi.
- Sử dụng WrapDeformer:SetCageMeshContent() để áp dụng thể hiện EditableMesh đại diện cho mesh cage liên quan vào WrapDeformer.
- Sử dụng EditableMesh, chẳng hạn như SetPosition(), để biến dạng các điểm và chỉnh sửa hình dạng của MeshPart.
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
Tạo thông báo tạo
Sau khi thiết lập cơ thể cơ bản và các API chỉnh sửa, hãy tạo một thông báo cho người dùng để tạo và mua từ trải nghiệm bằng cách sử dụng AvatarCreationService:PromptCreateAvatarAsync().
export type BodyPartInfo = {
bodyPart: Enum.BodyPart,
instance: Instance --Thư mục với các MeshParts đã tạo
}
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("Tải lên thành công với BundleId: ", bundleIdOrErrorMessage)
print("Tải lên thành công với OutfitId: ", outfitId)
else
print("Tải lên không thành công với thông báo lỗi:", bundleIdOrErrorMessage)
end
else
print("Tạo hình đại diện không thành công")
end
endAvatarCreationService:PromptCreateAvatarAsync() nhận tham số HumanoidDescription để đại diện cho hình đại diện dự kiến sẽ được mua hoặc tạo. Đối với việc tạo hình đại diện, HumanoidDescription của nhân vật phải bao gồm các tài sản mới để được tạo ra cho từng trong 6 bộ phận cơ thể (Head, Torso, RightLeg, LeftLeg, RightArm, LeftArm). Tùy chọn, nó cũng có thể bao gồm một phụ kiện Hair mới.
Để hỗ trợ điều này, HumanoidDescription nên bao gồm 6 BodyPartDescription con. Mỗi thuộc tính BodyPartDescription.Instance tham chiếu đến một Folder bao gồm tất cả các thể hiện MeshPart tạo thành bộ phận cơ thể. Ví dụ, thư mục LeftArm chứa LeftHand, LeftUpperArm, và LeftLowerArm MeshParts. Thuộc tính BodyPartDescription.BodyPart cũng nên được thiết lập để tương ứng với Enum.BodyPart.
Mỗi trong số 15 bộ phận MeshPart cơ thể phải bao gồm:
- Một EditableImage.
- Một WrapDeformer với một EditableMesh.
HumanoidDescription được cung cấp không nên bao gồm bất kỳ ID tài sản nào đã tồn tại trước đó để đại diện cho bộ phận cơ thể hoặc phụ kiện trên hình đại diện dự kiến sẽ được tạo. Ngược lại, HumanoidDescription có thể bao gồm quy mô nhân hình của BodyTypeScale, HeadScale, HeightScale, WidthScale, và ProportionScale. Hãy lưu ý đến các tỷ lệ mà cơ thể cơ bản được nhập với để chúng khớp với tỷ lệ được cung cấp cho HumanoidDescription.

Bao gồm phụ kiện
Nếu bao gồm một phụ kiện, chẳng hạn như tóc, HumanoidDescription nên bao gồm một AccessoryDescription con nơi:
- Thuộc tính AccessoryDescription.Instance tham chiếu đến thể hiện Accessory.
- Thuộc tính AccessoryDescription.AccessoryType được thiết lập tương ứng với Enum.AccessoryType.
- Trong trường hợp bao gồm Enum.AccessoryType.Hair trong các tác phẩm của bạn, MeshPart nên bao gồm một EditableImage. Tuy nhiên, nó không nên bao gồm một WrapDeformer con mà nên bao gồm một EditableMesh được thiết lập trên MeshPart trực tiếp.
Tạo mã thông báo tạo hình đại diện
AvatarCreationService:PromptCreateAvatarAsync() nhận tham số ID Mã thông báo Tạo hình đại diện. Mã thông báo này là chìa khóa cho các tác phẩm từ vũ trụ của bạn, và bạn có thể sử dụng nó để thiết lập giá cho việc tạo hình đại diện từ trải nghiệm của bạn. Để biết hướng dẫn và thông tin chi tiết bổ sung về việc tạo mã thông báo, xem Mã thông báo Tạo hình đại diện.
Sau khi mua và tạo mã thông báo của bạn, bạn có thể kiểm tra mã thông báo trong Creator Hub để tìm ID mà bạn có thể sử dụng cho API AvatarCreationService:PromptCreateAvatarAsync().

Phản hồi người chơi tham gia bằng liên kết phân phối
Các gói hình đại diện được tạo trong trải nghiệm bao gồm một liên kết phân phối đến trải nghiệm gốc mà hình đại diện đã được tạo ra. Nếu hình đại diện được kiểm tra bởi một người chơi khác, một thông báo xuất hiện cung cấp tùy chọn để truy cập trải nghiệm nơi hình đại diện đã được tạo ra.

Để xử lý người chơi tham gia trải nghiệm của bạn bằng cách sử dụng liên kết phân phối này, hãy sử dụng Player:GetJoinData() và phân tích bảng được trả về để lấy GameJoinContext.
GameJoinContext bao gồm các giá trị bảng sau:
- JoinSource — Enum.JoinSource
- Một Player tham gia trải nghiệm của bạn từ liên kết phân phối này sẽ có Enum.JoinSource.CreatedItemAttribution để chỉ ra việc tham gia từ một mặt hàng đã tạo.
- ItemType — tùy chọn Enum.AvatarItemType
- AssetId — tùy chọn string
- OutfitId — tùy chọn string
- AssetType — tùy chọn Enum.AssetType