體驗中的角色創建

*此內容是使用 AI(Beta 測試版)翻譯,可能含有錯誤。若要以英文檢視此頁面,請按一下這裡

您可以發布一個允許玩家實時創建、自定義和購買角色的體驗。當角色被購買時,這些自定義角色會直接保存在玩家的 Roblox 庫中,允許玩家在其他體驗中裝備和穿戴這些自定義角色。

實施體驗中角色創建的體驗擁有者可以同時作為角色項目的 創作者體驗擁有者 受益於 市場佣金。如果在體驗中創建的資產被檢查,該項目會提供鏈接到創建該資產的原始體驗。

您可以在 Roblox 的 角色創建器 演示中測試此功能。

如何實施體驗中的創建

使用以下指導和代碼參考來創建您的第一個體驗中角色創建項目。以下指令使用一個基礎身體 Model,玩家可以對其進行修改和自定義,然後再發布。

在開始之前,請熟悉以下內容:

  • 角色模型 — 以下實現需要導入符合 Roblox 的 15 部分規範的基礎身體。此 Model 是用戶進一步自定義和修改的基礎。
  • 角色創建令牌 — 實現角色創建的體驗至少需要一個創建令牌。這些令牌需要用 Robux 購買,並允許您設置在體驗中進行購買的價格和其他銷售設置。
  • API 類

導入基礎身體

基礎身體作為用戶可以自定義和編輯的初始基礎。您可以使用自己的 Model,或使用 導入工具 導入自定義資產並通過 角色設置 進行設置。

基礎身體必須遵守 Roblox 的角色規範,並且必須包括 15 個 MeshPart 實例,這些實例組成 6 個身體部位:頭部、軀幹、左臂、左腿、右臂和右腿,以及其他 角色部件

有關正確配置角色身體的參考和示例,請參閱 角色參考

實施編輯 API

要開發一個用戶可以在您的體驗中的角色上編輯 MeshPart 實例的系統,請使用 EditableImage 進行紋理編輯,使用 EditableMesh 進行網格編輯,以及使用 WrapDeformer 在網格編輯過程中保持蒙皮和 FACS 數據。

  1. 載入您的基礎身體後,使用以下腳本設置您的 EditableImagesEditableMeshesWrapDeformers

    local AssetService = game:GetService("AssetService")
    local function setupBodyPart(meshPart, wrapTarget)
    -- 創建並將 WrapDeformer 附加到 MeshPart
    local wrapDeformer = Instance.new("WrapDeformer")
    wrapDeformer.Parent = meshPart
    -- 為包圍目標的籠子網格創建可編輯網格
    local cageEditableMesh: EditableMesh =
    AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {
    FixedSize = true,
    })
    -- 將籠子網格分配給 WrapDeformer
    wrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))
    end
    local function setupRigidMesh(meshPart)
    -- 從原始 MeshPart 創建可編輯網格
    local editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {
    FixedSize = true,
    })
    -- 根據可編輯網格生成新的 MeshPart
    local newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))
    -- 從原始 MeshPart 複製大小、位置和紋理
    newMeshPart.Size = meshPart.Size
    newMeshPart.CFrame = meshPart.CFrame
    newMeshPart.TextureContent = meshPart.TextureContent
    -- 將新的 MeshPart 應用回原始
    meshPart:ApplyMesh(newMeshPart)
    end
    local function setupMeshTexture(meshPart, textureIdToEditableImageMap)
    -- 如果該 TextureID 已存在 EditableImage,則重用它,而不是創建新的
    if textureIdToEditableImageMap[meshPart.TextureID] then
    meshPart.TextureContent =
    Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])
    return
    end
    -- 創建新的 EditableImage 並將其應用為紋理內容
    local editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))
    textureIdToEditableImageMap[meshPart.TextureID] = editableImage
    meshPart.TextureContent = Content.fromObject(editableImage)
    end
    local function setupModel(model)
    -- 按紋理 ID 重用 EditableImage 實例的映射
    local textureIdToEditableImageMap = {}
    for _, descendant in model:GetDescendants() do
    if not descendant:IsA("MeshPart") then
    continue
    end
    -- 根據 WrapTarget 存在情況配置 MeshPart
    -- 如果存在 WrapTarget,則添加 WrapDeformer 子項,並帶有 EditableMesh
    -- 否則,直接將 EditableMesh 應用於 MeshPart
    local wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")
    if wrapTarget then
    setupBodyPart(descendant, wrapTarget)
    else
    setupRigidMesh(descendant)
    end
    -- 配置 MeshPart 的 EditableImage
    setupMeshTexture(descendant, textureIdToEditableImageMap)
    end
    end
  2. 創建 EditableImage 工具,允許玩家為您的基礎身體重新上色、繪畫或添加貼紙。您可以利用 DrawImage()DrawRectangle()WritePixelsBuffer() 等 API。

    • 對於高級變換,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
      )
      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. 使用 WrapDeformerEditableMesh 創建工具,以便在您的身體上編輯網格變形。

    1. WrapDeformer 處理顯示的 MeshPart 幾何形狀的實時變形,同時保持底層的蒙皮和 FACS 數據。

    2. EditableMesh 允許您修改 WrapDeformer 回應的籠子網格。

      1. 使用 WrapDeformer:SetCageMeshContent() 將表示相關籠子網格的 EditableMesh 實例應用於 WrapDeformer
      2. 使用 EditableMesh,例如 SetPosition(),變形頂點並編輯 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

