Das Bündel -Funktionspaket bietet eine Out-of-the-Box-Funktionalität, um Sammlungen von Artikeln an Spieler mit Rabatt zu verkaufen.Du kannst wählen, ob Spieler Bündel mit einer benutzerdefinierten In-Experience-Währung oder Robux kaufen sollen oder welchen Bündeltyp du verwenden möchtest, welche Artikel du verkaufen möchtest und wie du Spieler während ihres Gameplayauffordern möchtest.
Mit den Anpassungsoptionen des Pakets können Sie Ihre Pakete anpassen, um die Design- und Monetarisierungsziele Ihrer Erlebnisse zu erfüllen, wie:
- Zielrichtung einer niedrigen Umwandlungsrate, indem kostengünstige Starterpakete angeboten werden, die neuen Spielern einen Mehrwert bieten und sie zu frühen Ausgaben ermutigen.
- Erhöhung der Ausgabetiefe durch das Bündeln von Artikeln an verschiedenen Preispunkten, um eine Reihe von Spielern anzusprechen.
- Monetarisierung von Live-Operationen (LiveOps) Events durch Angebot von zeitlich begrenzten Bündeln exklusiver Artikel.

Paket erhalten
Der Creator-Store ist ein Tab der Toolbox, den Sie verwenden können, um alle Assets zu finden, die von Roblox und der Roblox-Community erstellt wurden, um sie in Ihren Projekten zu verwenden, einschließlich Modell, Bild, Mesh, Audiodateien, Plug-in, Video und Schriftarten.Du kannst den Creator-Store verwenden, um eine oder mehrere Assets direkt in ein offenes Erlebnis einzufügen, einschließlich Feature-Pakete!
Jedes Feature-Paket erfordert, dass das Kern -Feature-Paket ordnungsgemäß funktioniert.Sobald die Kern - und Bündel -Funktionspaket-Assets in deinem Inventar sind, kannst du sie in jedem Projekt auf der Plattform wiederverwenden.
Um die Pakete aus deinem Inventar in deine Erlebniszu bringen:
Füge das Kern - und Bündel -Funktionspaket zu deinem Inventar innerhalb von Studio hinzu, indem du auf die Schaltfläche Zum Inventar hinzufügen in der folgenden Reihe von Komponenten klickst.
Wählen Sie in der Toolbar die Ansicht-Registerkarte.
Klicken Sie auf Werkzeugkiste . Das Werkzeugkistenfenster wird angezeigt.
In dem Werkzeugkasten Fenster klicken Sie auf die Inventar Registerkarte. Die meine Modelle Sortierung wird angezeigt.
Klicken Sie auf die Feature-Paket-Kern -Kachel, dann auf die Bündel-Funktionspaket -Kachel.Beide Paketordner werden im Explorer -Fenster angezeigt.
Ziehe die PaketOrdner in ReplicatedStorage .
Erlaube Datenlagern, Anrufe zu verfolgen, mit denen Spielerkäufe mit den Paketen getätigt werden.
- Wählen Sie auf der Registerkarte Home der Toolbar Spieleinstellungen .
- Navigiere zur Sicherheits -Registerkarte und aktiviere dann Studio-Zugriff auf API-Dienste aktivieren .
Währungen definieren
Wenn deine Erfahrung ein eigenes Währungssystem hat, kannst du sie mit dem Kern -Funktionspaket registrieren, indem du sie in ReplicatedStorage.FeaturePackagesCore.Configs.Currencies definierst.Es gibt bereits ein kommentiertes Beispiel für eine Edelstein-Währung in dieser Datei; ersetze es durch besitzen.
Währungen
Gems = {displayName = "Gems",symbol = "💎",icon = nil,},
Das Currencies-Skript sagt dem Kern -Funktionspaket einige Metadaten über Ihre Währung:
- (erforderlich) displayName - Der Name deiner Währung. Wenn du kein Symbol oder ein Icon spezifizierst, wird dieser Name in Kauf buttons verwendet (z. B. "100 Edelsteine").
- (optional) symbol - Wenn du einen Textzeichen als Symbol für deine Währung verwenden möchtest, wird dies anstelle des displayName in Kauf buttons (z. B. "💎100") verwendet.
- (optional) icon - Wenn du ein AssetId Bildsymbol für deine Währung hast, wird dies anstelle des displayName in Kauf buttons verwendet (d.h.Das Bild wird links vom Preis "🖼️100") platziert
Sobald deine Währung eingerichtet ist, musst du den Preis, die Währung und das Symbol des Bündels für die Vorschauanzeige manuell angeben, anstatt dass diese Informationen vom verbundenen Entwicklerprodukt des Bündels abgerufen werden.
Bündel
-- Wenn du ein Entwicklerprodukt verwenden möchtest, musst du eine eindeutige devProductId liefern, die nur von einem Bündel verwendet wird.-- Wir werden den Bündelpreis und das Symbol vom Entwicklerprodukt abrufenpricing = {priceType = CurrencyTypes.PriceType.Marketplace,devProductId = 1795621566,},-- Andernfalls, wenn du stattdessen zur Erfahrungswährung anstelle eines Entwicklerprodukts verwenden möchtest, kannst du stattdessen Folgendes verwenden:-- Preis hier ist in der Währung, nicht in Robuxpricing = {priceType = CurrencyTypes.PriceType.InExperience,price = 79,currencyId = "Gems",icon = 18712203759,},
Du musst auch das BundlesExample-Skript referenzieren, um setInExperiencePurchaseHandler aufzurufen.
Bündelbeispiel
local function awardInExperiencePurchase(
_player: Player,
_bundleId: Types.BundleId,
_currencyId: CurrencyTypes.CurrencyId,
_price: number
)
-- Überprüfe, ob der Spieler über genug Währung verfügt, um das Bündel zu kaufen
-- Aktualisieren Sie Spielerdaten, geben Sie Artikel usw.
-- Subtrahiere die Währung vom Spieler:in
task.wait(2)
return true
end
local function initializePurchaseHandlers()
local bundles = Bundles.getBundles()
for bundleId, bundle in bundles do
-- Bündel ist nicht mit einem Entwicklerprodukt verbunden, wenn es keinen eingebenhat
if not bundle or bundle.pricing.priceType ~= "Marketplace" then
continue
end
Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
receiptHandlers[bundle.pricing.devProductId] = receiptHandler
end
-- Wenn du irgendwelche In-Experience-Währungen hast, die du für Bündel verwendest, lege den Handler hier fest
for currencyId, _ in Currencies do
Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
end
end
Insbesondere musst du awardInExperiencePurchase ausfüllen, was durch eine Schleife durch Currencies innerhalb des Beispiels initializePurchaseHandlers (d.h.jede WährungID ist mit dem Handler durch Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase) verbunden).
Bündel definieren
Alle Pakete, die in deiner Erfahrung angeboten werden können, können innerhalb von ReplicatedStorage.Bundles.Configs.Bundles definiert werden, mit Typs, die aus dem Types Skript im gleichen Ordner exportiert werden.
Wenn du eine devProductId verwendest, musst du das Haupt-devProductId des Bündels aktualisieren, um es mit dem in deiner Erlebnisübereinzubringen.Das ist, was durch MarketplaceService zum Kauf des Bündels selbst aufgefordert wird. Es wird dringend empfohlen, ein neues Entwicklerprodukt für das Bündel zu verwenden, um es einfacher zu machen, separate Verkäufe zu verfolgen. Wenn du ein Bündel mit mehreren Artikeln möchtest, und wenn diese bereits durch Entwicklerprodukte in deiner Erlebnisrepräsentiert sind, musst du den Artikelpreis/AssetId/Name nicht explizit festlegen, der über Produktinformationen abgerufen wird:
LESEN Sie ME
{itemType = ItemTypes.ItemType.DevProduct,devProductId = <DEV_PRODUCT_ID>,metadata = {caption = {text = "x1",color = Color3.fromRGB(236, 201, 74),} -- Untertitel ist optional! Du kannst auch dieses Feld überspringen}},
Ansonsten kannst du diese Artikeldetails manuell konfigurieren:
LESEN Sie ME
{itemType = ItemTypes.ItemType.Robux,priceInRobux = 49,icon = <IMAGE_ASSET_ID>,metadata = {caption = {text = "x1",color = Color3.fromRGB(236, 201, 74),} -- Untertitel ist optional! Sie können auch dieses Feld überspringen}},
Zum Beispiel wird dein gesamtes Bündel wahrscheinlich so aussehen:
LESEN Sie ME
local starterBundle: Types.RelativeTimeBundle = {bundleType = Types.BundleType.RelativeTime,-- Wenn du ein Entwicklerprodukt verwenden möchtest, musst du eine eindeutige devProductId liefern, die nur von einem Bündel verwendet wird.-- Wir werden den Bündelpreis und das Symbol vom Entwicklerprodukt abrufenpricing = {priceType = CurrencyTypes.PriceType.Marketplace,devProductId = <DEV_PRODUCT_ID>,},-- Andernfalls, wenn du stattdessen zur Erfahrungswährung anstelle eines Entwicklerprodukts verwenden möchtest, kannst du stattdessen Folgendes verwenden:-- Preis hier ist in der Währung, nicht in Robux-- preis = {-- preistyp = Währungstypen.Preistyp.InExperience,-- preis = 79,-- WährungId = <CURRENCY_ID>,-- icon = <IMAGE_ASSET_ID>,-- },includedItems = {[1] = {-- Das Item selbst wird nicht über ein Entwicklerprodukt verkauft, also gib an, wie viel es in Robux wert ist, und gib ein Icon-- Der PreisInRobux hilft Bündeln, den relativen Wert des Bündelpreises gegenüber der Summe seiner Inhalte anzuzeigenitemType = ItemTypes.ItemType.Robux,priceInRobux = 49,icon = <IMAGE_ASSET_ID>,-- Alternativ, wenn dies ein Entwicklerprodukt hat, lassen Sie den Preis und das Symbol oben weg und stellen Sie nur die devProductId ein-- Der Preis und das Icon werden aus dem Entwicklerprodukt abgerufen-- devProductId = <ITEM_DEV_PRODUCT_ID>-- Es gibt mehr optionale Metadatenfelder, die bei Bedarf UI-spezifisch sindmetadata = {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, -- Sobald gekauft oder abgelaufen, ist es nicht mehr gültig, auch wenn deine Erfahrung versucht, zu fragen (onPlayerAdded). Du kannst dies während des Tests im Studio falsch machen.durationInSeconds = 900, -- 15 minutenincludesOfflineTime = false, -- Zähle nur die Zeit, die im Erlebnis verstrichen istmetadata = {displayName = "STARTER BUNDLE",description = "Save 75% and get a head start!",},}
Serverlogik integrieren
Schau dir ReplicatedStorage.Bundles.Server.Examples.BundlesExample an, das zeigt, wie dein Server mit dem Bundles Feature-Paket und den oben genannten Methoden auf der ModuleScript interagieren wird.Die Snippets unten sind aus diesem Skript, das. PL: die Skripts.
Du musst vor allem vier Dinge verbinden, sobald du das Bündel -Funktionspaket in deine Erlebnisziehst:
Verbinde Kaufbearbeiter durch Bundles.setPurchaseHandler mit, um die Funktionen anzugeben, die zum Anrufen von Artikeln bei einem Kauf verwendet werden sollen, wenn ein Kauf bearbeitet wird.
Bündelbeispiellocal function awardMarketplacePurchase(_player: Player, _bundleId: Types.BundleId, _receiptInfo: { [string]: any })-- Aktualisieren Sie Spielerdaten, geben Sie Artikel usw.-- ... UND record receiptInfo.PurchaseId, damit wir überprüfen können, ob der Benutzer dieses Bündel bereits hattask.wait(2)return Enum.ProductPurchaseDecision.PurchaseGrantedendlocal function awardInExperiencePurchase(_player: Player,_bundleId: Types.BundleId,_currencyId: CurrencyTypes.CurrencyId,_price: number)-- Überprüfe, ob der Spieler über genug Währung verfügt, um das Bündel zu kaufen-- Aktualisieren Sie Spielerdaten, geben Sie Artikel usw.-- Subtrahiere die Währung vom Spieler:intask.wait(2)return trueendlocal function initializePurchaseHandlers()local bundles = Bundles.getBundles()for bundleId, bundle in bundles do-- Bündel ist nicht mit einem Entwicklerprodukt verbunden, wenn es keinen eingebenhatif not bundle or bundle.pricing.priceType ~= "Marketplace" thencontinueendBundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)receiptHandlers[bundle.pricing.devProductId] = receiptHandlerend-- Wenn du irgendwelche In-Experience-Währungen hast, die du für Bündel verwendest, lege den Handler hier festfor currencyId, _ in Currencies doBundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)endendVerbinde deine Logik für MarketplaceService.ProcessReceipt, aber das kann an anderer Stelle erledigt werden, wenn deine Erfahrung bereits Entwicklerprodukte zum Verkauf stehenhat.Im Wesentlichen wird beim Verarbeiten einer Entwicklerproduktrechnung nun Bundles.getBundleByDevProduct angerufen, um zu überprüfen, ob das Produkt zu einem Bündel gehört.Wenn es das tut, ruft das Skript dann Bundles.processReceipt auf.
Bündelbeispiel-- Prozessrezept vom Marktplatz, um zu bestimmen, ob der Spieler belastet werden muss oder nichtlocal 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] -- Holen Sie sich den Handler für das Produktlocal success, result = pcall(handler, receiptInfo, player) -- Rufen Sie den Handler auf, um zu überprüfen, ob die Kauflogik erfolgreich istif 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-- Dieser Kauf gehört zu einem Bündel, lassen Sie Bündel es handhabenlocal purchaseDecision = Bundles.processReceiptAsync(player, bundleId, receiptInfo)return purchaseDecision == Enum.ProductPurchaseDecision.PurchaseGrantedend-- Dieser Kauf gehört nicht zu einem Bündel,-- ... behandle alle deine vorhandene Logik hier, wenn du irgendwelche hastreturn falseendVerbinde Players.PlayerAdded:Connect(Bundles.OnPlayerAdded), damit das Feature-Paket Bündel erneut aktive Bündel fragt, die für einen Spieler:innoch nicht abgelaufen sind.
LESEN Sie MElocal function onPlayerAdded(player: Player)-- Sage Bundles, wenn Spieler beitreten, damit es ihre Daten neu laden kannBundles.onPlayerAdded(player)-- Wenn du ein Starter-Paket hättest, das du allen neuen Benutzern anbieten wolltest, könntest du das hier einfordern-- ... Bündel werden umgehen, wenn der Spieler es bereits gekauft hat oder es abgelaufen ist, da es nicht wiederholbar ist-- Bündel.promptIfValidAsync(Spieler:in, "StarterBundle")-- Wenn du das hier nur zum Beispiel aufrufst, kannst du es jederzeit und überall aufrufen, wann immer du willstonPromptBundleXYZEvent(player)endSchnelle Pakete. Während dies vom Gameplayabhängt, zeigt das Beispiel den Spielern mit einem Starter-Bündel onPlayerAdded an.
Die Bündel -Funktionspaketlogik gewährleistet, dass jeder Spieler kein wiederholtes Angebot erhält, wenn er das Bündel bereits gekauft hat oder das Angebot bereits abgelaufen ist (basierend auf Bündelkonfiguration).
Wann immer du ein Bündel einem Spieler:inanzeigen möchtest, rufe Bundles.promptIfValidAsync(player, bundleId) an.
LESEN Sie MElocal function onPromptBundleXYZEvent(player: Player)-- Verbinde jedes Erlebnisevent, das du verwenden möchtest, um festzustellen, wann ein Spieler aufgefordert wird, das Bündel zu erhalten-- ... das wird immer sein, wenn du deine Elegibilitätskriterien erfüllt hast, um einen Spieler das Bündel zu präsentieren-- ... Wenn du beispielsweise ein Bündel auffordern möchtest, wenn ein Spieler beitritt oder wenn ein Spieler aufsteigttask.spawn(Bundles.promptIfValidAsync, player, <Some_Bundle_Id>)-- ... Wenn mehrere Bündel erstellt werden, wird die Verwendung von task.Spawn() dazu beitragen, Diskrepanzen zwischen Countdowns zu minimierenend
Betrachte die folgenden Best Practise-Anweisungen zur redundanten Aufzeichnung von ReceiptIds:
Während das Bündel -Funktionspaket ReceiptIDs aufzeichnet, um zu vermeiden, dass die gleiche Rechnung zweimal verarbeitet wird, solltest du auch ReceiptIDs innerhalb deiner Tabellen aufzeichnen, damit du weißt, dass du bei einem Fehlschlag des Kaufprozesses nachdem dein Kaufverarbeiter bereits fertig ist, keine Artikel erneut vergeben sollst.
Das Bündel -Funktionspaket wird die ReceiptId nicht aufzeichnen, wenn der Kauf bei einem Schritt fehlschlägt, also solltest du sicherstellen, dass du die ReceiptId in deinen Tabellen aufzeichnest, bevor du die Receipt als Teil deines PurchaseHandlers verarbeitest.
Diese Redundanz hilft sicherzustellen, dass die gesamte Kauflogik angemessen behandelt wurde und der Datenstore Ihres Datenlagers und der Datenstore des Bundles Feature-Pakets letztendlich konsistent werden, wobei der Datenstore Ihrer Datenquelle die Quelle der Wahrheit ist.
Konfigurieren von Konstanten
Konstanten für das Kern -Funktionspaket sind live in zwei Orten:
Geteilte Konstanten leben in ReplicatedStorage.FeaturePackagesCore.Configs.SharedConstants.
Paket spezifische Konstanten, in diesem Fall das Bündel Feature-Paket, leben in ReplicatedStorage.Bundles.Configs.Constants .
Die wichtigsten Dinge, die du anpassen möchtest, um die Designanforderungen deines Erlebnisses zu erfüllen:
- Klang-AssetIDs
- Kaufeffektdauer und Partikelfarben kaufen
- Kopfbedienungskollapsibilität anzeigen
Zusätzlich können Sie Zeichen für die Übersetzung in eine einzige Position aufteilen: ReplicatedStorage.FeaturePackagesCore.Configs.TranslationStrings .
UI-Komponenten anpassen
Durch Änderung der Paketobjekte wie Farben, Schriftart und Transparenz kannst du die visuelle Präsentation deiner Bündelaufforderungen anpassen.Beachte jedoch, dass, wenn du eines der Objekte hierarchisch umstellst, der Code sie nicht finden kann und du Änderungen an deinem Codesvornehmen musst.
Ein Prompt besteht aus zwei hohen Komponenten:
- PromptItem – Die einzelne Komponente wiederholt sich für jedes Element innerhalb eines Bündels (Artikelbild, Untertitel, Name, Preis).
- Prompt – Das Eingabeaufforderungsfenster selbst.
Das Kopfzeichenanzeige besteht auch aus zwei Komponenten:
- HudItem – Eine einzelne Komponente, die jede Menüoption im Kopfaussteller darstellt.
- Hud – Um mit programmatisch mit HudItems gefüllt zu werden.
Wenn du mehr Kontrolle über das Kopfbedienfeld haben möchtest, anstatt nur die vorhandene HUD-Benutzeroberfläche innerhalb von ReplicatedStorage.Bundles.Objects.BundlesGui zu verwenden, kannst du die Dinge verschieben, um deinen eigenen Designanforderungen zu entsprechen.Stellen Sie nur sicher, dass Sie das Client-Skriptverhalten im ReplicatedStorage.Bundles.Client.UIController Skript, das. PL: die Skriptsaktualisieren.
API-Referenz
Arten
Relative Zeit
Sobald das RelativeTime Bündel einem Spieler:inangeboten wird, bleibt es bis zur Ablaufzeit der Zeitdauer verfügbar.Dieser Typ wird auf dem Hauptbildschirm des Spieler:inangezeigt und fragt automatisch in zukünftigen Sitzungen nach, bis das Bündel abläuft oder der Spieler es kauft.
Ein häufiges Beispiel für diesen Bündeltyp ist ein einmalige Starterpaketangebot, das für 24 Stunden allen neuen Spielern angezeigt wird.Für branchenbestimmte Praktiken zur Implementierung von Starter-Paket-Bündeln siehe Starter-Paket-Design.
Namen | Typ | Beschreibung |
---|---|---|
includeOfflineTime | bool | (Optional) Wenn nicht festlegen, zählt nur die Zeit, die in der Erfahrung verbracht wird, zur verbleibenden Angebotsdauer. |
singleUse | bool | (Optional) Wenn es nicht festlegenist, kann der Kauf nach dem Kauf oder Ablauf wieder aktiviert werden.Wenn es festlegenist, kann es einmal gekauft oder abgelaufen werden, bevor es zum ersten Mal gekauft oder abgelaufen wird, auch wenn Sie Bundles.promptIfValidAsync mit dem BündelId anrufen. |
Fixierte Zeit
Sobald das FixedTime Bündel einem Spieler:inangeboten wird, bleibt es bis zum Ende der koordinierten universellen Zeit (UTC) verfügbar.Dieser Typ wird auf dem Hauptbildschirm des Spieler:inangezeigt und fragt automatisch in zukünftigen Sitzungen nach, bis das Bündel abläuft oder der Spieler es kauft.
Ein häufiges Beispiel für diesen Bündeltyp ist ein Urlaubsangebot, das nur für einen bestimmten Monat verfügbar ist.
Einmalig
Ein OneTime-Paket ist nur verfügbar, wenn es einem Spieler:inangeboten wird.Es wird nicht auf dem Hauptbildschirm des Spieler:inangezeigt, und sobald ein Spieler die Aufforderung schließt, kann sie nicht wieder geöffnet werden, bis sie vom Server erneut angezeigt wird.
Ein häufiges Beispiel für diesen Bündeltyp ist ein Angebot, mehr Erfahrungswährung zu kaufen, sobald ein Spieler ausgeht.