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.
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 kerangka targetlocal cageEditableMesh: EditableMesh =AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {FixedSize = true,})-- Tetapkan mesh kerangka 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 mesh yang dapat dieditlocal 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 kembali ke yang 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 instance EditableImage berdasarkan ID teksturlocal textureIdToEditableImageMap = {}for _, descendant in model:GetDescendants() doif not descendant:IsA("MeshPart") thencontinueend-- Konfigurasi MeshPart berdasarkan keberadaan WrapTarget-- Jika WrapTarget ada, tambahkan WrapDeformer anak 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 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)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 skining dan data FACS yang mendasari.
EditableMesh memungkinkan Anda memodifikasi mesh kerangka yang diperoleh WrapDeformer.
- Gunakan WrapDeformer:SetCageMeshContent() untuk menerapkan instance EditableMesh yang mewakili mesh kerangka yang relevan ke WrapDeformer.
- 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.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 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:
- Sebuah EditableImage.
- Sebuah WrapDeformer dengan EditableMesh.
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:
- Properti AccessoryDescription.Instance merujuk ke instance Accessory.
- Properti AccessoryDescription.AccessoryType diatur ke Enum.AccessoryType yang relevan.
- Dalam hal menyertakan Enum.AccessoryType.Hair dalam penciptaan Anda, MeshPart harus menyertakan EditableImage. Namun, itu tidak boleh menyertakan anak WrapDeformer tetapi harus menyertakan EditableMesh yang diatur di MeshPart secara langsung.
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:
- 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