Paquete de paquetes

*Este contenido se traduce usando la IA (Beta) y puede contener errores. Para ver esta página en inglés, haz clic en aquí.

El paquete de características Bundles ofrece funcionalidad fuera de la caja para vender colecciones de artículos a jugadores con descuento.Puedes elegir si quieres permitir que los jugadores compren paquetes usando una moneda personalizada en la experiencia o Robux, qué tipo de paquete quieres usar, qué conjunto de artículos quieres vender y cómo quieres solicitar a los jugadores durante su juego.

Al usar las opciones de personalización del paquete, puedes ajustar tus paquetes para cumplir con los objetivos de diseño y monetización de tus experiencias, como:

  • Apuntar a una tasa de conversión baja de por ofrecer paquetes de inicio descuentados que proporcionen valor a los nuevos jugadores y alentar el gasto temprano.
  • Aumentar la profundidad de gasto al agrupar artículos en varios puntos de precio para apelar a una gama de jugadores
  • Monetizar operaciones en vivo (LiveOps) eventos ofreciendo paquetes de tiempo limitado de artículos exclusivos.

Obtener paquete

La tienda de creadores es una pestaña de la caja de herramientas que puedes usar para encontrar todos los recursos que se crean por Roblox y la comunidad de Roblox para su uso dentro de tus proyectos, incluidos aplicación de modelado, imágenes, mallas, sonido, audio, complemento, vídeo y fuentes.Puedes usar la Tienda de creadores para agregar uno o más recursos directamente a una experiencia abierta, incluidos paquetes de funciones!

Cada paquete de características requiere que el paquete de características Núcleo funcione correctamente.Una vez que los recursos del paquete de características Núcleo y Paquetes estén dentro de su inventario, puede volver a utilizarlos en cualquier proyecto en la plataforma.

Para obtener los paquetes de su inventario en su experiencia:

  1. Añade el paquete de características Núcleo y Paquetes al inventario dentro de Studio haciendo clic en el enlace Añadir al inventario en el siguiente conjunto de componentes.

  2. En la barra de herramientas, seleccione la pestaña Ver.

  3. Haga clic en Caja de herramientas . Se muestra la ventana Caja de herramientas .

    Studio's View tab with the Toolbox tool highlighted.
  4. En la ventana Caja de herramientas , haga clic en la pestaña Inventario . Se muestran los ordenados Mis modelos .

    Studio's Toolbox window with the Inventory tab highlighted.
  5. Haga clic en el azulejo mosaicode características principal, luego en el azulejo mosaicode características de paquete.Ambas carpetas de paquete se muestran en la ventana Explorador .

  6. Arrastra las carpetas del paquete a ReplicatedStorage .

  7. Permita las llamadas al almacén de datos para rastrear las compras de jugadores con los paquetes.

    1. En la pestaña Inicio de la barra de herramientas, seleccione Configuración del juego .
    2. Navegue hasta la pestaña Seguridad , luego habilite Habilitar el acceso de Studio a los servicios de API .

Define monedas

Si tu experiencia tiene su propio sistema de moneda, puedes registrarlos con el paquete de características Núcleo al definirlos en >.Hay un ejemplo comentado de una moneda de gemas ya en este archivo; reemplázalo con el en posesión.

Monedas

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

El script Currencies le dice al paquete de características Núcleo algunos metadatos sobre su moneda:

  • (requerido) displayName - El nombre de tu moneda. Si no especificas un símbolo o ícono, este nombre se usa en los botones de compra (es decir, "100 gemas").
  • (opcional) symbol - Si tiene un personaje de texto para usar como icono para su moneda, se usa en lugar del displayName en los botones de compra (es decir, "💎100").
  • (opcional) icon - Si tiene un icono de imagen AssetId para su moneda, se usa en lugar del displayName en los botones de compra (es decir,la imagen se colocará a la izquierda del precio "🖼️100")

