Pakiet funkcji Paczki oferuje funkcjonalność out-of-the-box do sprzedaży kolekcji przedmiotów do graczy z rabatem.Możesz wybrać, czy chcesz pozwolić graczom na zakup pakietów za pomocą niestandardowej waluty w doświadczeniu lub Robux, jaki rodzaj pakietu chcesz użyć, jakie przedmioty chcesz sprzedać i jak chcesz poprosić graczy o interakcję podczas ich rozgrywka.
Używając opcji personalizacji pakietu, możesz dostosować swoje pakiety do celów projektowania i monetyzacji swoich doświadczeń, takich jak:
- Celowanie w niską stopę konwersji poprzez oferowanie zniżonych pakietów startowych, które zapewniają wartość dla nowych graczy i zachęcają do wczesnego wydatkowania.
- Zwiększanie głębokości wydatków poprzez pakowanie przedmiotów w różnych punktach cenowych, aby dotrzeć do szerokiej gamy graczy.
- Monetyzacja działań na żywo (LiveOps) przez oferowanie ograniczonych czasowo pakietów ekskluzywnych przedmiotów.

Zdobądź pakiet
Sklep Twórców jest zakładką Toolbox, którą możesz użyć, aby znaleźć wszystkie zasoby, które są tworzone przez Roblox i społeczność Roblox do użytku w twoich projektach, w tym modele, obrazy, siatki, dźwięki, wtyczki, wideo i czcionki.Możesz użyć sklepu dla twórców, aby dodać jeden lub więcej zasobów bezpośrednio do otwartego doświadczenia, w tym pakietów funkcji!
Każdy pakiet funkcji wymaga, aby pakiet funkcji Rdzeń działał prawidłowo.Gdy pakiet funkcji Rdzeń i Paczki będzie już w twoim wyposażenie, możesz ponownie ich użyć w dowolnym projekcie na platforma.
Aby otrzymać pakiety z twojego zapasu do twojego doświadczenia:
Dodaj pakiet funkcji Rdzeń i Paczki do zapasu w Studio, klikając link Dodaj do zapasu w następującym zestawie komponentów.
W pasku narzędzi wybierz zakładkę Widok.
Kliknij Pudełko narzędzi . Okno Pudełko narzędzi wyświetla się.
W oknie Pudełko z narzędziami , kliknij zakładkę Ekwipunek . Wyświetlają się sortowania Moje modele .
Kliknij pasek Pakiet funkcji rdzenia , a następnie pasek Pakiet funkcji zestawu .Oba foldery pakietowe wyświetlają się w oknie Eksploratora .
Przeciągnij foldery pakietowe do ReplicatedStorage .
Pozwól na wezwania przechowywania danych śledzić zakupy gracza za pomocą pakietów.
- Na zakładce Dom w pasku narzędzi wybierz Ustawienia gry .
- Przejdź do zakładki Bezpieczeństwo , a następnie włącz Włącz dostęp Studio do usług API .
Określ waluty
Jeśli twoje doświadczenie ma własny system walutowy, możesz zarejestrować je za pomocą pakietu funkcji Rdzeń poprzez określenie ich w >.W tym pliku znajduje się skomentowany przykład waluty Gemów już zastąpiony posiadać.
Waluty
Gems = {displayName = "Gems",symbol = "💎",icon = nil,},
Skrypt Currencies mówi pakietowi funkcji Rdzeń o niektórych metadanych dotyczących twojej waluta:
- (wymagane) displayName - Nazwa twojej waluta. Jeśli nie określisz symbolu lub ikona, nazwa ta jest używana w przyciskach zakupu (tj. "100 klejnotów").
- (opcjonalnie) symbol - Jeśli masz znak tekstowy do użycia jako ikonę dla swojej waluta, zostanie on użyty zamiast displayName w przyciskach zakupu (tj. "💎100").
- (opcjonalnie) - Jeśli masz ikonę obrazu dla waluta, użyje się jej zamiast w przyciskach zakupu (tj.obraz zostanie umieszczony po lewej stronie ceny "🖼️100")
Po skonfigurowaniu waluty musisz ręcznie określić cenę pakietu, walutai ikonę do wyświetlenia na górze, zamiast informacji otrzymywanych z powiązanego produktu programisty pakietu.
Paczki
-- Jeśli chcesz używać produktu rozwojowego, musisz podać unikalny ID produktu rozwojowego, używany tylko przez jeden pakiet.-- Zbierzemy cenę pakietu i ikonę z produktu deweloperapricing = {priceType = CurrencyTypes.PriceType.Marketplace,devProductId = 1795621566,},-- W przeciwnym razie, jeśli chcesz używać waluty w doświadczeniu zamiast produktu rozwojowego, możesz użyć następującego zamiast:-- Cena tutaj jest w walucie waluta, a nie w Robuxpricing = {priceType = CurrencyTypes.PriceType.InExperience,price = 79,currencyId = "Gems",icon = 18712203759,},
Musisz również odwołać się do skryptu BundlesExample , aby wezwać setInExperiencePurchaseHandler .
Przykład bundli
local function awardInExperiencePurchase(
_player: Player,
_bundleId: Types.BundleId,
_currencyId: CurrencyTypes.CurrencyId,
_price: number
)
-- Sprawdź, czy gracz ma wystarczającą walutę, aby kupić pakiet
-- Aktualizuj dane gracza, daj przedmioty itp.
-- Odejmij walutę od gracza
task.wait(2)
return true
end
local function initializePurchaseHandlers()
local bundles = Bundles.getBundles()
for bundleId, bundle in bundles do
-- Pakiet nie jest powiązany z produktem dla programistów, jeśli nie ma wpisywaćceny rynkowej
if not bundle or bundle.pricing.priceType ~= "Marketplace" then
continue
end
Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
receiptHandlers[bundle.pricing.devProductId] = receiptHandler
end
-- Jeśli masz jakiekolwiek waluty w doświadczeniu, które używasz do pakietów, ustaw obsługę tutaj
for currencyId, _ in Currencies do
Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
end
end
W szczególności musisz wypełnić awardInExperiencePurchase, które jest nazywane przez pętiel przez Currencies wewnątrz przykładu initializePurchaseHandlers (tj.każdy currencyId jest połączony z obsługą za pomocą Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase) ).
Określ paczki
Wszystkie pakiety dostępne w twoim doświadczeniu mogą być zdefiniowane w ReplicatedStorage.Bundles.Configs.Bundles , z typami eksportowanymi z kodu Types ze skryptu w tym samym folderze.
Jeśli używasz devProductId, musisz zaktualizować główny devProductId pakiet, aby pasował do tego, który masz w swoim doświadczeniu.To jest to, co zostanie poproszone przez MarketplaceService o zakup samego pakietu. Zdecydowanie zaleca się użycie nowego produktu dla programistów dla pakietu, aby ułatwić śledzenie oddzielnych sprzedaży. Jeśli chcesz pakiet z wieloma przedmiotami i jeśli są one już reprezentowane przez produkty dewelopera w Twoim doświadczeniu, nie musisz wyraźnie ustawić ceny przedmiotu/assetId/nazwy, które zostaną pobrane za pośrednictwem informacji o produktach:
Przeczytaj README
{itemType = ItemTypes.ItemType.DevProduct,devProductId = <DEV_PRODUCT_ID>,metadata = {caption = {text = "x1",color = Color3.fromRGB(236, 201, 74),} -- Napis jest opcjonalny! Możesz również pominąć to pole}},
W przeciwnym razie możesz ręcznie skonfigurować te szczegóły przedmiotu:
Przeczytaj README
{itemType = ItemTypes.ItemType.Robux,priceInRobux = 49,icon = <IMAGE_ASSET_ID>,metadata = {caption = {text = "x1",color = Color3.fromRGB(236, 201, 74),} -- Napis jest opcjonalny! Możesz również pominąć to pole}},
Na przykład cały pakiet będzie prawdopodobnie wyglądał tak:
Przeczytaj README
local starterBundle: Types.RelativeTimeBundle = {bundleType = Types.BundleType.RelativeTime,-- Jeśli chcesz używać produktu rozwojowego, musisz podać unikalny ID produktu rozwojowego, używany tylko przez jeden pakiet.-- Zbierzemy cenę pakietu i ikonę z produktu deweloperapricing = {priceType = CurrencyTypes.PriceType.Marketplace,devProductId = <DEV_PRODUCT_ID>,},-- W przeciwnym razie, jeśli chcesz używać waluty w doświadczeniu zamiast produktu rozwojowego, możesz użyć następującego zamiast:-- Cena tutaj jest w walucie waluta, a nie w Robux-- cenowanie = {-- priceType = CurrencyTypes.PriceType.InExperience,-- cenę = 79,-- currencyId = <CURRENCY_ID>,-- ikoną = <IMAGE_ASSET_ID>,-- },includedItems = {[1] = {-- Sama rzecz nie jest sprzedawana za pośrednictwem produktu dla programistów, więc wskaż, ile jest warta w Robuxach i podaj ikona-- Cena w Robux pomaga pokazać wartość względną ceny pakietu w stosunku do sumy jego zawartościitemType = ItemTypes.ItemType.Robux,priceInRobux = 49,icon = <IMAGE_ASSET_ID>,-- Alternatywnie, jeśli to ma produkt rozwojowy pomiń cenę i ikonę powyżej i po prostu ustaw devProductId-- Cena i ikona zostaną pobrane z produktu dla programisty-- devProductId = <ITEM_DEV_PRODUCT_ID>-- Istnieje więcej opcjonalnych pól metadanych, które są interfejsowe, jeśli jest to potrzebnemetadata = {caption = {text = "x1",color = Color3.fromRGB(236, 201, 74),},},},[2] = {itemType = ItemTypes.ItemType.Robux,priceInRobux = 99,icon = <IMAGE_ASSET_ID>,metadata = {caption = {text = "x1",color = Color3.fromRGB(236, 201, 74),},},},[3] = {itemType = ItemTypes.ItemType.Robux,priceInRobux = 149,icon = <IMAGE_ASSET_ID>,metadata = {caption = {text = "x1",color = Color3.fromRGB(236, 201, 74),},},},},singleUse = true, -- Po zakupie lub wygaśnięciu nie jest już ważny, nawet jeśli twoje doświadczenie próbuje wysłać powiadomienie (onPlayerAdded). Możesz to uczynić fałszywe podczas testowania w studio.durationInSeconds = 900, -- 15 minutyincludesOfflineTime = false, -- Liczyć tylko czas upływający w doświadczeniumetadata = {displayName = "STARTER BUNDLE",description = "Save 75% and get a head start!",},}
Zintegruj logikę serwera
Spójrz na ReplicatedStorage.Bundles.Server.Examples.BundlesExample, który pokazuje, jak twój serwer będzie interakcjonował z pakietem funkcji Paczki i powyższymi metodami na ModuleScript.Poniższe kawałki pochodzą z tego skryptu.
Głównie musisz podłączyć cztery rzeczy po przeciągnięciu pakietu funkcji Paczki Bundli do swojego doświadczenia:
Podłącz menedżerów zakupów za pośrednictwem Bundles.setPurchaseHandler do określenia funkcji, do których należy zadzwonić, aby przyznać przedmioty za nagrodę, gdy przetwarzany jest zakup.
Przykład bundlilocal function awardMarketplacePurchase(_player: Player, _bundleId: Types.BundleId, _receiptInfo: { [string]: any })-- Aktualizuj dane gracza, daj przedmioty itp.-- ... I zapisz informacje o otrzymaniu rekordu info.PurchaseId, abyśmy mogli sprawdzić, czy użytkownik ma już ten pakiettask.wait(2)return Enum.ProductPurchaseDecision.PurchaseGrantedendlocal function awardInExperiencePurchase(_player: Player,_bundleId: Types.BundleId,_currencyId: CurrencyTypes.CurrencyId,_price: number)-- Sprawdź, czy gracz ma wystarczającą walutę, aby kupić pakiet-- Aktualizuj dane gracza, daj przedmioty itp.-- Odejmij walutę od graczatask.wait(2)return trueendlocal function initializePurchaseHandlers()local bundles = Bundles.getBundles()for bundleId, bundle in bundles do-- Pakiet nie jest powiązany z produktem dla programistów, jeśli nie ma wpisywaćceny rynkowejif not bundle or bundle.pricing.priceType ~= "Marketplace" thencontinueendBundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)receiptHandlers[bundle.pricing.devProductId] = receiptHandlerend-- Jeśli masz jakiekolwiek waluty w doświadczeniu, które używasz do pakietów, ustaw obsługę tutajfor currencyId, _ in Currencies doBundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)endendPołącz swoją logikę dla MarketplaceService.ProcessReceipt, ale można to zrobić gdzie indziej, jeśli twoje doświadczenie ma już produkty dla programistów na sprzedaż.Zasadniczo, gdy otrzymana jest faktura produktu programisty, teraz wezwą Bundles.getBundleByDevProduct , aby sprawdzić, czy produkt należy do pakietu.Jeśli tak, skrypt następnie dzwoni Bundles.processReceipt .
Przykład bundli-- Otrzymanie procesu z rynku, aby określić, czy gracz musi być obciążony czy nielocal function processReceipt(receiptInfo): Enum.ProductPurchaseDecisionlocal userId, productId = receiptInfo.PlayerId, receiptInfo.ProductIdlocal player = Players:GetPlayerByUserId(userId)if not player thenreturn Enum.ProductPurchaseDecision.NotProcessedYetendlocal handler = receiptHandlers[productId] -- Zdobądź identyfikator obsługi dla produktulocal success, result = pcall(handler, receiptInfo, player) -- Zadzwoń do menedżera, aby sprawdzić, czy logika zakupu jest pomyślnaif not success or not result thenwarn("Failed to process receipt:", receiptInfo, result)return Enum.ProductPurchaseDecision.NotProcessedYetendreturn Enum.ProductPurchaseDecision.PurchaseGrantedendlocal function receiptHandler(receiptInfo: { [string]: any }, player: Player)local bundleId, _bundle = Bundles.getBundleByProductId(receiptInfo.ProductId)if bundleId then-- Ten zakup należy do pakietu, pozwól pakietom go obsłużyćlocal purchaseDecision = Bundles.processReceiptAsync(player, bundleId, receiptInfo)return purchaseDecision == Enum.ProductPurchaseDecision.PurchaseGrantedend-- Ten zakup nie należy do pakietu,-- ... obsługuj całą swoją istniejącą logikę tutaj, jeśli masz jakąkolwiekreturn falseendPołącz Players.PlayerAdded:Connect(Bundles.OnPlayerAdded), aby pakiet funkcji Paczki ponownie zapytuje o aktywne paczki, które nie wygasły jeszcze dla gracza.
Przeczytaj READMElocal function onPlayerAdded(player: Player)-- Powiedz pakietom, kiedy gracz dołączy, aby mogły ponownie załadować swoje daneBundles.onPlayerAdded(player)-- Jeśli miałeś jakiś pakiet startowy, który chciałeś zaoferować wszystkim nowym użytkownikom, możesz to tutaj zapytać-- ... Pakiety zajmą się, jeśli gracz już go zakupił lub wygasł, ponieważ nie jest powtarzalny-- Bundles.promptIfValidAsync(gracz, "Pakiet startowy")-- Wezwanie tego tutaj tylko na przykład, możesz wezwać to kiedykolwiek i gdziekolwiek chceszonPromptBundleXYZEvent(player)endPrompty pakietów. Chociaż zależy to od rozgrywka, przykładowe wskazuje graczy z pakietem startowym onPlayerAdded .
Logika pakietu funkcji Paczki zapewnia, że każdy gracz nie otrzyma powtórnej oferty, jeśli już zakupił pakiet, lub jeśli pozwoli, aby oferta wygasła już (na podstawie konfiguracji pakietu).
Zawsze gdy chcesz wysłać żądanie do pakietu do gracza, wezwij Bundles.promptIfValidAsync(player, bundleId).
Przeczytaj READMElocal function onPromptBundleXYZEvent(player: Player)-- Połącz dowolne wydarzenie doświadczenia, które chcesz użyć, aby określić, kiedy gracz otrzyma zapytanie o pakiet-- ... będzie to za każdym razem, gdy spełnisz swoje kryteria kwalifikacji, aby poprosić gracza o pakiet-- ... Na przykład, jeśli chcesz poprosić o pakiet, gdy gracz dołącza, lub gdy gracz awansujetask.spawn(Bundles.promptIfValidAsync, player, <Some_Bundle_Id>)-- ... Jeśli tworzysz wiele bundli, użycie task.spawn() do owinięcia powyższego wezwania funkcji zmniejszy rozbieżności między odliczaniamiend
Rozważ następujące wytyczne dotyczące redundantnych rekordów ReceiptIds:
Chociaż pakiet funkcji Paczki rejestruje otrzymane ID faktur, aby uniknąć przetwarzania tej samej faktury dwa razy, powinieneś również rejestrować otrzymane ID faktur wewnątrz swoich tabel, aby w przypadku niepowodzenia przepływu zakupu po tym, jak jego przetwarzacz zakupów już zakończył, wiedziałeś w kolejnej próbie nie przyznawać przedmiotów ponownie.
Pakiet funkcji Paczki nie zarejestruje ReceiptId, jeśli zakup nie powiedzie się na każdym kroku, więc powinieneś upewnić się, że rejestrujesz ReceiptId w swoich tabelach przed przetworzeniem faktury jako część swojego procesora zakupów.
Ta redundancja pomaga zapewnić, że cała logika zakupów została właściwie obsługiwana i że przechód danych sklepu danych i pakietu funkcji Paczki osiągnie ostateczną spójność, z przechowaniem danych sklepu danych jako źródłem prawdy.
Konfiguruj stałe
Stałe dla pakietu funkcji Rdzenia żyją w dwóch miejscach:
Wspólne konstytucje żyją w ReplicatedStorage.FeaturePackagesCore.Configs.SharedConstants .
Konstytucje pakietowe, w tym przypadku pakiet funkcji Paczki , żyją w ReplicatedStorage.Bundles.Configs.Constants .
Główne rzeczy, które możesz dostosować, aby spełnić wymagania dotyczące projektu swojego doświadczenia:
- ID dźwięku
- Czas trwania efektu zakupu i kolory cząstek
- Ostrzeżenie o załamaniu wyświetlania głów
Ponadto możesz znaleźć struny do tłumaczenia rozdzielone w jednym miejscu: ReplicatedStorage.FeaturePackagesCore.Configs.TranslationStrings .
Dostosuj komponenty interfejsu
Poprzez modyfikowanie obiektów pakietu, takich jak kolory, czcionka i przejrzystość, możesz dostosować wizualną prezentację powiadomień o zestawie.Należy jednak pamiętać, że jeśli przeniesiesz którykolwiek z obiektów wokół hierarchicznie, kod nie będzie w stanie ich znaleźć, a będziesz musiał dokonać zmian w swoim kodzie.
Wyskakujące okienko składa się z dwóch wysokopoziomowych komponentów:
- PromptItem – Poszczególny komponent powtórzony dla każdego elementu w pakiecie (obraz przedmiotu, podpis, nazwa, cena).
- Prompt – Samo okienko wyskakujące.
Wyświetlanie ostrzeżeń składa się również z dwóch komponentów:
- HudItem – pojedynczy komponent, który reprezentuje każdą opcję menu w widoku górnym.
- Hud – Aby zostać wypełniony programowo za pomocą HudItems .
Jeśli chcesz mieć większą kontrolę nad wyświetlaniem informacji na głowie, zamiast po prostu używać istniejącego interfejsu HUD w ciągu ReplicatedStorage.Bundles.Objects.BundlesGui, możesz przenieść rzeczy, aby spełnić własne wymagania dotyczące projektu.Po prostu upewnij się, że zaktualizujesz zachowanie skryptu klienta w skrypcie ReplicatedStorage.Bundles.Client.UIController.
Referencja API
Typy
Czas względny
Gdy pakiet RelativeTime zostanie zaoferowany graczowi, pozostanie on dostępny do czasu wyczerpania czasu trwania.Ten typ wyświetla się na wyświetlaniu na górze głowy gracza i automatycznie prosi o przyszłych sesjach, dopóki pakiet nie wygaśnie lub gracz go nie kupi.
Wspólnym przykładem tego typu pakietu jest oferta jednorazowego pakietu startowego, która wyświetla się wszystkim nowym graczom przez 24 godziny.Aby uzyskać najlepsze praktyki branżowe dotyczące sposobu wdrażania pakietów pakietu startowego, zobacz Projekt pakietu startowego.
Nazwa | Typ | Opis |
---|---|---|
includeOfflineTime | bool | (Opcjonalnie) Jeśli nie jest ustawiać, tylko czas spędzony w doświadczeniu będzie liczony w kierunku pozostałego czasu trwania oferty. |
singleUse | bool | (Opcjonalnie) Jeśli nie jest ustawiać, zakup można ponownie aktywować po jego zakupie lub wygaśnięciu.Jeśli jest ustawiać, po raz pierwszy zakupiony lub wygasły, nie będzie można go ponownie zapytać, nawet jeśli wezwiesz Bundles.promptIfValidAsync z bundleId. |
Naprawiony czas
Gdy pakiet FixedTime zostanie zaoferowany graczowi, pozostanie on dostępny do końca skoordynowanego czasu uniwersalnego (UTC).Ten typ wyświetla się na wyświetlaniu na górze głowy gracza i automatycznie prosi o przyszłych sesjach, dopóki pakiet nie wygaśnie lub gracz go nie kupi.
Wspólnym przykładem tego typu pakietu jest oferta świąteczna, która jest dostępna tylko dla określonego miesiąca.
Jednorazowe
Paczka OneTime dostępna jest tylko w momencie, gdy jest oferowana graczowi.Nie wyświetla się na ekranie głównym gracza, a po zamknięciu przez gracza monitu nie może być ponownie otwarty, dopóki nie zostanie ponownie poproszony przez serwer.
Wspólnym przykładem tego typu pakietu jest oferta kupienia więcej waluty doświadczenia w momencie, gdy gracz się skończy.