建立{itemType}
Accelerate
營利

體驗中的角色創建

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

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

實施體驗內角色創建的體驗擁有者可以在作為角色物品的 創作者體驗擁有者 之間受益於 市場手續費。如果體驗內創建的資產被檢查,該物品會提供一個鏈接,指向其創建的原始體驗。

您可以在 Roblox 的 角色創建者 演示中測試體驗內創建。

如何實施體驗內創建

使用以下說明和代碼參考來創建您的第一個體驗內角色創建項目。以下說明使用一個基礎身體 Model,玩家可以在發布前對其進行修改和自訂。

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

  • 角色模型 — 以下實施需要導入符合 Roblox 15 部件規範的基礎身體。此 Model 作為其他用戶自訂和修改的基礎。
    • 基礎身體必須符合 Roblox 的 角色身體指南,包括臉部裝配的 FACS 控制的最小數量。
  • 角色創建令牌 — 實施角色創建的體驗需要至少一個創建令牌。這些令牌需要用 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)
    -- 為 MeshPart 創建並附加 WrapDeformer
    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)
    -- 重新使用 EditableImage 實例的紋理 ID 地圖
    local textureIdToEditableImageMap = {}
    for _, descendant in model:GetDescendants() do
    if not descendant:IsA("MeshPart") then
    continue
    end
    -- 根據 WrapTarget 的存在配置 MeshPart
    -- 如果存在 WrapTarget,則添加一個帶有 EditableMesh 的 WrapDeformer 子項
    -- 否則,直接將 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 屬性都引用一個 Folder,其中包含構成身體部件的所有 MeshPart 實例。例如,LeftArm 資料夾包含 LeftHandLeftUpperArmLeftLowerArmMeshPartsBodyPartDescription.BodyPart 屬性也應設置為相關的 Enum.BodyPart

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

提供的 HumanoidDescription 不應包含任何現有資產 ID 來表示意圖創建的身體部件或配件。另一方面,HumanoidDescription 可以包括 BodyTypeScaleHeadScaleHeightScaleWidthScaleProportionScale 的人類比例。請注意,導入基礎身體時,這些比例應與提供給 HumanoidDescription 的比例匹配。

包含配件

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

生成角色創建令牌

AvatarCreationService:PromptCreateAvatarAsync() 接受 角色創建令牌 ID 參數。這個令牌是您宇宙中創建的鑰匙,您可以用它來設置體驗中的角色創建價格。欲了解生成令牌的指導和更多詳細信息,請參見 角色創建令牌

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

通過歸屬響應玩家加入

在體驗中創建的角色捆綁包包含指向創建該角色的原始體驗的歸屬鏈接。如果另一個玩家檢查該角色,則彈出提示並提供訪問創建該角色的體驗的選項。

要使用該歸屬鏈接處理玩家加載您的體驗,請使用 Player:GetJoinData() 並解析返回的表以獲取 GameJoinContext

GameJoinContext 包括以下表值:

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