Buat {itemType}
Monetisasi
Kebijakan dan Pedoman

Pembuatan Avatar di dalam Pengalaman

*Konten ini diterjemahkan menggunakan AI (Beta) dan mungkin mengandung kesalahan. Untuk melihat halaman ini dalam bahasa Inggris, klik di sini.

Anda dapat menerbitkan pengalaman yang memungkinkan pemain membuat, menyesuaikan, dan membeli tubuh avatar secara real-time. Setelah dibeli, tubuh khusus ini disimpan langsung ke inventaris Roblox pemain, memungkinkan pemain untuk memasang dan mengenakan avatar khusus di pengalaman lain.

Pemilik pengalaman yang menerapkan pembuatan avatar di dalam pengalaman mendapatkan manfaat dari komisi Marketplace sebagai pembuat item avatar dan pemilik pengalaman. Jika suatu aset yang dibuat di dalam pengalaman diperiksa, item tersebut memberikan tautan ke pengalaman asli tempat ia dibuat.

Anda dapat menguji pembuatan di dalam pengalaman di demo Avatar Creator Roblox.

Cara menerapkan pembuatan di dalam pengalaman

Gunakan instruksi dan referensi kode berikut untuk membuat proyek pembuatan avatar di dalam pengalaman pertama Anda. Instruksi berikut menggunakan tubuh dasar Model yang dapat dimodifikasi dan disesuaikan oleh pemain sebelum diterbitkan.

Sebelum memulai, kenali hal-hal berikut:

  • Model avatar — Implementasi berikut memerlukan impor tubuh dasar yang memenuhi spesifikasi 15 bagian Roblox. Model ini berfungsi sebagai dasar untuk penyesuaian dan modifikasi pengguna tambahan.
    • Tubuh dasar harus memenuhi pedoman tubuh avatar Roblox, termasuk jumlah minimum kontrol FACS untuk pengatur rigging wajah.
  • Token pembuatan avatar — Pengalaman yang menerapkan pembuatan avatar memerlukan setidaknya satu token pembuatan. Token ini memerlukan Robux untuk dibeli dan memungkinkan Anda untuk menetapkan harga dan pengaturan penjualan lainnya untuk pembelian yang dilakukan di dalam pengalaman.
  • Kelas API
    • AvatarCreationService — Menangani permintaan pembuatan avatar dan validasi.
    • EditableImage — Menangani pembuatan dan manipulasi tekstur saat runtime.
    • EditableMesh — Menangani manipulasi geometri mesh saat runtime.
    • WrapDeformer — Menangani manipulasi runtime dari geometri kerangka luar yang tidak terlihat yang memungkinkan karakter avatar untuk memasang pakaian 3D.

Impor tubuh dasar

Tubuh dasar berfungsi sebagai fondasi awal yang dapat dikustomisasi dan diedit oleh pengguna. Anda dapat menggunakan Model Anda sendiri, atau mengimpor aset kustom dengan Importer dan mengatur melalui Avatar Setup.

Tubuh dasar harus mematuhi spesifikasi avatar Roblox, dan harus menyertakan komponen seperti 15 MeshPart yang membentuk 6 bagian tubuh: kepala, torso, lengan kiri, kaki kiri, lengan kanan, dan kaki kanan, serta komponen avatar lainnya.

Untuk referensi dan contoh tubuh avatar yang dikonfigurasi dengan benar, lihat Referensi Avatar.

Implementasikan API pengeditan

