Utwórz: {itemType}
Monetyzacja

Tworzenie awatarów w grze

*Ta zawartość została przetłumaczona przy użyciu narzędzi AI (w wersji beta) i może zawierać błędy. Aby wyświetlić tę stronę w języku angielskim, kliknij tutaj.

Możesz opublikować doświadczenie, które pozwala graczom tworzyć, dostosowywać i kupować ciała awatarów w czasie rzeczywistym. Po zakupie te niestandardowe ciała zapisywane są bezpośrednio w inwentarzu Roblox gracza, co pozwala graczom na wyposażenie i noszenie niestandardowych awatarów w innych doświadczeniach.

Właściciele doświadczeń, którzy wdrażają tworzenie awatarów w doświadczeniu, korzystają z prowizji rynkowych jako zarówno twórca przedmiotu awatara, jak i właściciel doświadczenia. Jeśli aktyw wyprodukowany w doświadczeniu zostanie sprawdzony, przedmiot dostarcza link do oryginalnego doświadczenia, w którym został stworzony.

Możesz przetestować tworzenie awatarów w doświadczeniu na demonstracji Kreatora Awatarów w Robloxie.

Jak wdrożyć tworzenie w doświadczeniu

Użyj poniższych instrukcji i odniesień kodu, aby stworzyć swój pierwszy projekt tworzenia awatarów w doświadczeniu. Poniższe instrukcje wykorzystują podstawowe ciało Model, które gracze mogą modyfikować i dostosowywać przed opublikowaniem.

Przed rozpoczęciem, zaznajom się z następującymi:

  • Modele awatarów — Poniższa implementacja wymaga zaimportowania podstawowego ciała, które spełnia specyfikację 15 części Roblox. To Model służy jako podstawa do dodatkowej personalizacji i modyfikacji przez użytkowników.
  • Tokenu do tworzenia awatarów — Doświadczenia realizujące tworzenie awatarów wymagają co najmniej jednego tokenu do tworzenia. Te tokeny wymagają Robux do zakupu i pozwalają na ustalanie cen oraz innych ustawień sprzedaży dla zakupów dokonanych w doświadczeniu.
  • Klasy API
    • AvatarCreationService — Obsługuje żądania tworzenia awatarów i walidację.
    • EditableImage — Obsługuje tworzenie i manipulację teksturami w czasie rzeczywistym.
    • EditableMesh — Obsługuje manipulację geometrią siatki w czasie rzeczywistym.
    • WrapDeformer — Obsługuje manipulację niewidzialną geometrią zewnętrznej klatki, która pozwala postaciom awatarów używać 3D odzieży.

Importuj podstawowe ciało

Podstawowe ciało działa jako początkowa podstawa, którą użytkownicy mogą dostosowywać i edytować. Możesz użyć własnego Model lub zaimportować niestandardowy zasób za pomocą Importera i skonfigurować przez Ustawienia awatara.

Podstawowe ciała muszą przestrzegać specyfikacji awatarów Roblox i muszą zawierać komponenty takie jak 15 instancji MeshPart, które składają się na 6 części ciała: głowa, tors, lewy ramie, lewa noga, prawa ramie i prawa noga, a także inne komponenty awatarów.

Aby uzyskać odniesienia i próbki poprawnie skonfigurowanych ciał awatarów, zobacz Odniesienia do awatarów.

Wdrożenie edytowalnych API

