Das Bundles-Feature-Paket bietet sofort einsatzbereite Funktionen, um Sammlungen von Gegenständen zu ermäßigten Preisen an Spieler zu verkaufen. Sie können wählen, ob Spieler Bundles mit einer benutzerdefinierten währung innerhalb der Erfahrung oder Robux kaufen dürfen, welchen Bundle-Typ Sie verwenden möchten, welches Set von Gegenständen Sie verkaufen möchten und wie Sie die Spieler während ihres Spiels ansprechen möchten.
Mit den Anpassungsoptionen des Pakets können Sie Ihre Bundles an die Design- und Monetarisierungsziele Ihrer Erfahrungen anpassen, wie zum Beispiel:
- Zielsetzung einer niedrigen Konversionsrate, indem Sie ermäßigte Starter-Pakete anbieten, die neuen Spielern Wert geben und frühe Ausgaben anregen.
- Erhöhung der Ausgabetiefe, indem Sie Gegenstände zu verschiedenen Preisniveaus bündeln, um eine Vielzahl von Spielern anzusprechen.
- Monetarisierung von Live-Operationen (LiveOps) Ereignissen, indem Sie zeitlich begrenzte Bundles mit exklusiven Gegenständen anbieten.

Paket abrufen
Der Creator Store ist ein Tab der Toolbox, den Sie verwenden können, um alle von Roblox und der Roblox-Community für Ihre Projekte erstellten Assets zu finden, einschließlich Modelle, Bilder, Meshes, Audios, Plugins, Videos und Schriftarten. Sie können den Creator Store nutzen, um ein oder mehrere Assets direkt in eine offene Erfahrung hinzuzufügen, einschließlich Feature-Paketen!
Jedes Feature-Paket benötigt das Core-Feature-Paket, um ordnungsgemäß zu funktionieren. Sobald die Core- und Bundles-Feature-Paket-Assets in Ihrem Inventar sind, können Sie sie in jedem Projekt auf der Plattform wiederverwenden.
Um die Pakete von Ihrem Inventar in Ihre Erfahrung zu bringen:
Fügen Sie das Core- und das Bundles-Feature-Paket Ihrem Inventar in Studio hinzu, indem Sie auf den Link In Inventar hinzufügen im folgenden Komponenten-Set klicken.
Öffnen Sie über das Fenster-Menü oder die Startseite-Tab-Werkzeuge die Toolbox.
Klicken Sie im Toolbox-Fenster auf den Inventar-Tab. Die Sortierung Meine Modelle wird angezeigt.

