Buat {itemType}
Monetisasi
Kebijakan dan Pedoman

Pembuatan avatar 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 untuk membuat, menyesuaikan, dan membeli tubuh avatar secara real time. Setelah dibeli, tubuh kustom ini disimpan langsung ke inventaris Roblox pemain, memungkinkan pemain untuk mengenakan dan memakai avatar kustom di pengalaman lainnya.

Pemilik pengalaman yang menerapkan pembuatan avatar dalam pengalaman mendapatkan manfaat dari komisi Marketplace sebagai pencipta item avatar dan pemilik pengalaman. Jika aset yang dibuat dalam pengalaman diperiksa, item tersebut menyediakan tautan ke pengalaman asli tempat avatar itu dibuat.

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

Cara menerapkan pembuatan dalam pengalaman

Gunakan instruksi dan referensi kode berikut untuk membuat proyek pembuatan avatar 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 pengimporan tubuh dasar yang memenuhi spesifikasi 15 bagian Roblox. Model ini berfungsi sebagai dasar untuk tambahan penyesuaian dan modifikasi pengguna.
    • Tubuh dasar harus memenuhi pedoman tubuh avatar Roblox, termasuk jumlah minimum kontrol FACS untuk pengaturan wajah.
  • Token pembuatan avatar — Pengalaman yang menerapkan pembuatan avatar memerlukan minimal satu token pembuatan. Token ini memerlukan Robux untuk dibeli dan memungkinkan Anda untuk menetapkan harga dan pengaturan penjualan lainnya untuk pembelian yang dilakukan dalam pengalaman.
  • Kelas API
    • AvatarCreationService — Menangani pengingat dan validasi pembuatan avatar.
    • EditableImage — Menangani pembuatan dan manipulasi tekstur pada waktu berjalan.
    • EditableMesh — Menangani manipulasi geometri mesh pada waktu berjalan.
    • WrapDeformer — Menangani manipulasi geometri kerangka luar yang tidak terlihat pada waktu berjalan yang memungkinkan karakter avatar untuk mengenakan pakaian 3D.

Impor tubuh dasar

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

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

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

Terapkan API pengeditan

Untuk mengembangkan sistem di mana pengguna dapat mengedit instansi MeshPart pada avatar dalam pengalaman Anda untuk pembuatan, gunakan EditableImage untuk pengeditan tekstur, EditableMesh untuk pengeditan mesh, dan WrapDeformer untuk mempertahankan data skinning dan 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 kandang dari target
    local cageEditableMesh: EditableMesh =
    AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {
    FixedSize = true,
    })
    -- Tetapkan konten mesh kandang 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 editable mesh
    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 ke 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 instansi EditableImage berdasarkan ID tekstur
    local textureIdToEditableImageMap = {}
    for _, descendant in model:GetDescendants() do
    if not descendant:IsA("MeshPart") then
    continue
    end
    -- Konfigurasi MeshPart berdasarkan kehadiran WrapTarget
    -- Jika WrapTarget ada, tambahkan anak WrapDeformer 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 pada tubuh dasar Anda. Anda dapat memanfaatkan API seperti DrawImage(), DrawRectangle(), WritePixelsBuffer().

    • Untuk transformasi lanjutan, DrawImageTransformed() memungkinkan Anda menentukan posisi, rotasi, dan skala saat menggambar satu EditableImage ke yang lain. Demikian juga, DrawImageProjected() bekerja seperti DrawImage() tetapi memproyeksikan gambar yang digambar dengan tepat jika instansi 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 data skinning dan FACS yang mendasari.

    2. EditableMesh memungkinkan Anda memodifikasi mesh kandang yang direspons oleh WrapDeformer.

      1. Gunakan WrapDeformer:SetCageMeshContent() untuk menerapkan instansi EditableMesh yang mewakili mesh kandang relevan ke WrapDeformer.
      2. Gunakan EditableMesh, seperti SetPosition(), untuk mendefinisikan ulang posisi dan mengedit bentuk dari 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 pengingat pembuatan

Setelah mengatur tubuh dasar Anda dan API pengeditan, buat pengingat untuk pengguna agar 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 menyertakan aset baru yang akan dibuat untuk masing-masing dari 6 bagian tubuh (Head, Torso, RightLeg, LeftLeg, RightArm, LeftArm). Secara opsional, itu juga dapat menyertakan aksesori baru Hair.

Untuk mendukung ini, HumanoidDescription harus menyertakan 6 anak BodyPartDescription. Setiap properti BodyPartDescription.Instance mereferensikan Folder yang menyertakan semua instansi MeshPart yang membentuk bagian tubuh. Misalnya, folder LeftArm berisi LeftHand, LeftUpperArm, dan LeftLowerArm MeshParts. Properti BodyPartDescription.BodyPart juga harus ditetapkan ke Enum.BodyPart yang relevan.

Setiap dari 15 bagian tubuh MeshPart harus menyertakan:

HumanoidDescription yang diberikan tidak boleh menyertakan ID aset yang sudah ada untuk mewakili bagian tubuh atau aksesori pada pembuatan yang dimaksud. Di sisi lain, HumanoidDescription dapat menyertakan skala humanoid dari BodyTypeScale, HeadScale, HeightScale, WidthScale, dan ProportionScale. Perhatikan skala yang digunakan tubuh dasar diimpor agar sesuai dengan skala yang diberikan ke HumanoidDescription.

Sertakan aksesori

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

Hasilkan token pembuatan avatar

AvatarCreationService:PromptCreateAvatarAsync() mengambil parameter ID Token Pembuatan Avatar. Token ini adalah kunci untuk kreasi dari alam semesta Anda, dan ini yang dapat Anda gunakan untuk menetapkan harga pembuatan avatar dari pengalaman Anda. Untuk instruksi dan rincian 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().

Tanggapan pemain yang bergabung melalui atribusi

Bundel avatar yang dibuat dalam pengalaman menyertakan tautan atribusi ke pengalaman asli di mana avatar tersebut dibuat. Jika avatar diperiksa oleh pemain lain, sebuah pengingat ditampilkan yang memberikan opsi untuk mengunjungi pengalaman tempat avatar itu 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.