Untuk mengembangkan sistem di mana pengguna dapat mengedit MeshPart pada avatar di dalam pengalaman Anda untuk pembuatan, gunakan EditableImage untuk pengeditan tekstur, EditableMesh untuk pengeditan mesh, dan WrapDeformer untuk mempertahankan skinning dan data FACS selama pengeditan mesh.

  1. Setelah mengimpor tubuh dasar Anda, gunakan skrip berikut untuk mengatur EditableImages, EditableMeshes, dan WrapDeformers.


    local AssetService = game:GetService("AssetService")
    local function setupBodyPart(meshPart, wrapTarget)
    -- Buat dan lampirkan WrapDeformer ke MeshPart
    local wrapDeformer = Instance.new("WrapDeformer")
    wrapDeformer.Parent = meshPart
    -- Buat mesh yang dapat diedit untuk mesh kerangka target
    local cageEditableMesh: EditableMesh =
    AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {
    FixedSize = true,
    })
    -- Tetapkan mesh kerangka ke WrapDeformer
    wrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))
    end
    local function setupRigidMesh(meshPart)
    -- Buat mesh yang dapat diedit dari MeshPart asli
    local editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {
    FixedSize = true,
    })
    -- Hasilkan MeshPart baru dari mesh yang dapat diedit
    local newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))
    -- Salin ukuran, posisi, dan tekstur dari MeshPart asli
    newMeshPart.Size = meshPart.Size
    newMeshPart.CFrame = meshPart.CFrame
    newMeshPart.TextureContent = meshPart.TextureContent
    -- Terapkan MeshPart baru kembali ke yang asli
    meshPart:ApplyMesh(newMeshPart)
    end
    local function setupMeshTexture(meshPart, textureIdToEditableImageMap)
    -- Jika EditableImage sudah ada untuk TextureID ini, gunakan kembali daripada membuat yang baru
    if textureIdToEditableImageMap[meshPart.TextureID] then
    meshPart.TextureContent =
    Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])
    return
    end
    -- Buat EditableImage baru dan terapkan sebagai konten tekstur
    local editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))
    textureIdToEditableImageMap[meshPart.TextureID] = editableImage
    meshPart.TextureContent = Content.fromObject(editableImage)
    end
    local function setupModel(model)
    -- Peta untuk menggunakan kembali instance EditableImage berdasarkan ID tekstur
    local textureIdToEditableImageMap = {}
    for _, descendant in model:GetDescendants() do
    if not descendant:IsA("MeshPart") then
    continue
    end
    -- Konfigurasi MeshPart berdasarkan keberadaan WrapTarget
    -- Jika WrapTarget ada, tambahkan WrapDeformer anak dengan EditableMesh
    -- Jika tidak, terapkan EditableMesh langsung ke MeshPart
    local wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")
    if wrapTarget then
    setupBodyPart(descendant, wrapTarget)
    else
    setupRigidMesh(descendant)
    end
    -- Konfigurasi EditableImage untuk MeshPart
    setupMeshTexture(descendant, textureIdToEditableImageMap)
    end
    end
  2. Buat alat EditableImage yang memungkinkan pemain untuk mengubah warna, menggambar, atau menambahkan stiker ke tubuh dasar Anda. Anda dapat memanfaatkan API seperti DrawImage(), DrawRectangle(), WritePixelsBuffer().

    • Untuk transformasi lanjutan, DrawImageTransformed() memungkinkan Anda untuk menentukan posisi, rotasi, dan skala saat menggambar satu EditableImage ke yang lain. Demikian pula, DrawImageProjected() bekerja hampir sama dengan DrawImage() tetapi memproyeksikan gambar yang digambar dengan benar jika instance EditableImage digunakan dengan 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. Menggunakan WrapDeformer dan EditableMesh, buat alat untuk mengedit deformasi mesh pada tubuh Anda.

    1. WrapDeformer menangani deformasi langsung dari geometri MeshPart yang dirender sambil mempertahankan skining dan data FACS yang mendasari.

    2. EditableMesh memungkinkan Anda memodifikasi mesh kerangka yang diperoleh WrapDeformer.

      1. Gunakan WrapDeformer:SetCageMeshContent() untuk menerapkan instance EditableMesh yang mewakili mesh kerangka yang relevan ke WrapDeformer.
      2. Gunakan EditableMesh, seperti SetPosition(), untuk mendefinisikan vertex dan mengedit bentuk 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

