Il pacchetto funzionalità Bundles offre funzionalità out-of-the-box per vendere collezioni di oggetti ai giocatori a uno sconto.Puoi scegliere se consentire ai giocatori di acquistare pacchetti utilizzando una valuta in-experience personalizzata o Robux, quale tipo di pacchetto vuoi utilizzare, quali oggetti vuoi vendere e come richiedere ai giocatori durante il loro Partita.
Usando le opzioni di personalizzazione del pacchetto, puoi personalizzare i tuoi pacchetti per soddisfare gli obiettivi di progettazione e monetizzazione delle tue esperienze, come:
- Mirare a un basso tasso di conversione metrica offrendo pacchetti di avviamento scontati che forniscono valore ai nuovi giocatori e incoraggiano le spese precoce.
- Aumentare la profondità di spesa aumentando il numero di oggetti venduti a diversi prezzi per appeal a una gamma di giocatori.
- Monetizzare le operazioni dal vivo (LiveOps) eventi offrendo pacchetti a tempo limitato di oggetti esclusivi.

Ottieni il pacchetto
Il Creator Store è una scheda della Toolbox che puoi utilizzare per trovare tutte le risorse create da Roblox e dalla comunità Roblox per l'uso all'interno dei tuoi progetti, tra cui modello, immagine, Mesh, maglia, audio/suono, Collegare, video e font.Puoi usare il Creator Store per aggiungere uno o più asset direttamente in un'esperienza aperta, inclusi i pacchetti delle funzionalità!
Ogni pacchetto delle funzionalità richiede che il pacchetto delle funzionalità Core funzioni correttamente.Una volta che le risorse del pacchetto Core e Bundles sono all'interno del tuo Inventario, reportorio, puoi riutilizzarle in qualsiasi progetto sulla Piattaforma.
Per ottenere i pacchetti dal tuo inventario nella tua esperienza:
Aggiungi il Core e Bundles pacchetto di funzionalità al tuo inventario all'interno di Studio facendo clic sul link Aggiungi all'inventario nel seguente set di componenti.
Nella barra degli strumenti, seleziona la scheda Visualizza.
Fai clic su Toolbox . La finestra Toolbox viene visualizzata.
Nella finestra Toolbox , fai clic sulla scheda Inventario . Le visualizzazioni di Modelli miei sono ordinate.
Fai clic sul Piastrella Feature Package Core , quindi sul Piastrella Bundle Feature Package .Entrambi i cartelletti del pacchetto vengono visualizzati nella finestra Explorer .
Trascina le cartelle del pacchetto in ReplicatedStorage .
Consenti alle chiamate del deposito di dati di tracciare gli acquisti del giocatore con i pacchetti.
- Nella scheda Home della barra degli strumenti, seleziona Impostazioni di gioco .
- Passa alla scheda Sicurezza , quindi attiva Abilita l'accesso Studio ai servizi API .
Definisci le valute
Se la tua esperienza ha un proprio sistema di valuta, puoi registrarle con il pacchetto funzionale Core definendole in ReplicatedStorage.FeaturePackagesCore.Configs.Currencies.C'è un esempio commentato di una valuta delle gemme già in questo file; sostituiscilo con il Proprio.
Valutazioni
Gems = {displayName = "Gems",symbol = "💎",icon = nil,},
Lo script Currencies dice al pacchetto funzionalità Core alcuni metadati sulla tua Moneta:
- (richiesto) displayName - Il nome della tua Moneta. Se non specifici un simbolo o un'Icona, questo nome viene utilizzato nei pulsanti di acquisto (ad esempio "100 gemme").
- (opzionale) symbol - Se hai un personaggio di testo da utilizzare come icona per la tua Moneta, questo viene utilizzato invece del displayName nei pulsanti di acquisto (ad esempio "💎100").
- (opzionale) icon - Se hai un'AssetId icona di immagine per la tua Moneta, questa viene utilizzata invece del displayName nei pulsanti di acquisto (cioèl'immagine verrà posizionata a sinistra del prezzo "🖼️100")
Una volta che la tua valuta è stata configurata, devi specificare manualmente il prezzo, la Monetae l'icona del pacchetto per l'esposizione in primo piano, invece di ottenere tali informazioni dal prodotto sviluppatore associato al pacchetto.
Pacchi
-- Se vuoi utilizzare un prodotto dev, devi fornire un ID prodotto dev unico, utilizzato solo da un pacchetto.-- Richercheremo il prezzo del pacchetto e l'icona dal prodotto dello sviluppatorepricing = {priceType = CurrencyTypes.PriceType.Marketplace,devProductId = 1795621566,},-- Altrimenti, se vuoi utilizzare la valuta in-experience invece di un prodotto dev, puoi utilizzare quanto segue invece:-- Il prezzo qui è nella Monetain-experience, non Robuxpricing = {priceType = CurrencyTypes.PriceType.InExperience,price = 79,currencyId = "Gems",icon = 18712203759,},
Devi anche fare riferimento allo script BundlesExample per chiamare setInExperiencePurchaseHandler .
Esempio di bundle
local function awardInExperiencePurchase(
_player: Player,
_bundleId: Types.BundleId,
_currencyId: CurrencyTypes.CurrencyId,
_price: number
)
-- Verifica se il giocatore abbia abbastanza valuta per acquistare il pacchetto
-- Aggiorna i dati del giocatore, dai oggetti, ecc.
-- Dedurre la valuta dal Giocatore
task.wait(2)
return true
end
local function initializePurchaseHandlers()
local bundles = Bundles.getBundles()
for bundleId, bundle in bundles do
-- Il pacchetto non è associato a un prodotto per sviluppatori se non ha il inserisci / scrividi prezzo del mercato
if not bundle or bundle.pricing.priceType ~= "Marketplace" then
continue
end
Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
receiptHandlers[bundle.pricing.devProductId] = receiptHandler
end
-- Se hai valute in-experience che stai utilizzando per i pacchetti, imposta il gestore qui
for currencyId, _ in Currencies do
Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
end
end
In particolare, devi riempire awardInExperiencePurchase, che viene chiamato da un ciclo attraverso Currencies all'interno dell'esempio initializePurchaseHandlers (cioèogni currencyId è connesso al handler attraverso Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase) ).
Definire pacchetti
Tutti i pacchetti offeribili nella tua esperienza possono essere definiti entro ReplicatedStorage.Bundles.Configs.Bundles , con tipi esportati dallo script Types nello stesso folder.
Se stai usando un devProductId , devi aggiornare il principale devProductId del bundle per abbinarsi a quello nella tua esperienza.Questo è ciò che verrà richiesto attraverso MarketplaceService per acquistare il pacchetto stesso. Si consiglia vivamente di utilizzare un nuovo prodotto per sviluppatori per il bundle per rendere più facile tracciare le vendite separate. Se vuoi un pacchetto con più oggetti e se questi sono già rappresentati da prodotti per sviluppatori nella tua esperienza, non devi impostare esplicitamente il prezzo dell'oggetto/assetId/name, che verrà recuperato tramite le informazioni sul prodotto:
LEGGIME
{itemType = ItemTypes.ItemType.DevProduct,devProductId = <DEV_PRODUCT_ID>,metadata = {caption = {text = "x1",color = Color3.fromRGB(236, 201, 74),} -- La didascalia è opzionale! Puoi anche omittere questo campo}},
Altrimenti, puoi configurare manualmente quei dettagli dell'elemento:
LEGGIME
{itemType = ItemTypes.ItemType.Robux,priceInRobux = 49,icon = <IMAGE_ASSET_ID>,metadata = {caption = {text = "x1",color = Color3.fromRGB(236, 201, 74),} -- La didascalia è opzionale! Puoi anche lasciare omettere questo campo}},
Ad esempio, l'intero bundle probabilmente avrà questo aspetto:
LEGGIME
local starterBundle: Types.RelativeTimeBundle = {bundleType = Types.BundleType.RelativeTime,-- Se vuoi utilizzare un prodotto dev, devi fornire un ID prodotto dev unico, utilizzato solo da un pacchetto.-- Richercheremo il prezzo del pacchetto e l'icona dal prodotto dello sviluppatorepricing = {priceType = CurrencyTypes.PriceType.Marketplace,devProductId = <DEV_PRODUCT_ID>,},-- Altrimenti, se vuoi utilizzare la valuta in-experience invece di un prodotto dev, puoi utilizzare quanto segue invece:-- Il prezzo qui è nella Monetain-experience, non Robux-- prezzi = {-- priceType = Tipo di prezzo = CurrencyTypes.PriceType.InExperience,-- prezzo = 79,-- currencyId = <CURRENCY_ID>,-- icona = <IMAGE_ASSET_ID>,-- },includedItems = {[1] = {-- L'oggetto stesso non viene venduto attraverso un prodotto per sviluppatori, quindi indica quanto vale in Robux e fornisci un'Icona-- Il prezzoInRobux aiuta i pacchetti a mostrare il valore relativo del prezzo del pacchetto rispetto alla somma dei suoi contenutiitemType = ItemTypes.ItemType.Robux,priceInRobux = 49,icon = <IMAGE_ASSET_ID>,-- In alternativa, se questo ha un prodotto dev lascia off prezzo e icona sopra e imposta solo il devProductId-- Il prezzo e l'icona verranno recuperati dal prodotto dell' sviluppatore-- devProductId = <ITEM_DEV_PRODUCT_ID>-- Ci sono più campi metadata opzionali che sono specifici per l'interfaccia utente se necessariometadata = {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, -- Una volta acquistato o scaduto, non è più valido anche se la tua esperienza cerca di richiedere (onPlayerAdded). Puoi rendere questo falso durante il test in studio.durationInSeconds = 900, -- 15 minutiincludesOfflineTime = false, -- Calcola solo il tempo trascorso nell'esperienzametadata = {displayName = "STARTER BUNDLE",description = "Save 75% and get a head start!",},}
Integrare la logica del server
Dai un'occhiata a ReplicatedStorage.Bundles.Server.Examples.BundlesExample, che mostra come il tuo server interagirà con il pacchetto di funzionalità Bundles e gli above metodi sul ModuleScript.Gli snippet seguenti sono da quel script.
Devi principalmente collegare quattro cose una volta dopo aver trascinato il pacchetto funzione Bundles nella tua esperienza:
Connetti i gestori di acquisto attraverso Bundles.setPurchaseHandler a specificare le funzioni da chiamare per assegnare gli oggetti acquistati quando viene eseguito l'acquisto.
Esempio di bundlelocal function awardMarketplacePurchase(_player: Player, _bundleId: Types.BundleId, _receiptInfo: { [string]: any })-- Aggiorna i dati del giocatore, dai oggetti, ecc.-- ... E registra ricezioneInfo.PurchaseId così possiamo controllare se l'utente ha già questo pacchettotask.wait(2)return Enum.ProductPurchaseDecision.PurchaseGrantedendlocal function awardInExperiencePurchase(_player: Player,_bundleId: Types.BundleId,_currencyId: CurrencyTypes.CurrencyId,_price: number)-- Verifica se il giocatore abbia abbastanza valuta per acquistare il pacchetto-- Aggiorna i dati del giocatore, dai oggetti, ecc.-- Dedurre la valuta dal Giocatoretask.wait(2)return trueendlocal function initializePurchaseHandlers()local bundles = Bundles.getBundles()for bundleId, bundle in bundles do-- Il pacchetto non è associato a un prodotto per sviluppatori se non ha il inserisci / scrividi prezzo del mercatoif not bundle or bundle.pricing.priceType ~= "Marketplace" thencontinueendBundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)receiptHandlers[bundle.pricing.devProductId] = receiptHandlerend-- Se hai valute in-experience che stai utilizzando per i pacchetti, imposta il gestore quifor currencyId, _ in Currencies doBundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)endendConnetti la tua logica per MarketplaceService.ProcessReceipt , ma questo potrebbe essere fatto altrove se la tua esperienza ha già prodotti per sviluppatori in Vendita.Fondamentalmente, quando viene elaborata una ricevuta di prodotto di sviluppatore, ora chiameranno Bundles.getBundleByDevProduct per verificare se il prodotto appartiene a un pacchetto.Se lo fa, lo script chiama quindi Bundles.processReceipt .
Esempio di bundle-- Ricezione del processo dal mercato per determinare se il giocatore debba essere addebitato o menolocal 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] -- Ottieni il gestore per il prodottolocal success, result = pcall(handler, receiptInfo, player) -- Chiama il gestore per verificare se la logica di acquisto è riuscitaif 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-- Questo acquisto appartiene a un pacchetto, lascia che i bundles lo gestiscanolocal purchaseDecision = Bundles.processReceiptAsync(player, bundleId, receiptInfo)return purchaseDecision == Enum.ProductPurchaseDecision.PurchaseGrantedend-- Questo acquisto non appartiene a un pacchetto,-- ... Gestisci tutta la tua logica esistente qui se hai qualunquereturn falseendConnetti Players.PlayerAdded:Connect(Bundles.OnPlayerAdded) in modo che il pacchetto funzionalità Bundles richieda nuovamente qualsiasi bundle attivo che non è ancora scaduto per un Giocatore.
LEGGIMElocal function onPlayerAdded(player: Player)-- Dì ai pacchetti quando il giocatore si unisce così può ricaricare i suoi datiBundles.onPlayerAdded(player)-- Se hai avuto un pacchetto iniziale che volevi offrire a tutti i nuovi utenti, puoi richiedere qui-- ... i pacchetti si occuperanno se il giocatore l'ha già acquistato o se è scaduto poiché non è ripetibile-- Bundles.promptIfValidAsync(Giocatore, "StarterBundle")-- Chiamare questo qui solo per esempio, puoi chiamare questo ogni volta o ovunque tu vogliaonPromptBundleXYZEvent(player)endPacchetti di richiesta. Mentre questo dipende dal Partita, l'esempio richiede ai giocatori un StarterBundle onPlayerAdded .
La logica del pacchetto delle funzionalità Bundles garantisce che ogni giocatore non riceva un'offerta ripetuta se ha già acquistato il pacchetto, o se lascia scadere l'offerta (in base alla configurazione del pacchetto).
Ogni volta che vuoi richiedere un pacchetto a un Giocatore, chiama Bundles.promptIfValidAsync(player, bundleId).
LEGGIMElocal function onPromptBundleXYZEvent(player: Player)-- Collega qualsiasi evento esperienza che vuoi utilizzare per determinare quando a un giocatore viene richiesto il pacchetto-- ... Questo sarà ogni volta che hai incontrato i tuoi criteri di idoneità per richiedere a un giocatore il pacchetto-- ... Ad esempio, se vuoi richiedere un pacchetto quando un giocatore si unisce o quando un giocatore sale di livellotask.spawn(Bundles.promptIfValidAsync, player, <Some_Bundle_Id>)-- ... Se si creano più pacchetti, l'utilizzo di task.Rigenerare() per avvolgere la chiamata funzione sopra riporterà le discrepanze tra i conteggi al minimoend
Considera le seguenti linee guida migliori pratiche sulla ridondanza delle registrazioni di ReceiptIds:
Mentre il pacchetto di funzionalità Bundles registra gli ID di ricevuta per evitare di elaborare due volte lo stesso ricevuto, dovresti anche registrare gli ID di ricevuta all'interno delle tabelle in modo che se il flusso di acquisto fallisce dopo che il loro gestore di acquisto è già finito, sai al successivo tentativo di non assegnare nuovamente gli oggetti.
Il pacchetto di funzionalità Bundles non registrerà l'ID della ricevuta se l'acquisto fallisce a qualsiasi passo, quindi dovresti assicurarti di registrare l'ID della ricevuta nelle tue tabelle prima di elaborare la ricevuta come parte del tuo gestore d'acquisto.
Questa ridondanza aiuta a garantire che tutta la logica di acquisto sia stata gestita in modo appropriato e che il deposito di dati del tuo negozio di dati e il pacchetto di funzionalità Bundles raggiunga la coerenza eventuale, con il tuo deposito di dati che sia la fonte di verità.
Configura le costanti
Le costanti per il pacchetto funzionale Core sono live in due punti:
Le costanti condivise vivono in ReplicatedStorage.FeaturePackagesCore.Configs.SharedConstants .
Costanti specifiche del pacchetto, in questo caso il pacchetto funzione Bundles , vive in ReplicatedStorage.Bundles.Configs.Constants .
Le principali cose che potresti voler aggiustare per soddisfare i requisiti di progettazione della tua esperienza:
- AssetID del suono
- Durata dell'effetto di acquisto e colori delle particelle
- Aggiornamento della compatibilità dell'esibizione delle teste
Inoltre, puoi trovare stringhe per la traduzione divise in una posizione: ReplicatedStorage.FeaturePackagesCore.Configs.TranslationStrings .
Personalizza componenti dell'interfaccia utente
Modificando gli oggetti del pacchetto, come colori, caratteri e trasparenza, puoi regolare la presentazione visiva dei prompt del tuo pacchetto.Tuttavia, tieni presente che se sposti uno qualsiasi degli oggetti intorno gerarchicamente, il codice non sarà in grado di trovarli e dovrai apportare delle modifiche al tuo codice.
Un prompt è composto da due componenti di alto livello:
- PromptItem – La componente individuale ripetuta per ogni oggetto all'interno di un pacchetto (immagine dell'oggetto, didascalia, nome, prezzo).
- Prompt – La finestra di avviso stessa.
Anche l'head up display è composto da due componenti:
- HudItem – Un componente individuale che rappresenta ciascuna opzione del menu nell'head up display.
- Hud – Per essere riempito con programmaticamente con HudItems .
Se vuoi avere un maggiore controllo sul display delle teste, invece di utilizzare solo l'interfaccia utente HUD esistente entro ReplicatedStorage.Bundles.Objects.BundlesGui , puoi spostare le cose per soddisfare i tuoi requisiti di progettazione.Assicurati di aggiornare il comportamento dello script del client nel script ReplicatedStorage.Bundles.Client.UIController.
Riferimento API
Tipi
Tempo relativo
Una volta che il RelativeTime pacchetto viene offerto a un Giocatore, rimane disponibile fino a quando la durata del tempo scade.Questo tipo viene visualizzato sull'head up display del Giocatoree viene richiesto automaticamente nelle sessioni future fino a quando il pacchetto non scade o il giocatore non lo acquista.
Un esempio comune di questo tipo di bundle è un'offerta di pacchetto di avviamento a uso singolo che viene visualizzata a tutti i nuovi giocatori per 24 ore.Per le migliori pratiche dell'industria su come implementare i pacchetti del kit di avviamento, vedi Design del kit di avviamento.
Nome | Tipo | Descrizione |
---|---|---|
includeOfflineTime | bool | (Opzionale) Se non è Impostare, solo il tempo speso nell'esperienza contribuirà alla durata dell'offerta rimanente. |
singleUse | bool | (Opzionale) Se non è Impostare, l'acquisto può essere riattivato dopo che è stato acquistato o scaduto.Se è Impostare, una volta acquistato o scaduto la prima volta, non sarà più richiesto mai più, anche se chiami Bundles.promptIfValidAsync con il bundleId. |
Fissato il tempo
Una volta che il FixedTime pacchetto viene offerto a un Giocatore, rimane disponibile fino alla fine del tempo universale coordinato (UTC).Questo tipo viene visualizzato sull'head up display del Giocatoree viene richiesto automaticamente nelle sessioni future fino a quando il pacchetto non scade o il giocatore non lo acquista.
Un esempio comune di questo tipo di bundle è un'offerta vacanze che è disponibile solo per un mese specifico.
Una volta
Un bundle A OneTime è disponibile solo nel momento in cui viene offerto a un Giocatore.Non viene visualizzato sull'head up display del Giocatoree una volta che un giocatore chiude il prompt, non può essere riaperto fino a quando non viene richiesto nuovamente dal server.
Un esempio comune di questo tipo di pacchetto è un'offerta di acquisto di più valuta in-experience al momento in cui un giocatore esaurisce.