Aby opracować system, w którym użytkownicy mogą edytować instancje MeshPart na awatarze w Twoim doświadczeniu, aby tworzyć niestandardowe modele, użyj EditableImage do edytowania tekstur, EditableMesh do edytowania siatek i WrapDeformer do utrzymywania danych o przypisaniu i FACS podczas edycji siatek.

  1. Po zaimportowaniu podstawowego ciała, użyj następującego skryptu, aby skonfigurować swoje EditableImages, EditableMeshes i WrapDeformers.


    local AssetService = game:GetService("AssetService")
    local function setupBodyPart(meshPart, wrapTarget)
    -- Tworzenie i dołączenie WrapDeformer do MeshPart
    local wrapDeformer = Instance.new("WrapDeformer")
    wrapDeformer.Parent = meshPart
    -- Tworzenie edytowalnej siatki dla siatki klatki celu
    local cageEditableMesh: EditableMesh =
    AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {
    FixedSize = true,
    })
    -- Przypisanie siatki klatki do WrapDeformer
    wrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))
    end
    local function setupRigidMesh(meshPart)
    -- Tworzenie edytowalnej siatki z oryginalnego MeshPart
    local editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {
    FixedSize = true,
    })
    -- Generowanie nowego MeshPart z edytowalnej siatki
    local newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))
    -- Kopiowanie rozmiaru, pozycji i tekstury z oryginalnego MeshPart
    newMeshPart.Size = meshPart.Size
    newMeshPart.CFrame = meshPart.CFrame
    newMeshPart.TextureContent = meshPart.TextureContent
    -- Zastosowanie nowego MeshPart z powrotem do oryginalnego
    meshPart:ApplyMesh(newMeshPart)
    end
    local function setupMeshTexture(meshPart, textureIdToEditableImageMap)
    -- Jeśli EditableImage już istnieje dla tego TextureID, użyj go zamiast tworzyć nowy
    if textureIdToEditableImageMap[meshPart.TextureID] then
    meshPart.TextureContent =
    Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])
    return
    end
    -- Tworzenie nowego EditableImage i zastosowanie go jako zawartości tekstury
    local editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))
    textureIdToEditableImageMap[meshPart.TextureID] = editableImage
    meshPart.TextureContent = Content.fromObject(editableImage)
    end
    local function setupModel(model)
    -- Mapowanie do ponownego użycia instancji EditableImage według ID tekstury
    local textureIdToEditableImageMap = {}
    for _, descendant in model:GetDescendants() do
    if not descendant:IsA("MeshPart") then
    continue
    end
    -- Konfigurowanie MeshPart w zależności od obecności WrapTarget
    -- Jeśli WrapTarget jest obecny, dodaj dziecko WrapDeformer z EditableMesh
    -- W przeciwnym razie, zastosuj EditableMesh bezpośrednio do MeshPart
    local wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")
    if wrapTarget then
    setupBodyPart(descendant, wrapTarget)
    else
    setupRigidMesh(descendant)
    end
    -- Konfigurowanie EditableImage dla MeshPart
    setupMeshTexture(descendant, textureIdToEditableImageMap)
    end
    end
  2. Stwórz narzędzia EditableImage, które pozwalają graczom na zmienianie kolorów, rysowanie lub dodawanie naklejek do podstawowego ciała. Możesz wykorzystać API takie jak DrawImage(), DrawRectangle(), WritePixelsBuffer().

    • Dla zaawansowanych transformacji, DrawImageTransformed() pozwala na określenie pozycji, rotacji i skali podczas rysowania jednego EditableImage na innym. Podobnie, DrawImageProjected() działa prawie jak DrawImage(), ale prawidłowo projecuje rysowany obraz, jeśli instancja EditableImage jest używana z 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. Używając WrapDeformer i EditableMesh, utwórz narzędzia do edytowania deformacji siatek w swoim ciele.

    1. WrapDeformer obsługuje żywe deformacje geometrii renderowanej MeshPart, zachowując przy tym dane o przypisaniu i FACS.

    2. EditableMesh pozwala na modyfikację siatki klatki, na którą reaguje WrapDeformer.

      1. Użyj WrapDeformer:SetCageMeshContent(), aby zastosować instancję EditableMesh, która reprezentuje odpowiednią siatkę klatki do WrapDeformer.
      2. Użyj EditableMesh, na przykład SetPosition(), aby deformować wierzchołki i edytować kształt 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

Stwórz zachętę do tworzenia

