Pacchetto Bundles

*Questo contenuto è tradotto usando AI (Beta) e potrebbe contenere errori. Per visualizzare questa pagina in inglese, clicca qui.

Il pacchetto Bundles offre funzionalità pronte all'uso per vendere collezioni di oggetti ai giocatori a un prezzo scontato. Puoi scegliere se consentire ai giocatori di acquistare bundle utilizzando una valuta personalizzata all'interno dell'esperienza o Robux, quale tipo di bundle desideri utilizzare, quale set di oggetti vuoi vendere e come vuoi invitare i giocatori durante il loro gameplay.

Utilizzando le opzioni di personalizzazione del pacchetto, puoi adattare i tuoi bundle per soddisfare gli obiettivi di design e monetizzazione delle tue esperienze, come:

  • Puntare a un basso tasso di conversione offrendo pacchetti di avvio scontati che forniscono valore ai nuovi giocatori e incoraggiano le spese iniziali.
  • Aumentare la profondità di spesa raggruppando oggetti a vari prezzi per attrarre una gamma di giocatori.
  • Monetizzare le operazioni dal vivo (LiveOps) eventi offrendo bundle di oggetti esclusivi a tempo limitato.

Ottieni il pacchetto

Il Creator Store è una scheda del Toolbox che puoi utilizzare per trovare tutte le risorse create da Roblox e dalla comunità Roblox per l'uso nei tuoi progetti, inclusi modelli, immagini, mesh, audio, plugin, video e risorse font. Puoi utilizzare il Creator Store per aggiungere una o più risorse direttamente in un'esperienza aperta, inclusi i pacchetti di funzionalità!

Ogni pacchetto di funzionalità richiede il pacchetto di funzionalità Core per funzionare correttamente. Una volta che le risorse dei pacchetti di funzionalità Core e Bundles sono nel tuo inventario, puoi riutilizzarle in qualsiasi progetto sulla piattaforma.

Per ottenere i pacchetti dal tuo inventario alla tua esperienza:

  1. Aggiungi il pacchetto di funzionalità Core e Bundles al tuo inventario all'interno di Studio facendo clic sul link Aggiungi all'inventario nel seguente set di componenti.

  2. Dal menu Finestra di Studio o dalla barra degli strumenti della scheda Home, apri il Toolbox.

  3. Nella finestra Toolbox, fai clic sulla scheda Inventario. Il filtro I miei modelli viene visualizzato.

    Finestra del Toolbox di Studio con la scheda Inventario evidenziata.
  4. Fai clic sulla tile Pacchetto di Funzionalità Core, quindi sulla tile Pacchetto di Funzionalità Bundle. Entrambi i folder dei pacchetti vengono visualizzati nella finestra Esplora.

  5. Trascina i folder dei pacchetti in ReplicatedStorage.

  6. Consenti le chiamate al data store per tracciare gli acquisti dei giocatori con i pacchetti.

    1. Apri la finestra FileImpostazioni esperienza di Studio.
    2. Naviga nella scheda Sicurezza, quindi abilita Abilita accesso studio ai servizi API.

Definisci le valute

Se la tua esperienza ha un proprio sistema di valuta, puoi registrarlo con il pacchetto di funzionalità Core definendolo in ReplicatedStorage.FeaturePackagesCore.Configs.Currencies. Esiste un esempio commentato di una valuta Gems già in questo file; sostituiscilo con il tuo.

Valute

Gems = {
displayName = "Gems",
symbol = "💎",
icon = nil,
},

Lo script Currencies informa il pacchetto di funzionalità Core su alcuni metadati riguardanti la tua valuta:

  • (obbligatorio) displayName - Il nome della tua valuta. Se non specifichi un simbolo o un'icona, questo nome viene utilizzato nei pulsanti di acquisto (ad es. "100 Gems").
  • (facoltativo) symbol - Se hai un carattere testuale da utilizzare come icona per la tua valuta, questo viene utilizzato al posto del displayName nei pulsanti di acquisto (ad es. "💎100").
  • (facoltativo) icon - Se hai un'icona di immagine AssetId per la tua valuta, questa viene utilizzata al posto del displayName nei pulsanti di acquisto (ad es. l'immagine sarà posizionata a sinistra del prezzo "🖼️100")

