คุณสามารถเผยแพร่ประสบการณ์ที่อนุญาตให้ผู้เล่นสร้าง ปรับแต่ง และซื้อร่างกายอวาตาร์แบบเรียลไทม์ เมื่อมีการซื้อ ร่างกายที่ปรับแต่งเหล่านี้จะถูกบันทึกโดยตรงไปยังอินเวนทอรี Roblox ของผู้เล่น ทำให้ผู้เล่นสามารถสวมใส่และสวมใส่อวาตาร์ที่ปรับแต่งในประสบการณ์อื่น ๆ
เจ้าของประสบการณ์ที่ดำเนินการสร้างอวาตาร์ในประสบการณ์จะได้รับประโยชน์จาก ค่าคอมมิชชั่นตลาด ในฐานะ ผู้สร้าง ของรายการอวาตาร์และ เจ้าของประสบการณ์ หากสินทรัพย์ที่สร้างในประสบการณ์ถูกตรวจสอบ รายการจะให้ลิงค์ไปยังประสบการณ์ต้นฉบับที่ถูกสร้างขึ้น
คุณสามารถทดสอบการสร้างในประสบการณ์ใน Avatar Creator ของ Roblox
วิธีการดำเนินการสร้างในประสบการณ์
ใช้คำแนะนำและการอ้างอิงโค้ดต่อไปนี้เพื่อสร้างโปรเจ็กต์การสร้างอวาตาร์ในประสบการณ์ครั้งแรกของคุณ คำแนะนำต่อไปนี้ใช้ร่างกายพื้นฐาน Model ที่ผู้เล่นสามารถปรับแต่งและปรับแก้ก่อนเผยแพร่
ก่อนเริ่มต้น ให้คุณทำความคุ้นเคยกับสิ่งต่อไปนี้:
- โมเดลอวาตาร์ — การดำเนินการต่อไปนี้ต้องใช้การนำเข้าร่างกายพื้นฐานที่ตรงตามข้อกำหนด 15 ชิ้นของ Roblox โมเดล Model นี้จะทำหน้าที่เป็นพื้นฐานสำหรับการปรับแต่งและการแก้ไขเพิ่มเติมของผู้ใช้
- ร่างกายพื้นฐานต้องตรงตาม แนวทางการสร้างร่างกายอวาตาร์ ของ Roblox รวมถึงจำนวนขั้นต่ำของ FACS ที่ใช้ควบคุมการวางตำแหน่งใบหน้า
- โทเค็นการสร้างอวาตาร์ — ประสบการณ์ที่ดำเนินการสร้างอวาตาร์ต้องมีโทเค็นอย่างน้อยหนึ่งโทเค็น โทเค็นเหล่านี้ต้องใช้ Robux ในการซื้อและอนุญาตให้คุณตั้งราคาและการตั้งค่าการขายอื่น ๆ สำหรับการซื้อที่ทำในประสบการณ์
- คลาส API
- AvatarCreationService — จัดการการกระตุ้นและการตรวจสอบการสร้างอวาตาร์
- EditableImage — จัดการการสร้างและการปรับแต่งพื้นผิวในระหว่างการทำงาน
- EditableMesh — จัดการการปรับแต่งรูปทรงของเมชในระหว่างการทำงาน
- WrapDeformer — จัดการการปรับแต่งเรขาคณิตของกรงที่มองไม่เห็นในระหว่างการทำงานซึ่งอนุญาตให้ตัวละครอวาตาร์สวมใส่ เสื้อผ้า 3D
นำเข้าร่างกายพื้นฐาน
ร่างกายพื้นฐานทำหน้าที่เป็นรากฐานเริ่มต้นที่ผู้ใช้สามารถปรับแต่งและแก้ไขได้ คุณสามารถใช้ Model ของคุณเอง หรือ นำเข้าทรัพย์สินที่กำหนดเองด้วย Importer และตั้งค่าผ่าน Avatar Setup
ร่างกายพื้นฐานต้องปฏิบัติตามสเปคอวาตาร์ของ Roblox และต้องประกอบด้วยส่วนประกอบต่าง ๆ เช่น 15 MeshPart ที่ประกอบขึ้นเป็น 6 ส่วนของร่างกาย: หัว ช่วงลำตัว แขนซ้าย ขาซ้าย แขนขวา และขาขวา รวมถึงส่วนประกอบอื่น ๆ ของอวาตาร์
สำหรับการอ้างอิงและตัวอย่างของร่างกายอวาตาร์ที่ถูกกำหนดค่าอย่างถูกต้อง โปรดดูที่ การอ้างอิงอวาตาร์
ดำเนินการ APIs การแก้ไข
เพื่อพัฒนาระบบที่ผู้ใช้สามารถแก้ไข MeshPart บนตัวละครอวาตาร์ในประสบการณ์ของคุณสำหรับการสร้าง ใช้ EditableImage สำหรับการแก้ไขพื้นผิว EditableMesh สำหรับการแก้ไขเมช และ WrapDeformer สำหรับการรักษาข้อมูลสกินและ FACS ในระหว่างการแก้ไขเมช
หลังจากนำเข้าร่างกายพื้นฐานของคุณแล้ว ใช้สคริปต์ต่อไปนี้เพื่อจัดตั้ง EditableImages EditableMeshes และ WrapDeformers
local AssetService = game:GetService("AssetService")local function setupBodyPart(meshPart, wrapTarget)-- สร้างและแนบ WrapDeformer ไปยังเมชพาร์ตlocal wrapDeformer = Instance.new("WrapDeformer")wrapDeformer.Parent = meshPart-- สร้างเมชที่แก้ไขได้สำหรับกรงกรณีของเป้าหมายlocal cageEditableMesh: EditableMesh =AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {FixedSize = true,})-- กำหนดเมชกรงให้กับ WrapDeformerwrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))endlocal function setupRigidMesh(meshPart)-- สร้างเมชที่แก้ไขได้จากเมชพาร์ตต้นฉบับlocal editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {FixedSize = true,})-- สร้างเมชพาร์ตใหม่จากเมชที่แก้ไขได้local newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))-- คัดลอกขนาด ตำแหน่ง และพื้นผิวจากเมชพาร์ตต้นฉบับnewMeshPart.Size = meshPart.SizenewMeshPart.CFrame = meshPart.CFramenewMeshPart.TextureContent = meshPart.TextureContent-- นำเมชพาร์ตใหม่ไปยังต้นฉบับmeshPart:ApplyMesh(newMeshPart)endlocal function setupMeshTexture(meshPart, textureIdToEditableImageMap)-- หาก EditableImage มีอยู่แล้วสำหรับ TextureID นี้ ให้ใช้มันแทนการสร้างใหม่if textureIdToEditableImageMap[meshPart.TextureID] thenmeshPart.TextureContent =Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])returnend-- สร้าง EditableImage ใหม่และใช้เป็นเนื้อหาพื้นผิวlocal editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))textureIdToEditableImageMap[meshPart.TextureID] = editableImagemeshPart.TextureContent = Content.fromObject(editableImage)endlocal function setupModel(model)-- แผนที่สำหรับการใช้ซ้ำอินสแตนซ์ EditableImage โดย ID ของพื้นผิวlocal textureIdToEditableImageMap = {}for _, descendant in model:GetDescendants() doif not descendant:IsA("MeshPart") thencontinueend-- กำหนดค่า MeshPart ตามการมีอยู่ของ WrapTarget-- หาก WrapTarget มีอยู่ ให้เพิ่ม WrapDeformer ที่มี EditableMesh-- มิฉะนั้น ให้ใช้ EditableMesh กับ MeshPart โดยตรงlocal wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")if wrapTarget thensetupBodyPart(descendant, wrapTarget)elsesetupRigidMesh(descendant)end-- กำหนดค่า EditableImage สำหรับ MeshPartsetupMeshTexture(descendant, textureIdToEditableImageMap)endendสร้างเครื่องมือ EditableImage ที่อนุญาตให้ผู้เล่นเปลี่ยนสี วาดภาพ หรือเพิ่มสติกเกอร์ไปยังร่างกายพื้นฐานของคุณ คุณสามารถใช้ API เช่น DrawImage(), DrawRectangle(), WritePixelsBuffer()
สำหรับการเปลี่ยนแปลงที่ซับซ้อน DrawImageTransformed() ช่วยให้คุณสามารถกำหนดตำแหน่ง หมุน และขนาดเมื่อวาด EditableImage หนึ่งลงบนอีกอันหนึ่ง ได้อย่างคล้ายคลึงกัน DrawImageProjected() จะทำงานคล้ายกับ DrawImage() แต่โปรเจคภาพที่ถูกวาดอย่างถูกต้องหากอินสแตนซ์ EditableImage ถูกใช้ร่วมกับ 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
ใช้ WrapDeformer และ EditableMesh สร้างเครื่องมือสำหรับการเปลี่ยนแปลงโครงสร้างเมชของร่างกายคุณ
WrapDeformer จัดการการเปลี่ยนแปลงแบบสดของเรขาคณิต MeshPart ในขณะที่รักษาข้อมูลสกินและ FACS ที่อยู่ใต้
EditableMesh ช่วยให้คุณปรับเปลี่ยนกรงเมชที่ WrapDeformer ตอบสนองได้
- ใช้ WrapDeformer:SetCageMeshContent() เพื่อใช้ EditableMesh ที่แทนที่กรงเมชที่เกี่ยวข้องกับ WrapDeformer
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
สร้างการกระตุ้นการสร้าง
หลังจากตั้งค่าร่างกายพื้นฐานและ APIs การแก้ไขแล้ว สร้างการกระตุ้นให้ผู้ใช้สร้างและซื้อจากประสบการณ์โดยใช้ AvatarCreationService:PromptCreateAvatarAsync()
export type BodyPartInfo = {
bodyPart: Enum.BodyPart,
instance: Instance --โฟลเดอร์ที่มี 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("อัปโหลดสำเร็จด้วย BundleId: ", bundleIdOrErrorMessage)
print("อัปโหลดสำเร็จด้วย OutfitId: ", outfitId)
else
print("อัปโหลดไม่สำเร็จด้วยข้อความแสดงความผิดพลาด:", bundleIdOrErrorMessage)
end
else
print("การสร้างอวาตาร์ไม่สำเร็จ")
end
end
AvatarCreationService:PromptCreateAvatarAsync() ใช้พารามิเตอร์ HumanoidDescription เพื่อแทนที่อวาตาร์ที่ตั้งใจจะซื้อหรือสร้าง สำหรับการสร้างอวาตาร์ HumanoidDescription ของตัวละครต้องรวมถึงสินทรัพย์ใหม่ที่สร้างขึ้นสำหรับแต่ละ 6 ส่วนของร่างกาย (Head, Torso, RightLeg, LeftLeg, RightArm, LeftArm). นอกจากนี้ยังอาจรวมถึงอุปกรณ์เสริมใหม่ Hair ได้อีกด้วย
เพื่อรองรับสิ่งนี้ HumanoidDescription ควรรวมถึงลูก 6 ชิ้น BodyPartDescription คุณสมบัติ BodyPartDescription.Instance อ้างอิงถึง Folder ซึ่งรวมถึงอินสแตนซ์ MeshPart ทั้งหมดที่ประกอบกันเป็นส่วนของร่างกาย ตัวอย่างเช่น โฟลเดอร์ LeftArm จะมี LeftHand, LeftUpperArm และ LeftLowerArm MeshParts คุณสมบัติ BodyPartDescription.BodyPart ควรตั้งค่าให้ตรงกับ Enum.BodyPart ที่เกี่ยวข้อง
แต่ละ 15 MeshPart ของร่างกายจะต้องมี:
- WrapDeformer ที่มี EditableMesh.
HumanoidDescription ที่จัดเตรียมไม่ควรรวมถึง ID สินทรัพย์ที่มีอยู่แล้วเพื่อแทนที่ส่วนของร่างกายหรืออุปกรณ์เสริมที่ตั้งใจจะสร้าง ในทางกลับกัน HumanoidDescription อาจรวมถึงมาตราส่วนของมนุษย์ BodyTypeScale, HeadScale, HeightScale, WidthScale, และ ProportionScale. ต้องคำนึงถึงการปรับขนาดที่ร่างกายพื้นฐานถูกนำเข้ามาด้วยเพื่อให้ตรงกับการปรับขนาดที่จัดเตรียมไว้สำหรับ HumanoidDescription

รวมอุปกรณ์เสริม
หากรวมอุปกรณ์เสริม เช่น ผม คุณสมบัติ HumanoidDescription ควรรวมถึง AccessoryDescription ลูกที่มี:
- คุณสมบัติ AccessoryDescription.Instance อ้างอิงถึง อินสแตนซ์ Accessory.
- คุณสมบัติ AccessoryDescription.AccessoryType จะ ตั้งค่าให้ตรงกับ Enum.AccessoryType ที่เกี่ยวข้อง
- ถ้ารวม Enum.AccessoryType.Hair ในการสร้างของคุณ MeshPart ควรรวม EditableImage ได้ อย่างไรก็ตาม มันไม่ควรรวมถึงลูก WrapDeformer แต่ควรรวมถึง EditableMesh ที่ตั้งค่าสำหรับ MeshPart โดยตรง
สร้างโทเค็นการสร้างอวาตาร์
AvatarCreationService:PromptCreateAvatarAsync() ใช้พารามิเตอร์ Avatar Creation Token ID โทเค็นนี้เป็นกุญแจสำหรับการสร้างจากจักรวาลของคุณ และเป็นสิ่งที่คุณสามารถใช้เพื่อตั้งราคาในการสร้างอวาตาร์จากประสบการณ์ของคุณ สำหรับคำแนะนำและรายละเอียดเพิ่มเติมเกี่ยวกับการสร้างโทเค็น โปรดดูที่ โทเค็นการสร้างอวาตาร์
หลังจากซื้อและสร้างโทเค็นของคุณ คุณสามารถตรวจสอบโทเค็นใน Creator Hub เพื่อค้นหา ID ซึ่งคุณสามารถใช้สำหรับ API AvatarCreationService:PromptCreateAvatarAsync()

ตอบสนองต่อผู้เล่นที่เข้าร่วมด้วยการระบุ
ชุดอวาตาร์ที่สร้างในประสบการณ์รวมถึงลิงก์การให้เครดิตไปยังประสบการณ์ต้นฉบับที่สร้างอวาตาร์ หากอวาตาร์ถูกตรวจสอบโดยผู้เล่นคนอื่น ข้อความแจ้งเตือนจะปรากฏขึ้นเพื่อให้เลือกไปยังประสบการณ์ที่อวาตาร์ถูกสร้างขึ้น

เพื่อจัดการผู้เล่นที่เข้าร่วมประสบการณ์ของคุณโดยใช้ลิงก์การให้เครดิตนี้ ใช้ Player:GetJoinData() และแยกตารางที่ส่งคืนสำหรับ GameJoinContext
GameJoinContext รวมถึงค่าตารางต่อไปนี้:
- JoinSource — Enum.JoinSource
- ผู้เล่น Player ที่เข้าร่วมประสบการณ์ของคุณจากลิงก์การให้เครดิตนี้จะมี Enum.JoinSource.CreatedItemAttribution เพื่อระบุการเข้าร่วมจากรายการที่สร้างขึ้น
- ItemType — Enum.AvatarItemType (ออปชัน)
- AssetId — string (ออปชัน)
- OutfitId — string (ออปชัน)
- AssetType — Enum.AssetType (ออปชัน)