Paket bundel

*Konten ini diterjemahkan menggunakan AI (Beta) dan mungkin mengandung kesalahan. Untuk melihat halaman ini dalam bahasa Inggris, klik di sini.

Paket fitur Bundel menawarkan fungsi keluar dari kotak untuk menjual koleksi item kepada pemain dengan diskon.Anda dapat memilih apakah akan mengizinkan pemain untuk membeli bundel menggunakan mata uang khusus dalam pengalaman atau Robux, jenis bundel yang ingin Anda gunakan, barang apa yang ingin Anda jual, dan bagaimana Anda ingin meminta pemain selama gameplaymereka.

Menggunakan opsi kustomisasi paket, Anda dapat menyesuaikan bundel Anda untuk memenuhi tujuan desain dan monetarisasi pengalaman Anda, seperti:

  • Menargetkan tingkat konversi rendah dengan menawarkan paket pemula diskon yang memberikan nilai kepada pemain baru dan mendorong pengeluaran awal.
  • Meningkatkan biaya pengeluaran dengan menggabungkan item di berbagai titik harga untuk menarik berbagai pemain.
  • Monetarisasi operasi langsung (LiveOps) peristiwa dengan menawarkan bundel waktu terbatas dari item eksklusif.

Dapatkan paket

Toko Pencipta adalah tab dari Toolbox yang dapat Anda gunakan untuk menemukan semua aset yang dibuat oleh Roblox dan komunitas Roblox untuk digunakan dalam proyek Anda, termasuk model, gambar, mesh, audio, plugin, video, dan aset font.Anda dapat menggunakan Toko Pencipta untuk menambahkan satu atau lebih aset langsung ke pengalaman terbuka, termasuk paket fitur!

Setiap paket fitur memerlukan paket fitur Inti untuk berfungsi dengan benar.Setelah Inti dan Bundel fitur paket aset sudah ada di inventaris Anda, Anda dapat menggunakannya kembali di proyek apa pun di platform.

Untuk mendapatkan paket dari inventaris Anda ke pengalaman Anda:

  1. Di bilah alat, pilih tab Tampilkan.

  2. Klik Toolbox . Jendela Toolbox ditampilkan.

    Studio's View tab with the Toolbox tool highlighted.
  3. Di jendela Toolbox , klik tab Inventaris . Tampilan urutan Model Saya ditampilkan.

    Studio's Toolbox window with the Inventory tab highlighted.
  4. Klik tombol Paket Fitur Inti , lalu tombol Paket Fitur Bundel .Kedua folder paket ditampilkan di jendela Explorer .

  5. Seret folder paket ke dalam ReplicatedStorage .

  6. Izinkan panggilan penyimpanan data untuk melacak pembelian pemain dengan paket.

    1. Di tab Rumah di bilah alat, pilih Pengaturan Permainan .
    2. Navigasikan ke tab Keamanan , lalu aktifkan Aktifkan Akses Studio ke Layanan API .

Definisikan mata uang

Jika pengalaman Anda memiliki sistem mata uang sendiri, Anda dapat mendaftarkan mereka dengan paket fitur Inti dengan menentukannya di ReplicatedStorage.FeaturePackagesCore.Configs.Currencies .Ada contoh komentar dari mata uang Permata yang sudah ada di file ini; gantikan dengan milik Anda sendiri.

Mata uang

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

Skrip Currencies memberitahu paket fitur Inti beberapa metadata tentang mata uang Anda:

  • (diperlukan) displayName - Nama mata uang Anda. Jika Anda tidak menyebutkan simbol atau ikon, nama ini digunakan dalam tombol pembelian (yaitu "100 Permata").
  • (opsional) symbol - Jika Anda memiliki karakter teks untuk digunakan sebagai ikon untuk mata uang Anda, ini digunakan sebagai gantinya displayName pada tombol pembelian (yaitu "💎100").
  • (opsional) icon - Jika Anda memiliki ikon gambar AssetId untuk mata uang Anda, ini digunakan sebagai gantinya displayName pada tombol pembelian (yaitugambar akan ditempatkan di sebelah kiri harga "🖼️100")

