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.
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 MeshPartlocal wrapDeformer = Instance.new("WrapDeformer")wrapDeformer.Parent = meshPart-- Buat mesh yang dapat diedit untuk mesh kandang dari targetlocal cageEditableMesh: EditableMesh =AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {FixedSize = true,})-- Tetapkan konten mesh kandang ke WrapDeformerwrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))endlocal function setupRigidMesh(meshPart)-- Buat mesh yang dapat diedit dari MeshPart aslilocal editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {FixedSize = true,})-- Hasilkan MeshPart baru dari editable meshlocal newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))-- Salin ukuran, posisi, dan tekstur dari MeshPart aslinewMeshPart.Size = meshPart.SizenewMeshPart.CFrame = meshPart.CFramenewMeshPart.TextureContent = meshPart.TextureContent-- Terapkan MeshPart baru ke aslimeshPart:ApplyMesh(newMeshPart)endlocal function setupMeshTexture(meshPart, textureIdToEditableImageMap)-- Jika EditableImage sudah ada untuk TextureID ini, gunakan kembali daripada membuat yang baruif textureIdToEditableImageMap[meshPart.TextureID] thenmeshPart.TextureContent =Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])returnend-- Buat EditableImage baru dan terapkan sebagai konten teksturlocal editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))textureIdToEditableImageMap[meshPart.TextureID] = editableImagemeshPart.TextureContent = Content.fromObject(editableImage)endlocal function setupModel(model)-- Peta untuk menggunakan kembali instansi EditableImage berdasarkan ID teksturlocal textureIdToEditableImageMap = {}for _, descendant in model:GetDescendants() doif not descendant:IsA("MeshPart") thencontinueend-- Konfigurasi MeshPart berdasarkan kehadiran WrapTarget-- Jika WrapTarget ada, tambahkan anak WrapDeformer dengan EditableMesh-- Jika tidak, terapkan EditableMesh langsung ke MeshPartlocal wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")if wrapTarget thensetupBodyPart(descendant, wrapTarget)elsesetupRigidMesh(descendant)end-- Konfigurasi EditableImage untuk MeshPartsetupMeshTexture(descendant, textureIdToEditableImageMap)endendBuat 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)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
Menggunakan WrapDeformer dan EditableMesh, buat alat untuk mengedit deformasi mesh pada tubuh Anda.
WrapDeformer menangani deformasi langsung dari geometri MeshPart yang dirender sambil mempertahankan data skinning dan FACS yang mendasari.
EditableMesh memungkinkan Anda memodifikasi mesh kandang yang direspons oleh WrapDeformer.
- Gunakan WrapDeformer:SetCageMeshContent() untuk menerapkan instansi EditableMesh yang mewakili mesh kandang relevan ke WrapDeformer.
- 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.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
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
endAvatarCreationService: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:
- Sebuah EditableImage.
- Sebuah WrapDeformer dengan EditableMesh.
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:
- Properti AccessoryDescription.Instance mereferensikan instansi Accessory.
- Properti AccessoryDescription.AccessoryType di atur ke Enum.AccessoryType yang relevan.
- Dalam hal termasuk Enum.AccessoryType.Hair dalam kreasi Anda, MeshPart harus menyertakan EditableImage. Namun, ia tidak boleh menyertakan anak WrapDeformer tetapi harus menyertakan EditableMesh yang diterapkan pada MeshPart secara langsung.
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:
- JoinSource — Enum.JoinSource
- Seorang Player yang bergabung dengan pengalaman Anda dari tautan atribusi ini akan memiliki Enum.JoinSource.CreatedItemAttribution untuk menunjukkan masuk dari item yang dibuat.
- ItemType — opsional Enum.AvatarItemType
- AssetId — opsional string
- OutfitId — opsional string
- AssetType — opsional Enum.AssetType