Po skonfigurowaniu podstawowego ciała i edytowalnych API, stwórz zachętę dla użytkowników do tworzenia i zakupu z doświadczenia za pomocą AvatarCreationService:PromptCreateAvatarAsync().


export type BodyPartInfo = {
bodyPart: Enum.BodyPart,
instance: Instance --Folder z utworzonymi 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("Pomyślnie przesłano z BundleId: ", bundleIdOrErrorMessage)
print("Pomyślnie przesłano z OutfitId: ", outfitId)
else
print("Niepowodzenie przesłania z komunikatem o błędzie:", bundleIdOrErrorMessage)
end
else
print("Tworzenie awatara nieudane")
end
end

AvatarCreationService:PromptCreateAvatarAsync() przyjmuje parametr HumanoidDescription, aby reprezentować awatar przeznaczony do zakupu lub tworzenia. W przypadku tworzenia awatara opis HumanoidDescription postaci musi zawierać nowe aktywa, które mają być utworzone dla każdej z 6 części ciała (Głowa, Tors, PrawaNoga, LewaNoga, PrawaRęka, LewaRęka). Opcjonalnie może także zawierać nowy akcesorium Włosy.

Aby to wspierać, HumanoidDescription powinien zawierać 6 dzieci typu BodyPartDescription. Każda właściwość BodyPartDescription.Instance odnosi się do Folder, która zawiera wszystkie instancje MeshPart składające się na część ciała. Na przykład folder LewaRęka zawiera LewaDłoń, LewaGórnaRęka i LewaDolaRęka MeshParts. Właściwość BodyPartDescription.BodyPart powinna być również ustawiona na odpowiedni Enum.BodyPart.

Każda z 15 części ciała MeshPart musi zawierać:

Dostarczony opis HumanoidDescription nie powinien zawierać żadnych ID aktywów, które już istnieją, aby reprezentować części ciała lub akcesoria w zamierzonym utworze. Z drugiej strony opis HumanoidDescription może zawierać skale humanoidalne BodyTypeScale, HeadScale, HeightScale, WidthScale, oraz ProportionScale. Uważaj na skale, z jakimi zaimportowane jest podstawowe ciało, aby były zgodne z tymi, które zostały dostarczone do HumanoidDescription.

Dołącz akcesoria

Jeśli dołączasz akcesorium, takie jak włosy, opis HumanoidDescription powinien zawierać dziecko AccessoryDescription, w którym:

Generuj token do tworzenia awatarów

AvatarCreationService:PromptCreateAvatarAsync() przyjmuje parametr ID tokenu do tworzenia awatarów. Ten token jest kluczem do tworzenia z Twojego wszechświata i to jest to, czego możesz użyć do ustawienia ceny tworzenia awatarów z Twojego doświadczenia. Aby uzyskać instrukcje i dodatkowe szczegóły dotyczące generowania tokenów, zobacz Tokeny do tworzenia awatarów.

Po zakupie i wygenerowaniu tokenu, możesz sprawdzić token w Centrum Twórcy, aby znaleźć ID, które możesz następnie wykorzystać do API AvatarCreationService:PromptCreateAvatarAsync().

Odpowiedz na dołączanie graczy przez atrybucję

Zestawy awatarów tworzone w doświadczeniu zawierają link atrybucji do oryginalnego doświadczenia, w którym awatar został stworzony. Jeśli awatar zostanie sprawdzony przez innego gracza, zostanie wyświetlony monit z opcją odwiedzenia doświadczenia, w którym awatar został stworzony.

Aby obsłużyć graczy dołączających do Twojego doświadczenia za pomocą tego linku atrybucji, użyj Player:GetJoinData() i przeanalizuj zwróconą tabelę pod kątem GameJoinContext.

GameJoinContext zawiera następujące wartości tabeli:

©2026 Roblox Corporation. Nazwa Roblox, logo Roblox oraz hasło „Powering Imagination” należą do naszych zarejestrowanych i niezarejestrowanych znaków towarowych na terenie Stanów Zjednoczonych oraz w innych krajach.