Setelah mata uang Anda ditetapkan, Anda perlu secara manual menentukan harga bundel, mata uang, dan ikon untuk tampilan kepala atas alih-alih informasi tersebut diambil dari produk pengembang terkait bundel.

Kelompok

-- Jika Anda ingin menggunakan produk dev, Anda harus memberikan devProductId unik, hanya digunakan oleh satu bundel.
-- Kami akan mengambil harga bundel dan ikon dari produk pengembang
pricing = {
priceType = CurrencyTypes.PriceType.Marketplace,
devProductId = 1795621566,
},
-- Jika tidak, jika Anda ingin menggunakan mata uang dalam pengalaman alih-alih produk dev, Anda dapat menggunakan yang berikut:
-- Harga di sini adalah dalam mata uang pengalaman, bukan Robux
pricing = {
priceType = CurrencyTypes.PriceType.InExperience,
price = 79,
currencyId = "Gems",
icon = 18712203759,
},

Anda juga perlu merujuk pada skrip BundlesExample untuk memanggil setInExperiencePurchaseHandler .

Contoh Bundel

local function awardInExperiencePurchase(
_player: Player,
_bundleId: Types.BundleId,
_currencyId: CurrencyTypes.CurrencyId,
_price: number
)
-- Periksa apakah pemain memiliki mata uang yang cukup untuk membeli bundel
-- Perbarui data pemain, berikan item, dll
-- Kurangi mata uang dari pemain
task.wait(2)
return true
end
local function initializePurchaseHandlers()
local bundles = Bundles.getBundles()
for bundleId, bundle in bundles do
-- Bundle tidak terkait dengan produk pengembang jika tidak memiliki jenis harga pasar
if not bundle or bundle.pricing.priceType ~= "Marketplace" then
continue
end
Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
receiptHandlers[bundle.pricing.devProductId] = receiptHandler
end
-- Jika Anda memiliki mata uang dalam pengalaman yang Anda gunakan untuk bundel, atur penangan di sini
for currencyId, _ in Currencies do
Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
end
end

Secara khusus, Anda perlu mengisi awardInExperiencePurchase , yang dipanggil oleh loop melalui Currencies di dalam contoh initializePurchaseHandlers (yaitusetiap currencyId terhubung ke penangan melalui Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase) ).

Definisikan bundel

Semua bundel yang dapat ditawarkan dalam pengalaman Anda dapat didefinisikan dalam ReplicatedStorage.Bundles.Configs.Bundles , dengan jenis diekspor dari skrip Types di folder yang sama.

Jika Anda menggunakan devProductId , Anda perlu memperbarui bundel utama devProductId untuk cocok dengan yang ada di pengalaman Anda.Inilah yang akan diminta melalui MarketplaceService untuk membeli bundel itu sendiri. Sangat disarankan untuk menggunakan produk pengembang baru untuk bundel agar lebih mudah melacak penjualan terpisah. Jika Anda ingin paket dengan beberapa item, dan jika ini sudah diwakili oleh produk pengembang dalam pengalaman Anda, Anda tidak perlu secara eksplisit mengatur harga item/assetId/nama, yang akan diambil melalui informasi produk:

README

{
itemType = ItemTypes.ItemType.DevProduct,
devProductId = <DEV_PRODUCT_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
} -- Keterangan opsional! Anda juga dapat menghilangkan bidang ini
}
},

Jika tidak, Anda dapat secara manual mengkonfigurasi detail item tersebut:

README

{
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 49,
icon = <IMAGE_ASSET_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
} -- Keterangan opsional! Anda juga dapat meninggalkan menghilangkan bidang ini
}
},

Sebagai contoh, seluruh bundel Anda kemungkinan akan terlihat seperti ini:

README

