Tạo {itemType}
Kiếm tiền

Tạo avatar trong trải nghiệm

*Nội dung này được dịch bằng AI (Beta) và có thể có lỗi. Để xem trang này bằng tiếng Anh, hãy nhấp vào đây.

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.

  1. 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, EditableMeshesWrapDeformers.


    local AssetService = game:GetService("AssetService")
    local function setupBodyPart(meshPart, wrapTarget)
    -- Tạo và gắn một WrapDeformer vào MeshPart
    local 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 target
    local cageEditableMesh: EditableMesh =
    AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {
    FixedSize = true,
    })
    -- Gán lưới cage cho WrapDeformer
    wrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))
    end
    local function setupRigidMesh(meshPart)
    -- Tạo một lưới có thể chỉnh sửa từ MeshPart gốc
    local editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {
    FixedSize = true,
    })
    -- Tạo một MeshPart mới từ lưới có thể chỉnh sửa
    local newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))
    -- Sao chép kích thước, vị trí và kết cấu từ MeshPart gốc
    newMeshPart.Size = meshPart.Size
    newMeshPart.CFrame = meshPart.CFrame
    newMeshPart.TextureContent = meshPart.TextureContent
    -- Áp dụng MeshPart mới trở lại cho gốc
    meshPart:ApplyMesh(newMeshPart)
    end
    local 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ới
    if textureIdToEditableImageMap[meshPart.TextureID] then
    meshPart.TextureContent =
    Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])
    return
    end
    -- Tạo một EditableImage mới và áp dụng nó làm nội dung kết cấu
    local editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))
    textureIdToEditableImageMap[meshPart.TextureID] = editableImage
    meshPart.TextureContent = Content.fromObject(editableImage)
    end
    local function setupModel(model)
    -- Bản đồ để sử dụng lại các phiên bản EditableImage theo ID kết cấu
    local textureIdToEditableImageMap = {}
    for _, descendant in model:GetDescendants() do
    if not descendant:IsA("MeshPart") then
    continue
    end
    -- 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 MeshPart
    local wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")
    if wrapTarget then
    setupBodyPart(descendant, wrapTarget)
    else
    setupRigidMesh(descendant)
    end
    -- Cấu hình EditableImage cho MeshPart
    setupMeshTexture(descendant, textureIdToEditableImageMap)
    end
    end
  2. Tạ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
      )
      end
      local 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)
      end
      local 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).Unit
      local 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
  3. Sử dụng WrapDeformerEditableMesh, 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.

    1. 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.

    2. EditableMesh cho phép bạn chỉnh sửa lưới cage mà WrapDeformer phản hồi tới.

      1. 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.
      2. 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.CageMeshId
      local wrapDeformer = Instance.new("WrapDeformer")
      wrapDeformer.Parent = meshPart
      local cageEditableMesh = AssetService:CreateEditableMeshAsync(cageMeshId)
      local verticesWithinSphere =
      cageEditableMesh:FindVerticesWithinSphere(controlPointCenter, controlPointRadius)
      for _, vertexId in verticesWithinSphere do
      local vertexPosition = cageEditableMesh:GetPosition(vertexId)
      cageEditableMesh:SetPosition(vertexId, vertexPosition + controlPointDeformation)
      end
      wrapDeformer: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:

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:

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:

©2026 Roblox Corporation. Roblox, logo Roblox và Powering Imagination là các nhãn hiệu đã đăng ký và chưa đăng ký của chúng tôi tại Hoa Kỳ và các quốc gia khác.