Una volta configurata la tua valuta, devi specificare manualmente il prezzo del bundle, la valuta e l'icona per il display informativo invece che queste informazioni vengano recuperate dal prodotto sviluppatore associato al bundle.

Bundles

-- Se vuoi utilizzare un prodotto sviluppatore, devi fornire un devProductId unico, utilizzato solo da un bundle.
-- Recupereremo prezzo e icona del bundle dal prodotto sviluppatore
pricing = {
priceType = CurrencyTypes.PriceType.Marketplace,
devProductId = 1795621566,
},
-- Altrimenti, se desideri utilizzare la valuta in esperienza invece di un prodotto sviluppatore, puoi utilizzare quanto segue:
-- Il prezzo qui è nella valuta in esperienza, non in Robux
pricing = {
priceType = CurrencyTypes.PriceType.InExperience,
price = 79,
currencyId = "Gems",
icon = 18712203759,
},

Devi anche fare riferimento allo script BundlesExample per chiamare setInExperiencePurchaseHandler.

BundlesExample

local function awardInExperiencePurchase(
_player: Player,
_bundleId: Types.BundleId,
_currencyId: CurrencyTypes.CurrencyId,
_price: number
)
-- Controlla se il giocatore ha abbastanza valuta per acquistare il bundle
-- Aggiorna i dati del giocatore, fornisci oggetti, ecc.
-- Deduci la valuta dal giocatore
task.wait(2)
return true
end
local function initializePurchaseHandlers()
local bundles = Bundles.getBundles()
for bundleId, bundle in bundles do
-- Il bundle non è associato a un prodotto sviluppatore se non ha un tipo di prezzo marketplace
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 esperienza che stai utilizzando per i bundle, imposta il gestore qui
for currencyId, _ in Currencies do
Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
end
end

In particolare, devi completare awardInExperiencePurchase, che viene chiamato da un ciclo attraverso Currencies all'interno dell'esempio initializePurchaseHandlers (cioè, ogni currencyId è collegato al gestore tramite Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)).

Definisci i bundle

Tutti i bundle offerti nella tua esperienza possono essere definiti all'interno di ReplicatedStorage.Bundles.Configs.Bundles, con tipi esportati dallo script Types nella stessa cartella.

Se stai usando un devProductId, devi aggiornare il devProductId principale del bundle per corrispondere a quello nella tua esperienza. Questo sarà ciò che verrà richiesto attraverso MarketplaceService per acquistare il bundle stesso. È fortemente consigliato utilizzare un nuovo prodotto sviluppatore per il bundle per facilitare il tracciamento delle vendite separate.

Se desideri un bundle con più oggetti, e se questi sono già rappresentati da prodotti sviluppatore nella tua esperienza, non è necessario impostare esplicitamente prezzo/assetId/nome dell'oggetto, che verranno recuperati tramite le informazioni sul prodotto:

README

{
itemType = ItemTypes.ItemType.DevProduct,
devProductId = <DEV_PRODUCT_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
} -- La didascalia è facoltativa! Puoi anche omettere questo campo
}
},

Altrimenti, puoi configurare manualmente quei dettagli dell'oggetto:

README

{
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 49,
icon = <IMAGE_ASSET_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
} -- La didascalia è facoltativa! Puoi anche omettere questo campo
}
},

Ad esempio, l'intero bundle potrebbe sembrare simile a questo:

README

