Możesz opublikować doświadczenie, które pozwala graczom tworzyć, dostosowywać i kupować ciała awatara w czasie rzeczywistym.Po zakupie te niestandardowe ciała są zapisywane bezpośrednio w wyposażeniegracza w Roblox, co pozwala graczom wyposażać i nosić niestandardowe awatary w innych doświadczeniach.
Właściciele doświadczeń, którzy wdrażają tworzenie awatara w doświadczeniu, korzystają z opłat za rynek jako zarówno twórca przedmiotu awatara, jak i właściciel doświadczenia .Jeśli zasób utworzony w doświadczeniu zostanie sprawdzony, przedmiot zapewnia link do oryginalnego doświadczenia, w którym został utworzony.
Możesz przetestować tworzenie w doświadczeniu w demokracji Roblox'a Twórca awatara.
Jak wdrożyć tworzenie w dzieło
Użyj następujących instrukcji i odniesień kodu, aby stworzyć swój pierwszy projekt tworzenia awatara w doświadczeniu.Następujące instrukcje wykorzystują podstawowe ciało Model, które gracze mogą modyfikować i dostosowywać przed publikacją.
Zanim zaczniesz, zapoznaj się z obserwujekwestiami:
- Modele awatarów — Następująca implementacja wymaga importowania podstawowego ciała, które spełnia specyfikacje części 15 Roblox.To Model służy jako podstawa dodatkowej personalizacji i modyfikacji użytkownika.
- Baza ciała musi spełniać wytyczne dla ciała awatara Roblox'a Avatar body guidelines, w tym minimalną liczbę kontroli FACS dla rygowania twarzy.
- Tokeny tworzenia awatara — doświadczenia implementujące tworzenie awatara wymagają co najmniej jednego tokenu tworzenia.Te tokeny wymagają Robux do zakupu i pozwalają ustawić ceny i inne ustawienia sprzedaży dla zakupów dokonywanych w doświadczeniu.
- Klasy API
- AvatarCreationService — obsługuje tworzenie awatara z prośbą o potwierdzenie i walidację.
- EditableImage — Zarządza tworzeniem czasu wykonania i manipulacją teksturami.
- EditableMesh — Rozwiązuje manipulację czasu wykonania geometrii siatki.
- WrapDeformer — Rozwiązania do manipulacji czasu wykonania geometrii niewidzialnej zewnętrznej klatki, które pozwalają postaciom awatara wyposażyć 3D odzież.
Importuj podstawowe ciało
Podstawowe ciało działa jako początkowa podstawa, którą użytkownicy mogą dostosować i edytować.Możesz używać własnego Model lub importera niestandardowych zasobów za pomocą Importera 3D i skonfigurować za pomocą ustawienia awatara.
Bazy muszą przestrzegać specyfikacji awatara Roblox i muszą zawierać komponenty takie jak 15 instancje, które tworzą 6 części ciała: głowa, tułów, lewą rękę, lewą nogę, prawą rękę i prawą nogę, a także inne komponenty awatara.
Aby uzyskać odniesienia i przykłady prawidłowo skonfigurowanych ciał awatara, zobacz odniesienia awatara.
Wdroż edytowanie API
Aby opracować system, w którym użytkownicy mogą edytować instancje MeshPart na awatarze w swoim doświadczeniu do dzieło, użyj EditableImage do edycji tekstur, EditableMesh do edycji siatki i WrapDeformer do utrzymywania danych skóry i FACS podczas edycji siatki.
Po zaimportowaniu twojego podstawowego ciałoużyj następującego skryptu, aby skonfigurować twoje EditableImages, EditableMeshes i WrapDeformers.
local AssetService = game:GetService("AssetService")local function setupBodyPart(meshPart, wrapTarget)-- Stwórz i przymocuj deformator do MeshPartlocal wrapDeformer = Instance.new("WrapDeformer")wrapDeformer.Parent = meshPart-- Stwórz edytowalną siatkę dla siatki klatki celu zawijanialocal cageEditableMesh: EditableMesh =AssetService:CreateEditableMeshAsync(Content.fromUri(wrapTarget.CageMeshId), {FixedSize = true,})-- Nadaj siatce klatki do WrapDeformerwrapDeformer:SetCageMeshContent(Content.fromObject(cageEditableMesh))endlocal function setupRigidMesh(meshPart)-- Stwórz edytowalną siatkę z oryginalnej części siatkilocal editableMesh = AssetService:CreateEditableMeshAsync(Content.fromUri(meshPart.MeshId), {FixedSize = true,})-- Wygeneruj nową część siatki z edytowanej siatkilocal newMeshPart = AssetService:CreateMeshPartAsync(Content.fromObject(editableMesh))-- Kopiuj rozmiar, pozycję i teksturę z oryginalnej części siatkinewMeshPart.Size = meshPart.SizenewMeshPart.CFrame = meshPart.CFramenewMeshPart.TextureContent = meshPart.TextureContent-- Zastosuj nową część siatki z powrotem do oryginałumeshPart:ApplyMesh(newMeshPart)endlocal function setupMeshTexture(meshPart, textureIdToEditableImageMap)-- Jeśli Edytowane obraz istnieje już dla tego ID tekstury, użyj go zamiast tworzyć nowyif textureIdToEditableImageMap[meshPart.TextureID] thenmeshPart.TextureContent =Content.fromObject(textureIdToEditableImageMap[meshPart.TextureID])returnend-- Stwórz nowy edytowalny obraz i zastosuj go jako zawartość teksturylocal editableImage = AssetService:CreateEditableImageAsync(Content.fromUri(meshPart.TextureID))textureIdToEditableImageMap[meshPart.TextureID] = editableImagemeshPart.TextureContent = Content.fromObject(editableImage)endlocal function setupModel(model)-- Mapa dla ponownego wykorzystania instancji EditableImage przez ID teksturylocal textureIdToEditableImageMap = {}for _, descendant in model:GetDescendants() doif not descendant:IsA("MeshPart") thencontinueend-- Konfiguruj MeshPart w oparciu o obecność WrapTarget-- Jeśli WrapTarget jest obecny, dodaj dziecko WrapDeformer z edytowalną siatką-- W przeciwnym razie zastosuj Edytowalną Sieć bezpośrednio do MeshPartlocal wrapTarget = descendant:FindFirstChildOfClass("WrapTarget")if wrapTarget thensetupBodyPart(descendant, wrapTarget)elsesetupRigidMesh(descendant)end-- Konfiguruj Edytowalny Obraz dla części siatkisetupMeshTexture(descendant, textureIdToEditableImageMap)endendTwórz narzędzia EditableImage, które pozwalają graczom na odmalowanie, narysowanie lub dodanie naklejek do twojego podstawowego ciało.Możesz wykorzystać API w takich przypadkach jak DrawImage(), DrawRectangle(), WritePixelsBuffer().
Dla zaawansowanych transformacji pozwala określić pozycję, rotację i skalę podczas rysowania jednego Edytowanego obrazu na drugim.Podobnie, DrawImageProjected() działa podobnie do DrawImage() ale projektuje poprawnie rysowane obrazy, 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)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 = (game.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
Używając WrapDeformer i EditableMesh, stwórz narzędzia do edycji deformacji siatki na swoim ciało.
WrapDeformer radzi sobie z żywymi deformacjami renderowanej MeshPart geometrii, zachowując podstawowe dane skinningowe i FACS.
EditableMesh pozwala modyfikować siatkę klatki, na którą odpowiada WrapDeformer .
- Użyj WrapDeformer:SetCageMeshContent() aby zastosować instancję EditableMesh reprezentującą odpowiednią siatkę klatki do WrapDeformer.
- Użyj EditableMesh, takich jak SetPosition(), aby zniekształcić wierzety i edytować kształt MeshPart.
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
Twórz powiadomienie o tworzeniu
Po skonfigurowaniu podstawowego ciała i edytowaniu interfejsów programowania utwórz powiadomienie dla użytkowników, aby stworzyli i kupili z doświadczenia za pomocą AvatarCreationService:PromptCreateAvatarAsync().
export type BodyPartInfo = {
bodyPart: Enum.BodyPart,
instance: Instance --Katalog z utworzonymi częściami siatki
}
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("Successfully uploaded with BundleId: ", bundleIdOrErrorMessage)
print("Successfully uploaded with OutfitId: ", outfitId)
else
print("Unsuccessfully uploaded with error message:", bundleIdOrErrorMessage)
end
else
print("Avatar creation unsuccessful")
end
end
AvatarCreationService:PromptCreateAvatarAsync() bierze parametr HumanoidDescription do reprezentowania awatara przeznaczonego do zakupu lub dzieło.Aby dziełoawatar, postać HumanoidDescription musi zawierać nowe zasoby, które należy stworzyć dla każdej z 6 części ciała (Head , Torso , RightLeg , LeftLeg , RightArm , LeftArm ).Opcjonalnie może również zawierać nowy Hair akcesorium.
Aby to wspierać, HumanoidDescription powinno zawierać 6 BodyPartDescription dzieci.Każda właściwość BodyPartDescription.Instance odnosi się do Folder, która zawiera wszystkie instancje MeshPart, które tworzą część ciała.Na przykład, katalog LeftArm zawiera LeftHand , LeftUpperArm , i LeftLowerArm``Class.MeshPart|MeshParts .Właściwość BodyPartDescription.BodyPart powinna również zostać ustawiona na odpowiednią Enum.BodyPart.
Każda z 15 części ciała MeshPart musi zawierać:
- An EditableImage .
- A WrapDeformer z EditableMesh.
Dostarczone HumanoidDescription nie powinno zawierać żadnych wcześniej istniejących identyfikatorów zasobów, aby reprezentować części ciała lub akcesoria w zamierzonej tworzonej dzieło.Z drugiej strony, HumanoidDescription może zawierać ludzkie skale BodyTypeScale , HeadScale , HeightScale , WidthScale i ProportionScale .Bądź ostrożny z skalami, z którymi zaimportowano podstawowe ciało, aby pasowały do skal dostarczonych do HumanoidDescription.

Załóż akcesoria
Jeśli włącza się akcesorium, takie jak włosy, HumanoidDescription powinno zawierać dziecko AccessoryDescription, gdzie:
- Właściwość AccessoryDescription.Instance odnosi się do instancji Accessory.
- Właściwość AccessoryDescription.AccessoryType jest ustawiona na odpowiednią Enum.AccessoryType.
- W przypadku uwzględnienia Enum.AccessoryType.Hair w swoich tworach, MeshPart powinno zawierać EditableImage.Nie powinno jednak zawierać dziecka WrapDeformer i powinno zawierać EditableMesh ustawienie bezpośrednio na MeshPart.
Generuj token tworzenia awatara
AvatarCreationService:PromptCreateAvatarAsync() bierze parametr ID tworzenia awatara .Ten token jest kluczem do tworów z twojego wszechświata i jest tym, co możesz użyć, aby ustawić cenę tworzenia awatara z twojego doświadczenia.Aby uzyskać instrukcje i dodatkowe szczegóły dotyczące generowania tokenów, zobacz Tokeny tworzenia awatara.
Po zakupie i generowaniu swojego tokenu możesz sprawdzić token w Centrum twórców, aby znaleźć ID, które możesz następnie użyć do API AvatarCreationService:PromptCreateAvatarAsync().

Odpowiadaj na dołączanie graczy przez przypisywanie
Paczki awatarów utworzone w doświadczeniu zawierają link do przypisania do oryginalnego doświadczenia, w którym powstał awatar.Jeśli awatar jest sprawdzany przez innego gracza, wyświetla się monit o wybór opcji odwiedzenia doświadczenia, w którym powstał awatar.

Aby obsłużyć graczy dołączających do twojego doświadczenia za pomocą tego łączyćprzypisania, użyj Player:GetJoinData() i przetwarzaj zwróconą tabelę dla GameJoinContext.
GameJoinContext zawiera następujące wartości tabeli:
- JoinSource — Enum.JoinSource
- Dołączenie do twojego doświadczenia z tego linka przypisania Player będzie miało Enum.JoinSource.CreatedItemAttribution wskazać wejście z utworzonego przedmiotu.
- ItemType — opcjonalne Enum.AvatarItemType
- AssetId — opcjonalne string
- OutfitId — opcjonalne string
- AssetType — opcjonalne Enum.AssetType