Una vez que tu moneda esté configurada, debes especificar manualmente el precio, la moneda y el icono del paquete para la pantalla de aviso en lugar de que esa información se obtenga del producto asociado del desarrollador del paquete.

Paquetes

-- Si desea utilizar un producto de desarrollador, debe proporcionar un ID de producto único, solo utilizado por un paquete.
-- Obtendremos el precio del paquete y el icono del producto del desarrollador
pricing = {
priceType = CurrencyTypes.PriceType.Marketplace,
devProductId = 1795621566,
},
-- De lo contrario, si quieres usar la moneda en experiencia en lugar de un producto de desarrollador, puedes usar lo siguiente en su lugar:
-- El precio aquí está en la moneda de experiencia, no en Robux
pricing = {
priceType = CurrencyTypes.PriceType.InExperience,
price = 79,
currencyId = "Gems",
icon = 18712203759,
},

También necesitas referenciar el BundlesExample script para llamar setInExperiencePurchaseHandler .

Ejemplo de paquetes

local function awardInExperiencePurchase(
_player: Player,
_bundleId: Types.BundleId,
_currencyId: CurrencyTypes.CurrencyId,
_price: number
)
-- Compruebe si el jugador tiene suficiente moneda para comprar el paquete
-- Actualizar datos del jugador, dar artículos, etc.
-- Deducir la moneda del jugador
task.wait(2)
return true
end
local function initializePurchaseHandlers()
local bundles = Bundles.getBundles()
for bundleId, bundle in bundles do
-- El paquete no está asociado con un producto de desarrollador si no tiene introducirde precio de mercado
if not bundle or bundle.pricing.priceType ~= "Marketplace" then
continue
end
Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
receiptHandlers[bundle.pricing.devProductId] = receiptHandler
end
-- Si tienes alguna moneda en experiencia que estás usando para paquetes, establece el manejador aquí
for currencyId, _ in Currencies do
Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
end
end

En particular, necesitas completar awardInExperiencePurchase , que se llama a través de un bucle a través de Currencies dentro del ejemplo initializePurchaseHandlers (es decir,cada currencyId está conectado al manipulador a través de Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase) ).

Define paquetes

Todos los paquetes ofrecibles en tu experiencia se pueden definir dentro de ReplicatedStorage.Bundles.Configs.Bundles , con tipos exportados del script Types en la misma carpeta.

Si estás usando un devProductId , necesitas actualizar el principal devProductId del paquete para coincidir con el de tu experiencia.Esto es lo que se solicitará a través de MarketplaceService para comprar el paquete en sí. Se recomienda encarecidamente utilizar un nuevo producto de desarrollador para el paquete para facilitar el seguimiento de ventas separadas. Si desea un paquete con múltiples artículos, y si estos ya están representados por productos de desarrollador en su experiencia, no necesita establecer explícitamente el precio del artículo/assetId/name, que se recuperará a través de la información del producto:

LEERME

{
itemType = ItemTypes.ItemType.DevProduct,
devProductId = <DEV_PRODUCT_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
} -- La descripción es opcional! También puedes omitir este campo
}
},

De lo contrario, puedes configurar manualmente esos detalles del artículo:

LEERME

{
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 49,
icon = <IMAGE_ASSET_ID>,
metadata = {
caption = {
text = "x1",
color = Color3.fromRGB(236, 201, 74),
} -- La descripción es opcional! También puedes omitir este campo
}
},

Por ejemplo, todo tu paquete probablemente se verá así:

LEERME

