คุณสามารถเผยแพร่ประสบการณ์ที่อนุญาตให้ผู้เล่นสร้าง ปรับแต่ง และซื้อร่างกายอวตารแบบเรียลไทม์ เมื่อซื้อ ร่างกายที่ปรับแต่งเหล่านี้จะบันทึกโดยตรงไปยังคลังของ Roblox ของผู้เล่น ช่วยให้ผู้เล่นสามารถติดตั้งและสวมใส่อวตารที่กำหนดเองในประสบการณ์อื่นๆ ได้
เจ้าของประสบการณ์ที่Implementการสร้างอวตารในประสบการณ์จะได้รับประโยชน์จาก ค่าคอมมิชชั่นตลาด ในฐานะผู้ สร้าง รายการอวตารและ เจ้าของประสบการณ์ หากสินทรัพย์ที่สร้างในประสบการณ์ถูกตรวจสอบ รายการนั้นจะให้ลิงก์ไปยังประสบการณ์ดั้งเดิมที่ถูกสร้างขึ้น
คุณสามารถทดสอบการสร้างในประสบการณ์ใน Avatar Creator ของ Roblox
วิธีการImplementการสร้างในประสบการณ์
ใช้คำแนะนำและการอ้างอิงโค้ดต่อไปนี้เพื่อสร้างโครงการสร้างอวตารในประสบการณ์ครั้งแรกของคุณ คำแนะนำต่อไปนี้ใช้ร่างกายพื้นฐาน Model ที่ผู้เล่นสามารถปรับแต่งและแก้ไขได้ก่อนที่จะเผยแพร่
ก่อนเริ่มต้น ให้คุ้นเคยกับสิ่งต่อไปนี้:
- โมเดลอวตาร — การImplementต่อไปนี้ต้องมีการนำเข้าร่างกายพื้นฐานที่ตรงตามข้อกำหนด 15 ส่วนของ Roblox ร่างกาย Model นี้ทำหน้าที่เป็นพื้นฐานสำหรับการปรับแต่งและแก้ไขเพิ่มเติมของผู้ใช้
- ร่างกายพื้นฐานจะต้องตรงตาม แนวทางอวตาร ของ Roblox รวมถึงจำนวนการควบคุม FACS ขั้นต่ำสำหรับการตั้งค่าหน้าตา
- โทเค็นการสร้างอวตาร — ประสบการณ์ที่Implementการสร้างอวตารจำเป็นต้องมีโทเค็นการสร้างอย่างน้อยหนึ่งอัน โทเค็นเหล่านี้ต้องใช้ Robux เพื่อซื้อและอนุญาตให้คุณตั้งราคาและการตั้งค่าการขายอื่นๆ สำหรับการซื้อที่ทำในประสบการณ์
- คลาส API
- AvatarCreationService — จัดการการกระตุ้นและการตรวจสอบการสร้างอวตาร
- EditableImage — จัดการการสร้างและการจัดการพื้นผิวในเวลารัน
- EditableMesh — จัดการการปรับเปลี่ยนเรขาคณิตของเมชในเวลารัน
- WrapDeformer — จัดการการปรับเปลี่ยนเรขาคณิตของกรงภายนอกที่มองไม่เห็นในเวลารันที่อนุญาตให้ตัวละครอวตารติดตั้ง เสื้อผ้า 3D
นำเข้าร่างกายพื้นฐาน
ร่างกายพื้นฐานทำหน้าที่เป็นพื้นฐานเริ่มต้นซึ่งผู้ใช้สามารถปรับแต่งและแก้ไขได้ คุณสามารถใช้ Model ของคุณเอง หรือนำเข้าสินทรัพย์ที่กำหนดเองด้วย Importer และตั้งค่าได้ผ่าน Avatar Setup
ร่างกายพื้นฐานจะต้องปฏิบัติตามข้อกำหนดของอวตาร Roblox และจะต้องรวมถึงส่วนประกอบเช่นส่วน MeshPart 15 ส่วนที่ประกอบขึ้นเป็น 6 ร่างกาย: หัว, ทรวงอก, แขนซ้าย, ขาซ้าย, แขนขวา และขาขวา รวมถึงส่วนประกอบอื่นๆ อวตาร
สำหรับการอ้างอิงและตัวอย่างของร่างกายอวตารที่ตั้งค่าถูกต้อง ดูที่ การอ้างอิงอวตาร
Implement APIs การแก้ไข
เพื่อพัฒนาระบบที่ผู้ใช้สามารถแก้ไข MeshPart บนร่างกายในประสบการณ์ของคุณสำหรับการสร้าง ให้ใช้ EditableImage สำหรับการแก้ไขพื้นผิว, EditableMesh สำหรับการแก้ไขเมช, และ WrapDeformer สำหรับการรักษาข้อมูลการผสมผสานและ FACS ระหว่างการแก้ไขเมช
หลังจากนำเข้าร่างกายพื้นฐานแล้ว ใช้สคริปต์ต่อไปนี้ในการตั้งค่า EditableImages, EditableMeshes, และ WrapDeformers ของคุณ
local AssetService = game:GetService("AssetService")local function setupBodyPart(meshPart, wrapTarget)-- สร้างและแนบ WrapDeformer ไปยัง MeshPartlocal 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)-- สร้างเมชที่สามารถแก้ไขได้จาก MeshPart ดั้งเดิมlocal editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {FixedSize = true,})-- สร้าง MeshPart ใหม่จาก mesh ที่สามารถแก้ไขได้local newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))-- คัดลอกขนาด ตำแหน่ง และพื้นผิวจาก MeshPart ดั้งเดิมnewMeshPart.Size = meshPart.SizenewMeshPart.CFrame = meshPart.CFramenewMeshPart.TextureContent = meshPart.TextureContent-- ใช้ MeshPart ใหม่กลับไปยังต้นฉบับ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 ซ้ำตาม Texture IDlocal 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 ที่อนุญาตให้ผู้เล่นเปลี่ยนสี วาด หรือเพิ่มสติกเกอร์ไปยังร่างกายพื้นฐานของคุณ คุณสามารถใช้ APIs เช่น 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 --Folder with 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("อัปโหลดสำเร็จด้วย BundleId: ", bundleIdOrErrorMessage)
print("อัปโหลดสำเร็จด้วย OutfitId: ", outfitId)
else
print("อัปโหลดไม่สำเร็จด้วยข้อความแสดงข้อผิดพลาด:", bundleIdOrErrorMessage)
end
else
print("การสร้างอวตารไม่สำเร็จ")
end
endAvatarCreationService: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 ที่ให้มาจะไม่ควรรวม IDs สินทรัพย์เดิมใดๆ เพื่อแสดงถึงร่างกายหรืออุปกรณ์เสริมในการสร้างที่ตั้งใจไว้ ในอีกด้านหนึ่ง 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() รับพารามิเตอร์ 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