local starterBundle: Types.RelativeTimeBundle = {
bundleType = Types.BundleType.RelativeTime,
-- Se vuoi utilizzare un prodotto sviluppatore, devi fornire un devProductId unico, utilizzato solo da un bundle.
-- Recupereremo prezzo e icona del bundle dal prodotto sviluppatore
pricing = {
priceType = CurrencyTypes.PriceType.Marketplace,
devProductId = <DEV_PRODUCT_ID>,
},
-- Altrimenti, se desideri utilizzare la valuta in esperienza invece di un prodotto sviluppatore, puoi usare quanto segue:
-- Il prezzo qui è nella valuta in esperienza, non in Robux
-- pricing = {
-- priceType = CurrencyTypes.PriceType.InExperience,
-- price = 79,
-- currencyId = <CURRENCY_ID>,
-- icon = <IMAGE_ASSET_ID>,
-- },
includedItems = {
[1] = {
-- L'oggetto stesso non viene venduto tramite un prodotto sviluppatore, quindi indica quanto vale in Robux e fornisci un'icona
-- Il priceInRobux aiuta i Bundle a mostrare il valore relativo del prezzo del bundle rispetto alla somma dei suoi contenuti
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 49,
icon = <IMAGE_ASSET_ID>,
-- In alternativa, se questo ha un prodotto sviluppatore ometti prezzo e icona sopra e imposta solo il devProductId
-- Il prezzo e l'icona verranno recuperati dal prodotto sviluppatore
-- devProductId = <ITEM_DEV_PRODUCT_ID>
-- Ci sono più campi di metadati opzionali specifici dell'interfaccia utente se necessario
metadata = {
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 impostare questo valore su false durante i test in studio.
durationInSeconds = 900, -- 15 minuti
includesOfflineTime = false, -- Conta solo il tempo trascorso nell'esperienza
metadata = {
displayName = "BUNDLE INIZIALE",
description = "Risparmia il 75% e ottieni un vantaggio!",
},
}

Integra 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 i metodi sopra sul ModuleScript. Gli estratti qui sotto provengono da quel script.

Devi principalmente collegare quattro cose una volta trascinato il pacchetto di funzionalità Bundles nella tua esperienza:

  1. Collega i gestori di acquisto tramite Bundles.setPurchaseHandler per specificare le funzioni da chiamare per premiare articoli quando viene elaborato un acquisto.

    BundlesExample

    local function awardMarketplacePurchase(_player: Player, _bundleId: Types.BundleId, _receiptInfo: { [string]: any })
    -- Aggiorna i dati del giocatore, fornisci oggetti, ecc.
    -- ... E registra receiptInfo.PurchaseId così possiamo controllare se l'utente ha già questo bundle
    task.wait(2)
    return Enum.ProductPurchaseDecision.PurchaseGranted
    end
    local function awardInExperiencePurchase(
    _player: Player,
    _bundleId: Types.BundleId,
    _currencyId: CurrencyTypes.CurrencyId,
    _price: number
    )
    -- Controlla se il giocatore ha abbastanza valuta per acquistare il bundle
    -- Aggiorna i dati del giocatore, fornisci oggetti, ecc.
    -- Deduci la valuta dal giocatore
    task.wait(2)
    return true
    end
    local function initializePurchaseHandlers()
    local bundles = Bundles.getBundles()
    for bundleId, bundle in bundles do
    -- Il bundle non è associato a un prodotto sviluppatore se non ha un tipo di prezzo marketplace
    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 esperienza che stai utilizzando per i bundle, imposta il gestore qui
    for currencyId, _ in Currencies do
    Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
    end
    end
  2. Collega la tua logica per MarketplaceService.ProcessReceipt, ma questo potrebbe essere fatto altrove se la tua esperienza ha già prodotti sviluppatore in vendita. Fondamentalmente, quando una ricevuta di prodotto sviluppatore viene elaborata, ora chiameranno Bundles.getBundleByDevProduct per controllare se il prodotto appartiene a un bundle. Se sì, lo script chiama quindi Bundles.processReceipt.

    BundlesExample

    -- Elabora la ricevuta dal marketplace per determinare se il giocatore deve essere addebitato o meno
    local function processReceipt(receiptInfo): Enum.ProductPurchaseDecision
    local userId, productId = receiptInfo.PlayerId, receiptInfo.ProductId
    local player = Players:GetPlayerByUserId(userId)
    if not player then
    return Enum.ProductPurchaseDecision.NotProcessedYet
    end
    local handler = receiptHandlers[productId] -- Ottieni il gestore per il prodotto
    local success, result = pcall(handler, receiptInfo, player) -- Chiama il gestore per controllare se la logica dell'acquisto ha avuto successo
    if not success or not result then
    warn("Impossibile elaborare la ricevuta:", receiptInfo, result)
    return Enum.ProductPurchaseDecision.NotProcessedYet
    end
    return Enum.ProductPurchaseDecision.PurchaseGranted
    end
    local function receiptHandler(receiptInfo: { [string]: any }, player: Player)
    local bundleId, _bundle = Bundles.getBundleByProductId(receiptInfo.ProductId)
    if bundleId then
    -- Questo acquisto appartiene a un bundle, lascia che i Bundles lo gestiscano
    local purchaseDecision = Bundles.processReceiptAsync(player, bundleId, receiptInfo)
    return purchaseDecision == Enum.ProductPurchaseDecision.PurchaseGranted
    end
    -- Questo acquisto non appartiene a un bundle,
    -- ... Gestisci qui tutta la tua logica esistente se ne hai
    return false
    end
  3. Collega Players.PlayerAdded:Connect(Bundles.OnPlayerAdded) in modo che il pacchetto di funzionalità Bundles riprometta eventuali bundle attivi che non sono ancora scaduti per un giocatore.

    README

    local function onPlayerAdded(player: Player)
    -- Comunica a Bundles quando il giocatore entra così può ricaricare i dati
    Bundles.onPlayerAdded(player)
    -- Se avevi un bundle iniziale che volevi offrire a tutti i nuovi utenti, potresti richiedere quello qui
    -- ... Bundles gestirà se il giocatore ha già acquistato o se è scaduto poiché non è ripetibile
    -- Bundles.promptIfValidAsync(player, "StarterBundle")
    -- Chiamando questo qui solo per esempio, puoi chiamare questo ogni volta o ovunque vuoi
    onPromptBundleXYZEvent(player)
    end
  4. Richiedi i bundle. Sebbene dipenda dal gameplay, l'esempio richiede ai giocatori un StarterBundle onPlayerAdded.

    • La logica del pacchetto di funzionalità Bundles assicura che ogni giocatore non riceva un'offerta ripetuta se ha già acquistato il bundle, o se ha lasciato scadere l'offerta (in base alla configurazione del bundle).

    • Ogni volta che desideri richiedere un bundle a un giocatore, chiama Bundles.promptIfValidAsync(player, bundleId).

    README

    local function onPromptBundleXYZEvent(player: Player)
    -- Collega qualsiasi evento dell'esperienza vuoi utilizzare per determinare quando un giocatore viene invitato al bundle
    -- ... Questo sarà ogni volta che hai soddisfatto i tuoi criteri di idoneità per invitare un giocatore al bundle
    -- ... Ad esempio, se desideri richiedere un bundle quando un giocatore entra, o quando un giocatore sale di livello
    task.spawn(Bundles.promptIfValidAsync, player, <Some_Bundle_Id>)
    -- ... Se crei più bundle, utilizzare task.spawn() per avvolgere la chiamata alla funzione sopra minimizzerà le discrepanze tra i countdown
    end

Considera le seguenti linee guida sulle migliori pratiche per le registrazioni ridondanti degli ReceiptIds:

  • Anche se il pacchetto di funzionalità Bundles registra ReceiptIds per evitare di elaborare la stessa ricevuta due volte, dovresti anche registrare ReceiptIds all'interno delle tue tabelle in modo che se il flusso di acquisto fallisce dopo che il gestore degli acquisti ha già finito, sai in una eventuale nuova iterazione di non premiare nuovamente gli oggetti.

  • Il pacchetto di funzionalità Bundles non registrerà il ReceiptId se l'acquisto fallisce in alcun passaggio, quindi dovresti assicurarti di registrare il ReceiptId nelle tue tabelle prima di elaborare la ricevuta come parte del tuo purchaseHandler.

  • Questa ridondanza aiuta a garantire che tutta la logica di acquisto sia stata gestita in modo appropriato e che il tuo data store e il data store del pacchetto di funzionalità Bundles raggiungano una consistenza finale, con il tuo data store che funge da fonte di verità.

Configura costanti

Le costanti per il pacchetto di funzionalità Core si trovano in due posti:

  • Le costanti condivise si trovano in ReplicatedStorage.FeaturePackagesCore.Configs.SharedConstants.

  • Le costanti specifiche del pacchetto, in questo caso il pacchetto di funzionalità Bundles, si trovano in ReplicatedStorage.Bundles.Configs.Constants.

Le principali cose che potresti voler modificare per soddisfare i requisiti di design della tua esperienza:

  • ID degli asset audio
  • Durata dell'effetto d'acquisto e colori delle particelle
  • Collassabilità del display informativo

Inoltre, puoi trovare le stringhe per la traduzione suddivise in un'unica posizione: ReplicatedStorage.FeaturePackagesCore.Configs.TranslationStrings.

Personalizza i componenti UI

Modificando gli oggetti del pacchetto, come colori, carattere e trasparenza, puoi aggiustare la presentazione visiva dei tuoi avvisi di bundle. Tuttavia, tieni presente che se sposti uno qualsiasi degli oggetti gerarchicamente, il codice non sarà in grado di trovarli e dovrai apportare delle modifiche al tuo codice.

Un avviso è composto da due componenti ad alto livello:

  • PromptItem – Il componente individuale ripetuto per ciascun elemento all'interno di un bundle (immagine dell'oggetto, didascalia, nome, prezzo).
  • Prompt – La finestra dell'avviso stesso.

Il display informativo è composto anche da due componenti:

  • HudItem – Un componente individuale che rappresenta ciascuna opzione di menu nel display informativo.
  • Hud – Da riempire programmaticamente con HudItems.

Se desideri avere un maggiore controllo sul display informativo, invece di utilizzare semplicemente l'interfaccia HUD esistente all'interno di ReplicatedStorage.Bundles.Objects.BundlesGui, puoi spostare le cose per soddisfare i tuoi requisiti di design. Assicurati solo di aggiornare il comportamento degli script client nella script ReplicatedStorage.Bundles.Client.UIController.

Riferimento API

Tipi

RelativeTime

Una volta che il bundle RelativeTime è offerto a un giocatore, rimane disponibile fino all'esaurimento della durata. Questo tipo viene visualizzato nel display informativo del giocatore e richiede automaticamente nuove sessioni future fino a quando il bundle scade o il giocatore lo acquista.

Un esempio comune di questo tipo di bundle è un'offerta di pacchetto di avvio a uso singolo che viene visualizzato per tutti i nuovi giocatori per 24 ore.

NomeTipoDescrizione
includeOfflineTimebool(Facoltativo) Se non impostato, solo il tempo trascorso nell'esperienza verrà conteggiato per la durata restante dell'offerta.
singleUsebool(Facoltativo) Se non impostato, l'acquisto può essere riattivato dopo che è stato acquistato o scaduto.

Se impostato, una volta acquistato o scaduto la prima volta, non sarà mai più richiamabile, anche se chiami Bundles.promptIfValidAsync con il bundleId.

FixedTime

Una volta che il bundle FixedTime è offerto a un giocatore, rimane disponibile fino alla fine del tempo coordinato universale impostato (UTC). Questo tipo viene visualizzato nel display informativo del giocatore e richiede automaticamente nuove sessioni future fino a quando il bundle scade o il giocatore lo acquista.

Un esempio comune di questo tipo di bundle è un'offerta natalizia disponibile solo per un mese specifico.

OneTime

Un bundle OneTime è disponibile solo nel momento in cui viene offerto a un giocatore. Non viene visualizzato nel display informativo del giocatore e una volta che un giocatore chiude l'invito, non può essere riaperto fino a quando non viene nuovamente invitato dal server.

Un esempio comune di questo tipo di bundle è un'offerta per acquistare più valuta in-experience nel momento in cui un giocatore esaurisce.

© 2026 Roblox Corporation. Roblox, il logo Roblox e Powering Imagination sono tra i nostri marchi registrati e non registrati negli Stati Uniti. e altri paesi.