Buat permintaan pembuatan

Setelah mengatur tubuh dasar Anda dan API pengeditan, buat permintaan bagi pengguna untuk membuat dan membeli dari pengalaman menggunakan AvatarCreationService:PromptCreateAvatarAsync().


export type BodyPartInfo = {
bodyPart: Enum.BodyPart,
instance: Instance --Folder dengan Created 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("Berhasil diunggah dengan BundleId: ", bundleIdOrErrorMessage)
print("Berhasil diunggah dengan OutfitId: ", outfitId)
else
print("Tidak berhasil diunggah dengan pesan kesalahan:", bundleIdOrErrorMessage)
end
else
print("Pembuatan avatar tidak berhasil")
end
end

AvatarCreationService:PromptCreateAvatarAsync() mengambil parameter HumanoidDescription untuk mewakili avatar yang dimaksudkan untuk dibeli atau dibuat. Untuk pembuatan avatar, HumanoidDescription karakter harus mencakup aset baru yang akan dibuat untuk masing-masing dari 6 bagian tubuh (Head, Torso, RightLeg, LeftLeg, RightArm, LeftArm). Jika diinginkan, juga dapat mencakup aksesori baru Hair.

Untuk mendukung ini, HumanoidDescription harus mencakup 6 anak BodyPartDescription. Setiap properti BodyPartDescription.Instance merujuk ke Folder yang mencakup semua instance MeshPart yang membentuk bagian tubuh. Sebagai contoh, folder LeftArm berisi LeftHand, LeftUpperArm, dan LeftLowerArm MeshParts. Properti BodyPartDescription.BodyPart juga harus diatur ke Enum.BodyPart yang relevan.

Setiap dari 15 MeshPart bagian tubuh harus mencakup:

HumanoidDescription yang disediakan tidak boleh mencakup ID aset yang sudah ada untuk mewakili bagian tubuh atau aksesori pada penciptaan yang dimaksudkan. Di sisi lain, HumanoidDescription dapat mencakup skala humanoid dari BodyTypeScale, HeadScale, HeightScale, WidthScale, dan ProportionScale. Perhatikan skala yang diimpor tubuh dasar sehingga sesuai dengan skala yang diberikan kepada HumanoidDescription.

Sertakan aksesori

Jika menyertakan aksesori, seperti rambut, HumanoidDescription harus mencakup anak AccessoryDescription di mana:

Hasilkan token pembuatan avatar

AvatarCreationService:PromptCreateAvatarAsync() mengambil parameter ID Token Pembuatan Avatar. Token ini adalah kunci untuk ciptaan dari alam semesta Anda, dan dapat Anda gunakan untuk menetapkan harga pembuatan avatar dari pengalaman Anda. Untuk instruksi dan detail tambahan tentang menghasilkan token, lihat Token Pembuatan Avatar.

Setelah membeli dan menghasilkan token Anda, Anda dapat memeriksa token di Creator Hub untuk menemukan ID yang kemudian dapat Anda gunakan untuk API AvatarCreationService:PromptCreateAvatarAsync().

Tanggapi pemain yang bergabung dengan atribusi

Paket avatar yang dibuat di dalam pengalaman menyertakan tautan atribusi ke pengalaman asli tempat avatar tersebut dibuat. Jika avatar tersebut diperiksa oleh pemain lain, tampilan permintaan akan memberikan opsi untuk mengunjungi pengalaman di mana avatar tersebut dibuat.

Untuk menangani pemain yang bergabung dengan pengalaman Anda menggunakan tautan atribusi ini, gunakan Player:GetJoinData() dan analisis tabel yang dikembalikan untuk GameJoinContext.

GameJoinContext mencakup nilai tabel berikut:

©2026 Roblox Corporation. Roblox, logo Roblox, dan Powering Imagination termasuk dalam merek dagang kami yang terdaftar dan tidak terdaftar di AS dan negara lainnya.