local starterBundle: Types.RelativeTimeBundle = {
bundleType = Types.BundleType.RelativeTime,
-- Jika Anda ingin menggunakan produk dev, Anda harus memberikan devProductId unik, hanya digunakan oleh satu bundel.
-- Kami akan mengambil harga bundel dan ikon dari produk pengembang
pricing = {
priceType = CurrencyTypes.PriceType.Marketplace,
devProductId = <DEV_PRODUCT_ID>,
},
-- Jika tidak, jika Anda ingin menggunakan mata uang dalam pengalaman alih-alih produk dev, Anda dapat menggunakan yang berikut:
-- Harga di sini adalah dalam mata uang pengalaman, bukan Robux
-- harga = {
-- priceType = CurrencyTypes.PriceType.InExperience,
-- harga = 79,
-- currencyId = <CURRENCY_ID>,
-- ikon = <IMAGE_ASSET_ID>,
-- },
includedItems = {
[1] = {
-- Item itu sendiri tidak dijual melalui produk pengembang, jadi indikasikan berapa nilainya dalam Robux dan berikan ikon
-- HargaInRobux membantu Bundel menunjukkan nilai relatif harga bundel vs. total kontennya
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 49,
icon = <IMAGE_ASSET_ID>,
-- Alternatifnya, jika ini memiliki produk dev meninggalkan harga dan ikon di atas dan hanya menetapkan devProductId
-- Harga dan ikon akan diambil dari produk pengembang
-- produk devProductId = <ITEM_DEV_PRODUCT_ID>
-- Ada lebih banyak bidang metadata opsional yang spesifik UI jika diperlukan
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, -- Setelah dibeli atau kedaluwarsa, tidak lagi valid bahkan jika pengalaman Anda mencoba meminta (onPlayerAdded). Anda dapat membuat ini palsu saat menguji di studio.
durationInSeconds = 900, -- 14 menit
includesOfflineTime = false, -- Hanya hitung waktu yang terlalu di pengalaman
metadata = {
displayName = "STARTER BUNDLE",
description = "Save 75% and get a head start!",
},
}

Integrasikan logika server

Lihat ReplicatedStorage.Bundles.Server.Examples.BundlesExample , yang menunjukkan bagaimana server Anda akan berinteraksi dengan paket fitur Bundel dan metode di atas di ModuleScript .Potongan di bawah ini berasal dari skrip itu.

Anda terutama perlu menghubungkan empat hal setelah menyeret paket fitur Bundel ke dalam pengalaman Anda:

  1. Hubungkan penangan pembelian melalui Bundles.setPurchaseHandler untuk menentukan fungsi yang akan dipanggil untuk menghadiahkan item saat pembelian diproses.

    Contoh Bundel

    local function awardMarketplacePurchase(_player: Player, _bundleId: Types.BundleId, _receiptInfo: { [string]: any })
    -- Perbarui data pemain, berikan item, dll
    -- ... DAN catat penerimaan informasi pembelian ID sehingga kami dapat memeriksa apakah pengguna sudah memiliki bundel ini
    task.wait(2)
    return Enum.ProductPurchaseDecision.PurchaseGranted
    end
    local function awardInExperiencePurchase(
    _player: Player,
    _bundleId: Types.BundleId,
    _currencyId: CurrencyTypes.CurrencyId,
    _price: number
    )
    -- Periksa apakah pemain memiliki mata uang yang cukup untuk membeli bundel
    -- Perbarui data pemain, berikan item, dll
    -- Kurangi mata uang dari pemain
    task.wait(2)
    return true
    end
    local function initializePurchaseHandlers()
    local bundles = Bundles.getBundles()
    for bundleId, bundle in bundles do
    -- Bundle tidak terkait dengan produk pengembang jika tidak memiliki jenis harga pasar
    if not bundle or bundle.pricing.priceType ~= "Marketplace" then
    continue
    end
    Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
    receiptHandlers[bundle.pricing.devProductId] = receiptHandler
    end
    -- Jika Anda memiliki mata uang dalam pengalaman yang Anda gunakan untuk bundel, atur penangan di sini
    for currencyId, _ in Currencies do
    Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
    end
    end
  2. Hubungkan logika Anda untuk MarketplaceService.ProcessReceipt , tetapi ini mungkin dilakukan di tempat lain jika pengalaman Anda sudah memiliki produk pengembang untuk penjualan.Pada dasarnya, ketika terjadi penerimaan produk pengembang, mereka sekarang akan memanggil Bundles.getBundleByDevProduct untuk memeriksa apakah produk tersebut milik bundel.Jika demikian, skrip kemudian memanggil Bundles.processReceipt .

    Contoh Bundel

    -- Proses terima dari pasar untuk menentukan apakah pemain perlu dikenakan biaya atau tidak
    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] -- Dapatkan penangan untuk produk
    local success, result = pcall(handler, receiptInfo, player) -- Hubungi penangan untuk memeriksa apakah logika pembelian berhasil
    if not success or not result then
    warn("Failed to process receipt:", 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
    -- Pembelian ini termasuk dalam bundel, biarkan Bundel menanganinya
    local purchaseDecision = Bundles.processReceiptAsync(player, bundleId, receiptInfo)
    return purchaseDecision == Enum.ProductPurchaseDecision.PurchaseGranted
    end
    -- Pembelian ini tidak termasuk dalam bundel,
    -- ... Tangani semua logika yang ada di sini jika Anda memiliki apa pun
    return false
    end
  3. Hubungkan Players.PlayerAdded:Connect(Bundles.OnPlayerAdded) sehingga paket fitur Bundel meminta ulang bundel aktif yang belum kedaluwarsa untuk pemain.

    README

    local function onPlayerAdded(player: Player)
    -- Beritahu Bundel ketika pemain bergabung sehingga dapat memuat ulang data mereka
    Bundles.onPlayerAdded(player)
    -- Jika Anda memiliki beberapa bundel pemula yang ingin Anda tawarkan kepada semua pengguna baru, Anda bisa meminta di sini
    -- ... Bundel akan menangani jika pemain sudah membelinya atau jika sudah kedaluwarsa karena tidak dapat diulang
    -- Bundles.promptIfValidAsync(pemain, "StarterBundle")
    -- Memanggil ini di sini hanya sebagai contoh, Anda dapat memanggil ini kapan saja atau di mana pun Anda mau
    onPromptBundleXYZEvent(player)
    end
  4. Paket cepat. Sementara ini tergantung pada gameplay, contoh meminta pemain dengan StarterBundle onPlayerAdded .

    • Logik paket fitur Bundel memastikan setiap pemain tidak mendapatkan tawaran ulang jika mereka sudah membeli bundel, atau jika mereka membiarkan tawaran itu kedaluwarsa (berdasarkan konfigurasi bundel).

    • Kapan pun Anda ingin meminta bundel kepada pemain, hubungi Bundles.promptIfValidAsync(player, bundleId) .

    README

    local function onPromptBundleXYZEvent(player: Player)
    -- Hubungkan peristiwa pengalaman apa pun yang ingin Anda gunakan untuk menentukan kapan seorang pemain diminta bundel
    -- ... Ini akan terjadi setiap kali Anda memenuhi kriteria kelayakan untuk meminta pemain bundel
    -- ... Misalnya, jika Anda ingin meminta bundel saat pemain bergabung, atau saat pemain naik level
    task.spawn(Bundles.promptIfValidAsync, player, <Some_Bundle_Id>)
    -- ... Jika membuat beberapa bundel, menggunakan task.spawn() untuk membungkus panggilan fungsi di atas akan mengurangi ketidakcocokan antara hitung mundur
    end

Pertimbangkan panduan praktik terbaik berikut tentang rekaman redundan dari ReceiptIds:

  • Sementara paket fitur Bundel melakukan perekaman ReceiptIds untuk menghindari memproses invoice yang sama dua kali, Anda juga harus mencatat ReceiptIds di dalam tabel Anda sehingga jika aliran pembelian gagal setelah penangan pembelian mereka sudah selesai, Anda tahu pada pencobaan berikutnya untuk tidak memberikan item lagi.

  • Paket fitur Bundel tidak akan merekam ReceiptId jika pembelian gagal di setiap langkah, jadi Anda harus memastikan bahwa Anda mencatat ReceiptId di tabel Anda sebelum memproses pembayaran sebagai bagian dari pengelola pembelian Anda.

  • Redundansi ini membantu memastikan bahwa semua logika pembelian telah ditangani dengan tepat dan bahwa penyimpanan data toko data dan paket fitur Bundel mencapai konsistensi akhir, dengan penyimpanan data toko data Anda menjadi sumber kebenaran.

Konfigurasi konstan

Konstan untuk paket fitur Inti hidup di dua tempat:

  • Konstan bersama hidup di ReplicatedStorage.FeaturePackagesCore.Configs.SharedConstants .

  • Konstan khusus paket, dalam hal ini paket fitur Bundel hidup di ReplicatedStorage.Bundles.Configs.Constants .

Hal utama yang mungkin ingin Anda sesuaikan untuk memenuhi persyaratan desain pengalaman Anda:

  • AssetID suara
  • Durasi efek pembelian dan warna partikel
  • Peringatan penampilan kolapsibilitas kepala

Selain itu, Anda dapat menemukan string untuk terjemahan dibagi menjadi satu lokasi: ReplicatedStorage.FeaturePackagesCore.Configs.TranslationStrings .

Kustomisasi komponen UI

Dengan memodifikasi objek paket, seperti warna, font, dan transparansi, Anda dapat menyesuaikan presentasi visual bundel prompt Anda.Namun, ingatlah bahwa jika Anda memindahkan salah satu objek di sekitar hierarkis, kode tidak akan dapat menemukannya, dan Anda perlu melakukan penyesuaian pada kode Anda.

Sebuah prompt terdiri dari dua komponen tingkat tinggi:

  • PromptItem – Komponen individu diulang untuk setiap item dalam bundel (gambar item, keterangan, nama, harga).
  • Prompt – Jendela prompt itu sendiri.

Tampilan kepala juga terdiri dari dua komponen:

  • HudItem – Komponen individu yang mewakili setiap opsi menu dalam tampilan kepala.
  • Hud – Untuk diisi secara programatik dengan HudItems .

Jika Anda ingin memiliki kontrol lebih besar atas tampilan kepala, bukan hanya menggunakan HUD UI yang ada dalam ReplicatedStorage.Bundles.Objects.BundlesGui , Anda dapat memindahkan hal-hal untuk memenuhi persyaratan desain Anda sendiri.Pastikan saja untuk memperbarui perilaku skrip klien di skrip ReplicatedStorage.Bundles.Client.UIController.

Referensi API

Jenis

Waktu Relatif

Setelah bundel RelativeTime diterima oleh pemain, tetap tersedia sampai waktu berakhir.Jenis ini ditampilkan di layar tampilan kepala pemain, dan secara otomatis meminta pada sesi masa depan sampai bundel berakhir atau pemain membelinya.

Contoh umum dari jenis bundel ini adalah penawaran paket pemula satu kali penggunaan yang ditampilkan kepada semua pemain baru selama 24 jam.Untuk praktik terbaik industri tentang cara menerapkan bundel paket pemula, lihat Desain Paket Pemula.

NamaJenisDeskripsi
includeOfflineTimebool (Opsi) Jika tidak atur, hanya waktu yang dihabiskan dalam pengalaman yang akan dihitung menuju durasi tawaran yang tersisa.
singleUsebool (Opsi) Jika tidak diatur, pembelian dapat diaktifkan kembali setelah dibeli atau kedaluwarsa.Jika diatur, setelah dibeli atau kedaluwarsa pertama kali, tidak akan dapat diaktifkan lagi, bahkan jika Anda memanggil Bundles.promptIfValidAsync dengan bundelId.

Waktu Tetap

Setelah bundel FixedTime diterima oleh pemain, tetap tersedia sampai akhir waktu universal terkoordinasi (UTC).Jenis ini ditampilkan di layar tampilan kepala pemain, dan secara otomatis meminta pada sesi masa depan sampai bundel berakhir atau pemain membelinya.

Contoh umum dari jenis bundel ini adalah penawaran liburan yang hanya tersedia untuk bulan tertentu.

Satu Kali

Sebuah bundel OneTime hanya tersedia pada saat ditawarkan kepada pemain.Ini tidak ditampilkan di layar kepala atas pemain, dan setelah seorang pemain menutup prompt, prompt tidak dapat dibuka kembali sampai diminta oleh server lagi.

Contoh umum dari jenis bundel ini adalah penawaran untuk membeli lebih banyak mata uang pengalaman saat pemain kehabisan.