創建創建提示

在設置好基礎身體和編輯 API 後,創建一個提示,讓用戶能夠使用 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 個身體部位的新資產 (HeadTorsoRightLegLeftLegRightArmLeftArm)。選擇性地,它還可以包括一個新的 Hair 配件。

為了支持這一點,HumanoidDescription 應該包括 6 個 BodyPartDescription 子項。每個 BodyPartDescription.Instance 屬性引用包含所有構成身體部位的 MeshPart 實例的 Folder。例如,LeftArm 文件夾包含 LeftHandLeftUpperArmLeftLowerArmMeshPartsBodyPartDescription.BodyPart 屬性也應設置為相關的 Enum.BodyPart

每個 15 個 MeshPart 的身體部位必須包括:

提供的 HumanoidDescription 不應包含任何預先存在的資產 ID 來表示預期創建的身體部位或配件。另一方面,HumanoidDescription 可能包括 BodyTypeScaleHeadScaleHeightScaleWidthScaleProportionScale 的人類比例。請注意基礎身體的比例應與提供給 HumanoidDescription 的比例相匹配。

包含配件

如果包含配件,例如頭髮,則 HumanoidDescription 應該包括一個子 AccessoryDescription,其中:

生成角色創建令牌

AvatarCreationService:PromptCreateAvatarAsync() 需要一個 角色創建令牌 ID 參數。此令牌是您宇宙中創建項目的關鍵,您可以用來設置來自您的體驗的角色創建價格。 有關生成令牌的說明和更多詳細信息,請參見 角色創建令牌

在購買並生成您的令牌後,您可以在創作者中心檢查該令牌以找到 ID,然後可以用於 AvatarCreationService:PromptCreateAvatarAsync() API。

根據歸因回應玩家加入

在體驗中創建的角色捆綁具有指向原始體驗的歸因鏈接,該體驗創建了角色。如果其他玩家檢查該角色,提示會顯示提供選項以訪問創建該角色的體驗。

要處理使用此歸因鏈接加入您的體驗的玩家,請使用 Player:GetJoinData() 並解析返回的表以獲得 GameJoinContext

GameJoinContext 包含以下表值:

©2026 Roblox Corporation、Roblox、Roblox 標誌及 Powering Imagination 是我們在美國及其他國家地區的部分註冊與未註冊商標。