local starterBundle: Types.RelativeTimeBundle = {
bundleType = Types.BundleType.RelativeTime,
-- Si desea utilizar un producto de desarrollador, debe proporcionar un ID de producto único, solo utilizado por un paquete.
-- Obtendremos el precio del paquete y el icono del producto del desarrollador
pricing = {
priceType = CurrencyTypes.PriceType.Marketplace,
devProductId = <DEV_PRODUCT_ID>,
},
-- De lo contrario, si quieres usar la moneda en experiencia en lugar de un producto de desarrollador, puedes usar lo siguiente en su lugar:
-- El precio aquí está en la moneda de experiencia, no en Robux
-- precios = {
-- priceType = Tipo de precio = Tipo de moneda.PriceType.InExperience,
-- precio = 79,
-- currencyId = <CURRENCY_ID>,
-- icón = <IMAGE_ASSET_ID>,
-- },
includedItems = {
[1] = {
-- El artículo en sí no se vende a través de un producto de desarrollador, por lo que indique cuánto vale en Robux y dé un ícono
-- El precioInRobux ayuda a los paquetes a mostrar el valor relativo del precio del paquete vs. la suma de su contenido
itemType = ItemTypes.ItemType.Robux,
priceInRobux = 49,
icon = <IMAGE_ASSET_ID>,
-- Alternativamente, si esto tiene un producto de desarrollador elimine el precio y el icono de arriba y solo establezca el devProductId
-- El precio y el icono se recuperarán del producto del desarrollador
-- idProductoDev = <ITEM_DEV_PRODUCT_ID>
-- Hay más campos de metadatos opcionales que son específicos de la interfaz de usuario si es necesario
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 vez comprado o expirado, ya no es válido incluso si tu experiencia intenta solicitar (onPlayerAdded). Puedes hacer esto falso durante la prueba en el estudio.
durationInSeconds = 900, -- 15 minutos
includesOfflineTime = false, -- Solo cuente el tiempo transcurrido en la experiencia
metadata = {
displayName = "STARTER BUNDLE",
description = "Save 75% and get a head start!",
},
}

Integrar lógica del servidor

Echa un vistazo a ReplicatedStorage.Bundles.Server.Examples.BundlesExample, que muestra cómo interactuará tu servidor con el paquete de características Bundles y los métodos anteriores en el ModuleScript.Los fragmentos siguientes son de ese script.

Necesitas principalmente conectar cuatro cosas una vez que arrastres el paquete de características Bundles a tu experiencia:

  1. Conecte los manipuladores de compras a través de Bundles.setPurchaseHandler para especificar las funciones a llamar para otorgar artículos de recompensa cuando se esté procesando una compra.

    Ejemplo de paquetes

    local function awardMarketplacePurchase(_player: Player, _bundleId: Types.BundleId, _receiptInfo: { [string]: any })
    -- Actualizar datos del jugador, dar artículos, etc.
    -- ... Y registro de recibo de información de compra para que podamos verificar si el usuario ya tiene este paquete
    task.wait(2)
    return Enum.ProductPurchaseDecision.PurchaseGranted
    end
    local function awardInExperiencePurchase(
    _player: Player,
    _bundleId: Types.BundleId,
    _currencyId: CurrencyTypes.CurrencyId,
    _price: number
    )
    -- Compruebe si el jugador tiene suficiente moneda para comprar el paquete
    -- Actualizar datos del jugador, dar artículos, etc.
    -- Deducir la moneda del jugador
    task.wait(2)
    return true
    end
    local function initializePurchaseHandlers()
    local bundles = Bundles.getBundles()
    for bundleId, bundle in bundles do
    -- El paquete no está asociado con un producto de desarrollador si no tiene introducirde precio de mercado
    if not bundle or bundle.pricing.priceType ~= "Marketplace" then
    continue
    end
    Bundles.setPurchaseHandler(bundleId, awardMarketplacePurchase)
    receiptHandlers[bundle.pricing.devProductId] = receiptHandler
    end
    -- Si tienes alguna moneda en experiencia que estás usando para paquetes, establece el manejador aquí
    for currencyId, _ in Currencies do
    Bundles.setInExperiencePurchaseHandler(currencyId, awardInExperiencePurchase)
    end
    end
  2. Conecta tu lógica para MarketplaceService.ProcessReceipt , pero esto se puede hacer en otro lugar si tu experiencia ya tiene productos de desarrollador a la venta.Esencialmente, cuando se esté procesando un recibo de producto de desarrollador, ahora llamarán Bundles.getBundleByDevProduct para verificar si el producto pertenece a un paquete.Si lo hace, el script luego llama Bundles.processReceipt .

    Ejemplo de paquetes

    -- Procesar recibo del mercado para determinar si el jugador debe ser cargado o no
    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] -- Obtener el manejador del producto
    local success, result = pcall(handler, receiptInfo, player) -- Llamar al manipulador para verificar si la lógica de compra es exitosa
    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
    -- Esta compra pertenece a un paquete, deje que los paquetes lo manejen
    local purchaseDecision = Bundles.processReceiptAsync(player, bundleId, receiptInfo)
    return purchaseDecision == Enum.ProductPurchaseDecision.PurchaseGranted
    end
    -- Esta compra no pertenece a un paquete,
    -- ... Manejar toda tu lógica existente aquí si tienes alguna
    return false
    end
  3. Conecte Players.PlayerAdded:Connect(Bundles.OnPlayerAdded) para que el paquete de características de paquetes reindique cualquier paquete activo que aún no haya expirado para un jugador.

    LEERME

    local function onPlayerAdded(player: Player)
    -- Dile a los paquetes cuándo se une un jugador para que pueda recargar sus datos
    Bundles.onPlayerAdded(player)
    -- Si tuvieras un paquete de inicio que quieras ofrecer a todos los nuevos usuarios, podrías solicitarlo aquí
    -- ... los paquetes se encargarán si el jugador ya lo ha comprado o si expiró desde que no es repetible
    -- Bundles.promptIfValidAsync(jugador, "StarterBundle")
    -- Llamar esto aquí solo por ejemplo, puedes llamar esto cuando quieras o donde quieras
    onPromptBundleXYZEvent(player)
    end
  4. Paquetes de promoción. Aunque esto depende del juego, el ejemplo invita a los jugadores con un paquete de inicio onPlayerAdded .

    • La lógica del paquete de funciones Bundles garantiza que cada jugador no reciba una oferta repetida si ya ha comprado el paquete, o si deja que la oferta expire (basada en la configuración del paquete).

    • Cada vez que quieras solicitar un paquete a un jugador, llama a Bundles.promptIfValidAsync(player, bundleId) .

    LEERME

    local function onPromptBundleXYZEvent(player: Player)
    -- Conecta cualquier evento de experiencia que quieras usar para determinar cuándo se le solicita al jugador que obtenga el paquete
    -- ... Esto será cada vez que hayas cumplido con tus criterios de elegibilidad para solicitarle a un jugador el paquete
    -- ... Por ejemplo, si quieres solicitar un paquete cuando un jugador se una o cuando un jugador suba de nivel
    task.spawn(Bundles.promptIfValidAsync, player, <Some_Bundle_Id>)
    -- ... Si se crean múltiples paquetes, usar task.regeneración() para envolver la llamada de función anterior minimizará las discrepancias entre los recuentos
    end

Tenga en cuenta la siguiente guía de mejores prácticas sobre grabaciones redundantes de ReceiptIds:

  • Mientras que el paquete de características Paquetes registra ReceiptIds para evitar procesar el mismo recibo dos veces, también deberías estar registrando ReceiptIds dentro de tus tablas para que si el flujo de compra falla después de que su manipulador de compras ya haya terminado, sepas en el siguiente intento no otorgar artículos nuevamente.

  • El paquete de características Paquetes no registrará el ID de recibo si la compra falla en cualquier paso, por lo que debe asegurarse de que esté registrando el ID de recibo en sus tablas antes de procesar el recibo como parte de su manejador de compras.

  • Esta redundancia ayuda a garantizar que toda la lógica de compra se haya manejado apropiadamente y que el almacén de datos de tu almacén de datos y el paquete de características de paquetes alcancen la consistencia eventual, con tu almacén de datos siendo la fuente de verdad.

Configurar constantes

Las constantes para el paquete de características Núcleo viven en dos lugares:

  • Las constantes compartidas viven en ReplicatedStorage.FeaturePackagesCore.Configs.SharedConstants .

  • Las constantes específicas del paquete, en este caso el paquete de características Bundles , viven en ReplicatedStorage.Bundles.Configs.Constants .

Las principales cosas que quizás quieras ajustar para cumplir con los requisitos de diseño de tu experiencia:

  • ID de sonido
  • Duración del efecto de compra y colores de partículas
  • Colapso de la visualización de cabezas

Además, puedes encontrar cadenas para la traducción separadas en una ubicación: ReplicatedStorage.FeaturePackagesCore.Configs.TranslationStrings .

Personalizar componentes de UI

Al modificar los objetos del paquete, como colores, fuente y transparencia, puedes ajustar la presentación visual de tus solicitudes de paquetes.Sin embargo, tenga en cuenta que si mueve cualquiera de los objetos alrededor jerárquicamente, el código no podrá encontrarlos y tendrá que hacer ajustes a su código.

Un mensaje de advertencia se compone de dos componentes de alto nivel:

  • PromptItem – El componente individual se repite por cada artículo dentro de un paquete (imagen del artículo, subtítulo, nombre, precio).
  • Prompt – La ventana de confirmación en sí.

La pantalla de advertencia también se compone de dos componentes:

  • HudItem – Un componente individual que representa cada opción de menú en la pantalla de cabecera.
  • Hud – Para ser llenado con programáticamente con HudItems .

Si desea tener un mayor control sobre la pantalla de cabeceras, en lugar de utilizar solo la interfaz de usuario HUD existente dentro de ReplicatedStorage.Bundles.Objects.BundlesGui , puede mover las cosas para cumplir con sus propios requisitos de diseño.Solo asegúrate de actualizar el comportamiento del script del cliente en el ReplicatedStorage.Bundles.Client.UIController script.

Referencia de API

Tipos

Tiempo relativo

Una vez que el paquete RelativeTime se ofrezca a un jugador, permanece disponible hasta que se agote el tiempo.Este tipo se muestra en la pantalla de visualización en la cabeza del jugador y se muestra automáticamente en las sesiones futuras hasta que el paquete expire o el jugador lo compre.

Un ejemplo común de este tipo de paquete es una oferta de paquete de inicio de un solo uso que se muestra a todos los nuevos jugadores durante 24 horas.Para las mejores prácticas de la industria sobre cómo implementar paquetes de inicio, vea Diseño del paquete de inicio.

NombreTipoDescripción
includeOfflineTimebool (Opcional) Si no se establecer, solo el tiempo que se pasa en la experiencia contará para la duración restante de la oferta.
singleUsebool (Opcional) Si no se establecer, la compra se puede reactivar después de que se haya comprado o expirado.Si se establecer, una vez comprada o expirada la primera vez, no se volverá a solicitar nunca, incluso si llama Bundles.promptIfValidAsync con el ID del paquete.

Tiempo fijo

Una vez que se ofrezca el paquete FixedTime al jugador, permanece disponible hasta el final del tiempo universal coordinado (UTC).Este tipo se muestra en la pantalla de visualización en la cabeza del jugador y se muestra automáticamente en las sesiones futuras hasta que el paquete expire o el jugador lo compre.

Un ejemplo común de este tipo de paquete es una oferta de vacaciones que solo está disponible para un mes determinado.

Una vez

Un paquete OneTime solo está disponible en el momento en que se ofrece a un jugador.No se muestra en la pantalla de cabeceras del jugador, y una vez que un jugador cierra la ventana emergente, no se puede volver a abrir hasta que sea solicitado por el servidor nuevamente.

Un ejemplo común de este tipo de paquete es una oferta para comprar más moneda en experiencia en el momento en que un jugador se queda sin ella.