Klicken Sie auf die Kachel Feature-Paket Core und dann auf die Kachel Bundle-Feature-Paket. Beide Paketordner werden im Explorer-Fenster angezeigt.
Ziehen Sie die Paketordner in ReplicatedStorage.
Erlauben Sie Datenstore-Anfragen, um die Käufe der Spieler mit den Paketen nachzuverfolgen.
- Öffnen Sie das Datei ⟩ Erfahrungs-Einstellungen-Fenster von Studio.
- Navigieren Sie zum Sicherheit-Tab und aktivieren Sie Studio-Zugriff auf API-Services aktivieren.
Währungen definieren
Wenn Ihre Erfahrung ein eigenes Währungssystem hat, können Sie diese mit dem Core-Feature-Paket registrieren, indem Sie sie in ReplicatedStorage.FeaturePackagesCore.Configs.Currencies definieren. Es gibt bereits ein commented out Beispiel einer Gem-Währung in dieser Datei; ersetzen Sie es durch Ihre eigene.
WährungenGems = {displayName = "Edelsteine",symbol = "💎",icon = nil,},
Das Currencies-Skript teilt dem Core-Feature-Paket einige Metadaten über Ihre Währung mit:
- (erforderlich) displayName - Der Name Ihrer Währung. Wenn Sie kein Symbol oder Icon angeben, wird dieser Name in Kauf-Buttons verwendet (d. h. "100 Edelsteine").
- (optional) symbol - Wenn Sie ein Textzeichen als Symbol für Ihre Währung verwenden möchten, wird dies anstelle des displayName in Kauf-Buttons verwendet (d. h. "💎100").
- (optional) icon - Wenn Sie ein AssetId-Bildsymbol für Ihre Währung haben, wird dies anstelle des displayName in Kauf-Buttons verwendet (d. h. das Bild wird links neben dem Preis "🖼️100" platziert).
Sobald Ihre Währung eingerichtet ist, müssen Sie manuell den Preis, die Währung und das Icon des Bundles für die Heads-up-Anzeige angeben, anstatt diese Informationen aus dem zugehörigen Entwicklerprodukt des Bundles abzurufen.
Bundles-- Wenn Sie ein Entwicklerprodukt verwenden möchten, müssen Sie eine eindeutige devProductId angeben, die nur von einem Bundle verwendet wird.-- Wir werden den Bundle-Preis und das Icon vom Entwicklerprodukt abrufenpricing = {priceType = CurrencyTypes.PriceType.Marketplace,devProductId = 1795621566,},-- Andernfalls, wenn Sie stattdessen eine in-experience Währung verwenden möchten, können Sie Folgendes verwenden:-- Der Preis hier ist in der in-experience Währung, nicht in Robuxpricing = {priceType = CurrencyTypes.PriceType.InExperience,price = 79,currencyId = "Gems",icon = 18712203759,},
Sie müssen auch das BundlesExample-Skript referenzieren, um setInExperiencePurchaseHandler aufzurufen.
BundlesExample
local function awardInExperiencePurchase(
_player: Player,
_bundleId: Types.BundleId,
_currencyId: CurrencyTypes.CurrencyId,
_price: number
)
-- Überprüfen Sie, ob der Spieler genügend Währung hat, um das Bundle zu kaufen
-- Aktualisieren Sie die Spieldaten, geben Sie Items, etc.
-- Ziehen Sie die Währung vom Spieler ab
task.wait(2)
return true
end
local function initializePurchaseHandlers()
local bundles = Bundles.getBundles()
for bundleId, bundle in bundles do
-- Ein Bundle ist nicht mit einem Entwicklerprodukt assoziiert, wenn es keinen Marktpreis-Typ hat
if not bundle or bundle.pricing.priceType ~= "Marketplace" then
continue
end
Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
receiptHandlers[bundle.pricing.devProductId] = receiptHandler
end
-- Wenn Sie irgendwelche in-experience Währungen verwenden, die Sie für Bundles verwenden, setzen Sie den Handler hier
for currencyId, _ in Currencies do
Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
end
end
Sie müssen speziell awardInExperiencePurchase ausfüllen, das durch eine Schleife durch Currencies innerhalb des Beispiels initializePurchaseHandlers aufgerufen wird (d. h. jede currencyId ist über Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase) mit dem Handler verbunden).
Bundles definieren
Alle Bundles, die in Ihrer Erfahrung angeboten werden können, können innerhalb von ReplicatedStorage.Bundles.Configs.Bundles definiert werden, wobei Typen aus dem Types-Skript im selben Ordner exportiert werden.
Wenn Sie eine devProductId verwenden, müssen Sie die Haupt-devProductId des Bundles aktualisieren, um mit der in Ihrer Erfahrung übereinzustimmen. Dies wird durch MarketplaceService aufgefordert, um das Bundle selbst zu kaufen. Es wird dringend empfohlen, ein neues Entwicklerprodukt für das Bundle zu verwenden, um separate Verkäufe leichter nachverfolgen zu können.
Wenn Sie ein Bundle mit mehreren Gegenständen möchten und wenn diese bereits durch Entwicklerprodukte in Ihrer Erfahrung dargestellt sind, müssen Sie nicht explizit den Preis/assetId/Namen des Gegenstands festlegen, die über die Produktinformationen abgerufen werden:
README{itemType = ItemTypes.ItemType.DevProduct,devProductId = <DEV_PRODUCT_ID>,metadata = {caption = {text = "x1",color = Color3.fromRGB(236, 201, 74),} -- Beschriftung ist optional! Sie können dieses Feld auch weglassen}},
Andernfalls können Sie diese Einzelheiten der Gegenstände manuell konfigurieren:
README{itemType = ItemTypes.ItemType.Robux,priceInRobux = 49,icon = <IMAGE_ASSET_ID>,metadata = {caption = {text = "x1",color = Color3.fromRGB(236, 201, 74),} -- Beschriftung ist optional! Sie können dieses Feld auch weglassen}},
Ihr gesamtes Bundle wird wahrscheinlich so aussehen:
READMElocal starterBundle: Types.RelativeTimeBundle = {bundleType = Types.BundleType.RelativeTime,-- Wenn Sie ein Entwicklerprodukt verwenden möchten, müssen Sie eine eindeutige devProductId angeben, die nur von einem Bundle verwendet wird.-- Wir werden den Bundle-Preis und das Icon vom Entwicklerprodukt abrufenpricing = {priceType = CurrencyTypes.PriceType.Marketplace,devProductId = <DEV_PRODUCT_ID>,},-- Andernfalls, wenn Sie stattdessen eine in-experience Währung verwenden möchten, können Sie Folgendes verwenden:-- Preis hier ist in der in-experience Währung, nicht in Robux-- pricing = {-- priceType = CurrencyTypes.PriceType.InExperience,-- price = 79,-- currencyId = <CURRENCY_ID>,-- icon = <IMAGE_ASSET_ID>,-- },includedItems = {[1] = {-- Der Gegenstand selbst wird nicht über ein Entwicklerprodukt verkauft, also geben Sie an, wie viel er in Robux wert ist und geben Sie ein Icon an-- Der priceInRobux hilft Bundles, den relativen Wert des Bundle-Preises im Vergleich zur 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 Icon oben weg und setzen Sie einfach die devProductId-- Der Preis und das Icon werden vom Entwicklerprodukt abgerufen-- devProductId = <ITEM_DEV_PRODUCT_ID>-- Es gibt weitere optionale Metadatenfelder, die UI-spezifisch sind, falls erforderlichmetadata = {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, -- Einmal gekauft oder abgelaufen, nicht mehr gültig, selbst wenn Ihre Erfahrung versucht, ihn zu zeigen (onPlayerAdded). Sie können dies während des Testens im Studio auf false setzen.durationInSeconds = 900, -- 15 MinutenincludesOfflineTime = false, -- Nur die Zeit zählen, die in der Erfahrung vergangen istmetadata = {displayName = "STARTER BUNDLE",description = "Sparen Sie 75 % und erhalten Sie einen Vorsprung!",},}
Serverlogik integrieren
Werfen Sie einen Blick auf ReplicatedStorage.Bundles.Server.Examples.BundlesExample, das zeigt, wie Ihr Server mit dem Bundles-Feature-Paket und den oben genannten Methoden im ModuleScript interagieren wird. Die nachstehenden Ausschnitte stammen aus diesem Skript.
Sie müssen hauptsächlich vier Dinge anschließen, nachdem Sie das Bundles-Feature-Paket in Ihre Erfahrung gezogen haben:
Verbinden Sie Kaufhandler durch Bundles.setPurchaseHandler, um die Funktionen anzugeben, die zum Auszeichnen von Gegenständen aufgerufen werden sollen, wenn ein Kauf verarbeitet wird.
BundlesExamplelocal function awardMarketplacePurchase(_player: Player, _bundleId: Types.BundleId, _receiptInfo: { [string]: any })-- Aktualisieren Sie die Spieldaten, geben Sie Gegenstände, etc.-- ... UND zeichnen Sie receiptInfo.PurchaseId auf, sodass wir überprüfen können, ob der Benutzer dieses Bundle bereits hattask.wait(2)return Enum.ProductPurchaseDecision.PurchaseGrantedendlocal function awardInExperiencePurchase(_player: Player,_bundleId: Types.BundleId,_currencyId: CurrencyTypes.CurrencyId,_price: number)-- Überprüfen Sie, ob der Spieler genügend Währung hat, um das Bundle zu kaufen-- Aktualisieren Sie die Spieldaten, geben Sie Gegenstände, etc.-- Ziehen Sie die Währung vom Spieler abtask.wait(2)return trueendlocal function initializePurchaseHandlers()local bundles = Bundles.getBundles()for bundleId, bundle in bundles do-- Ein Bundle ist nicht mit einem Entwicklerprodukt assoziiert, wenn es keinen Marktpreis-Typ hatif not bundle or bundle.pricing.priceType ~= "Marketplace" thencontinueendBundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)receiptHandlers[bundle.pricing.devProductId] = receiptHandlerend-- Wenn Sie irgendwelche in-experience Währungen verwenden, die Sie für Bundles verwenden, setzen Sie den Handler hierfor currencyId, _ in Currencies doBundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)endendVerbinden Sie Ihre Logik für MarketplaceService.ProcessReceipt, aber dies kann auch anderswo erfolgen, wenn Ihre Erfahrung bereits Entwicklerprodukte zum Verkauf hat. Im Wesentlichen, wenn ein Entwicklerproduktquittung verarbeitet wird, wird jetzt Bundles.getBundleByDevProduct aufgerufen, um zu überprüfen, ob das Produkt zu einem Bundle gehört. Wenn ja, ruft das Skript dann Bundles.processReceipt auf.
BundlesExample-- Quittung vom Marktplatz verarbeiten, 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 warif not success or not result thenwarn("Fehler beim Verarbeiten der Quittung:", 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 Bundle, lassen Sie Bundles dies übernehmenlocal purchaseDecision = Bundles.processReceiptAsync(player, bundleId, receiptInfo)return purchaseDecision == Enum.ProductPurchaseDecision.PurchaseGrantedend-- Dieser Kauf gehört nicht zu einem Bundle,-- ... Behandeln Sie hier all Ihre vorhandene Logik, falls Sie welche habenreturn falseendVerbinden Sie Players.PlayerAdded:Connect(Bundles.OnPlayerAdded), damit das Bundles-Feature-Paket alle aktiven Bundles, die noch nicht abgelaufen sind, für einen Spieler erneut anzeigt.
READMElocal function onPlayerAdded(player: Player)-- Informieren Sie Bundles, wenn der Spieler beitritt, damit es seine Daten neu laden kannBundles.onPlayerAdded(player)-- Wenn Sie ein Starter-Bundle hatten, das Sie allen neuen Nutzern anbieten möchten, könnten Sie das hier anzeigen-- ... Bundles kümmert sich darum, ob der Spieler es bereits gekauft hat oder ob es abgelaufen ist, da es nicht wiederholt werden kann-- Bundles.promptIfValidAsync(player, "StarterBundle")-- Dies hier nur als Beispiel nennend, Sie können dies jederzeit oder überall aufrufen, wo Sie möchtenonPromptBundleXYZEvent(player)endBundles anfragen. Während dies vom Gameplay abhängt, bietet das Beispiel Bundles mit einem StarterBundle onPlayerAdded an.
Die Logik des Bundles-Feature-Pakets stellt sicher, dass jeder Spieler kein Wiederangebot erhält, wenn er das Bundle bereits gekauft hat oder wenn das Angebot bereits abgelaufen ist (basierend auf der Bundle-Konfiguration).
Wann immer Sie ein Bundle einem Spieler anbieten möchten, rufen Sie Bundles.promptIfValidAsync(player, bundleId) auf.
READMElocal function onPromptBundleXYZEvent(player: Player)-- Verbinden Sie jedes beliebige Ereignis innerhalb der Erfahrung, das Sie verwenden möchten, um zu bestimmen, wann ein Spieler das Bundle angeboten bekommt-- ... Dies wird jedes Mal sein, wenn Sie die Berechtigungskriterien erfüllt haben, um einem Spieler das Bundle anzubieten-- ... Zum Beispiel, wenn Sie ein Bundle anbieten möchten, wenn ein Spieler beitritt oder wenn ein Spieler aufsteigttask.spawn(Bundles.promptIfValidAsync, player, <Some_Bundle_Id>)-- ... Wenn Sie mehrere Bundles erstellen, minimiert die Verwendung von task.spawn() den Unterschied zwischen den Countdown-Zeitenend
Berücksichtigen Sie die folgenden besten Praktiken zur redundanten Aufzeichnung von ReceiptIds:
Während das Bundles-Feature-Paket ReceiptIds aufzeichnet, um zu vermeiden, dass dieselbe Quittung zweimal verarbeitet wird, sollten Sie auch ReceiptIds in Ihren Tabellen aufzeichnen, sodass Sie im Falle eines Kaufablaufs, nachdem der Kauf-Handler bereits abgeschlossen ist, wissen, dass Sie keine Gegenstände erneut auszeichnen sollten.
Das Bundles-Feature-Paket zeichnet die ReceiptId nicht auf, wenn der Kauf bei einem Schritt fehl schlägt. Stellen Sie daher sicher, dass Sie die ReceiptId in Ihren Tabellen aufzeichnen, bevor Sie die Quittung als Teil Ihres purchaseHandlers verarbeiten.
Diese Redundanz hilft sicherzustellen, dass alle Kauflogik angemessen behandelt wurde und dass Ihr Datenstore und der Datenstore des Bundles-Feature-Pakets letztendlich konsistent sind, wobei Ihr Datenstore die Quelle der Wahrheit ist.
Konstanten konfigurieren
Konstanten für das Core-Feature-Paket befinden sich an zwei Stellen:
Gemeinschaftliche Konstanten befinden sich in ReplicatedStorage.FeaturePackagesCore.Configs.SharedConstants.
Paket-spezifische Konstanten, in diesem Fall das Bundles-Feature-Paket, befinden sich in ReplicatedStorage.Bundles.Configs.Constants.
Die wichtigsten Dinge, die Sie anpassen möchten, um die Designanforderungen Ihrer Erfahrung zu erfüllen:
- Sound-Asset-IDs
- Kaufeffekt-Dauer und Partikel-Farben
- Zusammenklappbarkeit der Heads-up-Anzeige
Darüber hinaus können Sie Strings für die Übersetzung an einem Ort finden: ReplicatedStorage.FeaturePackagesCore.Configs.TranslationStrings.
UI-Komponenten anpassen
Durch die Modifizierung der Paketobjekte, wie Farben, Schriftarten und Transparenz, können Sie die visuelle Präsentation Ihrer Bundle-Aufforderungen anpassen. Beachten Sie jedoch, dass, wenn Sie einige der Objekte hierarchisch verschieben, der Code sie nicht finden kann und Sie Ihre Codes anpassen müssen.
Eine Aufforderung besteht aus zwei Hauptkomponenten:
- PromptItem – Die einzelne Komponente, die für jeden Gegenstand innerhalb eines Bundles (Gegenstandsbild, Beschriftung, Name, Preis) wiederholt wird.
- Prompt – Das Aufforderungsfenster selbst.
Die Heads-up-Anzeige besteht ebenfalls aus zwei Komponenten:
- HudItem – Eine einzelne Komponente, die jede Menüoption in der Heads-up-Anzeige darstellt.
- Hud – Um durch HudItems programmiert ausgefüllt zu werden.
Wenn Sie eine größere Kontrolle über die Heads-up-Anzeige möchten, anstatt nur die vorhandene HUD-UI innerhalb von ReplicatedStorage.Bundles.Objects.BundlesGui zu verwenden, können Sie die Dinge umstellen, um Ihren eigenen Designanforderungen gerecht zu werden. Stellen Sie lediglich sicher, dass Sie das Verhalten des Client-Skripts im Skript ReplicatedStorage.Bundles.Client.UIController aktualisieren.
API-Referenz
Typen
RelativeTime
Sobald das RelativeTime-Bundle einem Spieler angeboten wird, bleibt es bis der Zeitablauf abgelaufen ist, verfügbar. Dieser Typ wird in der Heads-up-Anzeige des Spielers angezeigt und fordert automatisch in zukünftigen Sitzungen an, bis das Bundle abläuft oder der Spieler es kauft.
Ein häufiges Beispiel für diesen Bundlestyp ist ein einmaliges Starter-Pack-Angebot, das allen neuen Spielern für 24 Stunden angezeigt wird.
| Name | Typ | Beschreibung |
|---|---|---|
| includeOfflineTime | bool | (Optional) Wenn nicht gesetzt, zählt nur die verbrachte Zeit in der Erfahrung gegenüber der verbleibenden Angebotsdauer. |
| singleUse | bool | (Optional) Wenn nicht gesetzt, kann der Kauf reaktiviert werden, nachdem er gekauft oder abgelaufen ist. Wenn gesetzt, wird es nach dem ersten Kauf oder Ablauf niemals wieder angeboten, selbst wenn Sie Bundles.promptIfValidAsync mit der bundleId aufrufen. |
FixedTime
Sobald das FixedTime-Bundle einem Spieler angeboten wird, bleibt es bis zum Ende der festgelegten koordinierten Weltzeit (UTC) verfügbar. Dieser Typ wird in der Heads-up-Anzeige des Spielers angezeigt und fordert automatisch in zukünftigen Sitzungen an, bis das Bundle abläuft oder der Spieler es kauft.
Ein häufiges Beispiel für diesen Bundlestyp ist ein Feiertagsangebot, das nur einen bestimmten Monat lang verfügbar ist.
OneTime
Ein OneTime-Bundle ist nur zu dem Zeitpunkt verfügbar, zu dem es einem Spieler angeboten wird. Es wird nicht in der Heads-up-Anzeige des Spielers angezeigt, und sobald ein Spieler die Aufforderung schließt, kann sie nicht wieder geöffnet werden, bis sie vom Server erneut angefordert wird.
Ein häufiges Beispiel für diesen Bundlestyp ist ein Angebot, mehr Währung innerhalb der Erfahrung zu kaufen, sobald ein Spieler ausgeht.