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 phần cơ thể avatar trong thời gian thực. Khi được mua, những phần cơ thể tùy chỉnh này sẽ được lưu trực tiếp vào kho đồ Roblox của người chơi, cho phép người chơi trang bị và mặc các avatar 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 avatar trong trải nghiệm sẽ hưởng lợi từ hoa hồng trên thị trường như cả nhà sáng tạo của vật phẩm avatar 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, vật phẩm này 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ể kiểm tra việc tạo trong trải nghiệm ở bản trình diễn 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à tham khảo mã sau để tạo dự án tạo avatar 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ể sửa đổi 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 những điều sau:
- Mô hình avatar — 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 nền tảng cho việc tùy chỉnh và sửa đổi thêm của người dùng.
- Cơ thể cơ bản phải đáp ứng các hướng dẫn về cơ thể avatar 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ã tạo avatar — Các trải nghiệm thực hiện việc tạo avatar yêu cầu ít nhất một mã tạo. Các mã 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 hàng 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 nhắc người dùng tạo avatar và xác thực.
- 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ý thao tác hình học lưới trong thời gian thực.
- WrapDeformer — Xử lý thao tác hình học cage bên ngoài không nhìn thấy cho phép nhân vật avatar trang bị thời trang 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 của riêng mình, hoặc nhập một tài sản tùy chỉnh với Importer và thiết lập thông qua Cài đặt Avatar.
Cơ thể cơ bản phải tuân thủ các thông số kỹ thuật avatar của Roblox và phải bao gồm các thành phần như 15 phiên bản MeshPart tạo thành 6 phần cơ thể: đầu, thân, tay trái, chân trái, tay phải và chân phải, cũng như các thành phần avatar khác.
Để tham khảo và mẫu của những cơ thể avatar được cấu hình đúng, xem Tham khảo Avatar.
Thực hiện các API chỉnh sửa
Để phát triển một hệ thống mà người dùng có thể chỉnh sửa các phiên bản MeshPart trên một avatar trong trải nghiệm của bạn cho việc tạo ra, hãy sử dụng EditableImage cho việc chỉnh sửa kết cấu, EditableMesh cho việc chỉnh sửa lưới, và WrapDeformer để duy trì dữ liệu skinning và FACS trong các lần sửa đổi lưới.
Sau khi nhập cơ thể cơ bản của bạn, hãy sử dụng kịch bản 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 lưới có thể chỉnh sửa cho lưới cage của wrap targetlocal cageEditableMesh: EditableMesh =AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {FixedSize = true,})-- Gán lưới cage cho WrapDeformerwrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))endlocal function setupRigidMesh(meshPart)-- Tạo một lưới 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ừ lưới 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 gốcmeshPart:ApplyMesh(newMeshPart)endlocal function setupMeshTexture(meshPart, textureIdToEditableImageMap)-- Nếu EditableImage đã tồn tại cho TextureID này, hãy sử dụng lại nó thay vì tạo 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ó làm 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 đồ để sử dụng lại các phiên bả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-- Ngược lại, áp dụng EditableMesh trực tiếp cho 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 thay đổi màu sắc, 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í, xoay và tỷ lệ khi vẽ một EditableImage lên một EditableImage khác. Tương tự, DrawImageProjected() hoạt động tương tự như DrawImage() nhưng chiếu hình ảnh đã vẽ đúng cách nếu phiên bả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ụ cho việc chỉnh sửa biến dạng lưới 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 kết xuất trong khi duy trì dữ liệu skinning và FACS cơ bản.
EditableMesh cho phép bạn chỉnh sửa lưới cage mà WrapDeformer phản hồi tới.
- Sử dụng WrapDeformer:SetCageMeshContent() để áp dụng phiên bản EditableMesh đại diện cho lưới cage liên quan cho WrapDeformer.
- Sử dụng EditableMesh, chẳng hạn như SetPosition(), để biến dạng các đỉnh 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 prompt cho việc 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 prompt 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 --Folder với các MeshPart đã 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("Không thành công khi tải lên với thông báo lỗi: ", bundleIdOrErrorMessage)
end
else
print("Việc tạo avatar không thành công")
end
end
AvatarCreationService:PromptCreateAvatarAsync() nhận một tham số HumanoidDescription để đại diện cho avatar dự định được mua hoặc tạo. Đối với việc tạo avatar, mô tả của nhân vật HumanoidDescription phải bao gồm các tài sản mới sẽ được tạo cho mỗi trong 6 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 mới Hair.
Để hỗ trợ điều này, HumanoidDescription nên bao gồm 6 đứa trẻ BodyPartDescription. Mỗi thuộc tính BodyPartDescription.Instance tham chiếu đến một Folder bao gồm tất cả các phiên bản MeshPart tạo thành 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 đặt thành Enum.BodyPart phù hợp.
Mỗi trong số 15 phần cơ thể MeshPart phải bao gồm:
- Một EditableImage.
- Một WrapDeformer với một EditableMesh.
HumanoidDescription cung cấp không nên bao gồm bất kỳ ID tài sản nào đã có để đại diện cho các phần cơ thể hoặc phụ kiện trên việc tạo dự định. Mặt khác, HumanoidDescription có thể bao gồm các kích thước nhân loại của BodyTypeScale, HeadScale, HeightScale, WidthScale, và ProportionScale. Hãy chú ý đến các kích thước mà một cơ thể cơ bản được nhập với để đảm bảo rằng chúng khớp với các kích thước đượ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, thì HumanoidDescription nên bao gồm một đứa trẻ AccessoryDescription nơi:
- Thuộc tính AccessoryDescription.Instance tham chiếu tới phiên bản Accessory.
- Thuộc tính AccessoryDescription.AccessoryType được đặt thành Enum.AccessoryType phù hợp.
- Trong trường hợp bao gồm Enum.AccessoryType.Hair trong các sản 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 đặt trực tiếp trên MeshPart.
Tạo mã tạo avatar
AvatarCreationService:PromptCreateAvatarAsync() nhận một tham số Mã Tạo Avatar. Mã này là chìa khóa cho các sản phẩm từ vũ trụ của bạn, và đó là thứ bạn có thể sử dụng để thiết lập giá cho việc tạo avatar từ trải nghiệm của bạn. Để hướng dẫn và thông tin chi tiết bổ sung về việc tạo mã, xem Mã tạo Avatar.
Sau khi mua và tạo mã của bạn, bạn có thể kiểm tra mã trong Creator Hub để tìm ID mà bạn có thể sử dụng cho API AvatarCreationService:PromptCreateAvatarAsync().

Phản hồi khi người chơi tham gia thông qua Attribution
Các gói avatar được tạo ra trong trải nghiệm bao gồm một liên kết attribution đến trải nghiệm gốc mà avatar được tạo ra. Nếu avatar được kiểm tra bởi một người chơi khác, một prompt hiển thị cung cấp tùy chọn để truy cập vào trải nghiệm nơi avatar được tạo ra.

Để xử lý việc 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 attribution này, hãy sử dụng Player:GetJoinData() và phân tích bảng trả về cho 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 attribution này sẽ có Enum.JoinSource.CreatedItemAttribution để chỉ ra việc vào từ một vật phẩm đã 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