Las transacciones en la isla te permiten comercializar objetos, ofertas y ofertas combinadas en tu isla utilizando Verse.
En esta guía, aprenderás a configurar tus propios objetos, ofertas y ofertas combinadas. A continuación, utilizando el módulo Marketplace de la API de Verse, gestionarás la venta de objetos en el juego.
Objetos
Los objetos se definen en Verse como privilegios y se dividen en dos categorías: objetos consumibles, que se eliminan del inventario del jugador cuando se usan, y objetos duraderos, que el jugador puede seguir utilizando sin que se eliminen del inventario.
Todos los privilegios de Verse tiene las siguientes propiedades:
Name: el nombre del privilegio, con un máximo de 50 caracteres.
Description: la descripción larga que se muestra con el privilegio. Tiene un máximo de 500 caracteres.
ShortDescription: una descripción breve que resume el privilegio en un cuadro de diálogo más pequeño de hasta 100 caracteres.
Icon: una imagen del privilegio.
Si tu privilegio es un objeto aleatorio de pago, debes incluir en la descripción las probabilidades numéricas exactas de lo que el jugador puede recibir. Para obtener más información, consulta Objetos aleatorios de pago.
Un privilegio de Verse también puede tener las siguientes propiedades opcionales:
MaxCount: el número máximo de ese privilegio que el jugador puede tener en un momento dado.
Consumable: si este privilegio se activa (true), el producto se puede consumir, lo que reduce el número total de usos. Si se desactiva (false), el privilegio es un objeto permanente y no se consumirá con el uso.
PaidArea: si esta propiedad se activa (true), el privilegio brindará acceso a un área de pago.
PaidRandomItem: si esta propiedad se activa (true), estos privilegios se compran o canjean con contenido adquirido para obtener una recompensa aleatoria.
ConsequentialToGameplay: si se activa, el objeto proporciona a los jugadores una ventaja significativa en tu isla. Consulta Relevante para el juego para obtener más información.
Si tienes privilegios activos que no estás utilizando y no confirmas las compras dentro de la aplicación en el cuestionario de IARC, tu isla no superará la moderación.
Para evitarlo, puedes dejar un comentario sobre tus privilegios en Verse hasta que estés listo para usarlos en un juego real. Una vez lo hayas hecho, no es necesario que reclames las compras dentro de la aplicación en el cuestionario de IARC.
Cómo crear un privilegio consumible en Verse
Los privilegios se definen en Verse y se derivan de la clase base del privilegio. El siguiente fragmento de código muestra cómo crear un objeto consumible. En este ejemplo, crearás semillas de maíz como tu objeto consumible. A continuación, se incluye un icono de las semillas para que lo utilices.
# The base entitlement you should define for ALL of your entitlements in your experience.
my_island_entitlement := class<abstract><castable>(entitlement){}
CornSeedPacket<public> := module:
Name<public><localizes> : message = "Corn seed pack"
Description<public><localizes> : message = "A pack of corn seeds. Opening a pack yields 10 corn seeds for planting."
ShortDescription<public><localizes> : message = "Contains 10 corn seeds for planting."
cornseedpacket<public> := class<concrete>(my_island_entitlement):
var Name<override>:message = CornSeedPacket.Name
Cuando crees un privilegio, debes incluir una ruta a una textura de icono válida para que tu código de Verse se compile correctamente. ¡Llévate gratis el paquete de semillas de maíz y otros iconos incluidos en esta guía!
Asegúrate de que los iconos de tus privilegios utilicen una textura cuadrada con potencia de dos para obtener imágenes de la mejor calidad en tu tienda. Para obtener información sobre cómo importar texturas a UEFN para utilizarlas como iconos, consulta Cómo importar recursos. Para obtener información sobre cómo exponer recursos como texturas en Verse, consulta Cómo exponer recursos.
Cómo crear privilegios duraderos en Verse
Los privilegios duraderos en Verse siguen el mismo formato que los privilegios consumibles, pero con una diferencia clave: la propiedad Consumable está desactivada (false) en vez de activada (true). Los jugadores solo pueden comprar los privilegios duraderos una vez y pueden poseer uno de cada uno.
Para este ejemplo, crearás una pala como privilegio duradero. Se incluye un icono para la textura de la pala después del fragmento de código que aparece a continuación.
Shovel<public> := module:
Name<public><localizes>: message = "Shovel"
Description<public><localizes>: message = "An unbreakable shovel used to dig holes for planting."
ShortDescription<public><localizes>: message = "Digs holes."
shovel<public> := class<concrete>(my_island_entitlement):
var Name<override>:message = Shovel.Name
var Description<override>:message = Shovel.Description
var ShortDescription<override>:message = Shovel.ShortDescription
var Icon<override>:texture = # path to your texture here
De forma predeterminada, los objetos no son consumibles (propiedad Consumable desactivada) y tienen un recuento máximo (propiedad MaxCount) de 1. Si el objeto es un área de pago, un elemento aleatorio de pago o proporciona una ventaja significativa que afecta al desarrollo del juego, los campos pertinentes deben estar definidos en el código.
Reglas de validación de privilegios
Un privilegio válido en Verse debe cumplir las siguientes directrices. No será posible comprar privilegios que no cumplan estos requisitos.
Las reglas que definen un privilegio válido son:
Name tiene 50 caracteres como máximo.
Description tiene 500 caracteres como máximo.
ShortDescription tiene 100 caracteres como máximo.
MaxCount debe ser 1 cuando Consumable=false.
MaxCount tiene un valor máximo de 10 000 000.
No es obligatorio establecer MaxCount < 1, pero fallará, ya que no se puede otorgar menos de un objeto a un jugador.
Catálogo de privilegios
Puedes usar este catálogo para ver todos los privilegios que ofreces a los jugadores.
Puedes ver un informe con la lista de tus privilegios en UEFN haciendo clic en Herramientas > Catálogo de privilegios o directamente desde el catálogo del portal para creadores de tu isla.
Ofertas
Una oferta especifica un precio en paVos por un objeto o recurso. Cada oferta tiene su propio nombre, descripción e icono, y son independientes de las especificaciones del privilegio. Una oferta se define en Verse.
Cada oferta tiene las siguientes propiedades:
Name: el nombre de la oferta.
Description: la descripción larga que aparece junto a la oferta.
ShortDescription: una descripción breve que puedes utilizar para resumir la oferta en cuadros de diálogo más pequeños.
Icon: una imagen de la oferta.
EntitlementType: una declaración del privilegio incluido en la oferta.
Price: un precio en paVos. No debe ser inferior a 50 paVos ni superior a 5000 paVos. El precio debe fijarse en múltiplos de 50.
Cómo crear una oferta simple
Este fragmento de código define una oferta básica para una oferta simple: el paquete de semillas de maíz. Puedes reutilizar el icono de la semilla de maíz del ejemplo del privilegio como icono para esta oferta.
CornSeedPacket<public> := module:
Name<public><localizes> : message = "Corn seed pack"
Description<public><localizes> : message = "A pack of corn seeds. Opening a pack yields 10 corn seeds for planting."
ShortDescription<public><localizes> : message = "Contains 10 corn seeds for planting."
corn_seed_pack<public> := class(entitlement_offer):
var Name<override> : message = CornSeedPacket.Name
var Description<override> : message = CornSeedPacket.Description
var ShortDescription<override> : message = CornSeedPacket.ShortDescription
El precio en paVos debe ser un múltiplo de 50 y estar comprendido entre 50 y 5000 paVos.
Debes asegurarte de que los jugadores puedan ver las probabilidades numéricas exactas de obtener cada objeto aleatorio de pago antes de comprarlo. El incumplimiento de esta norma se considerará una infracción de las Reglas para desarrolladores de Fortnite y os someterá a ti y a tu isla a las sanciones correspondientes.
Para obtener más información, consulta Restricciones de las transacciones en la isla.
Cómo crear y modificar ofertas fijas y alternativas
Puedes realizar ofertas alternativas para el mismo privilegio con el fin de ofrecer precios especiales para días festivos, bonificaciones de lanzamiento y variar el precio por zona. También puedes usarlo para realizar pruebas de privilegios creando una oferta idéntica pero utilizando un icono diferente para ver cuál atrae más a los jugadores. Usemos este icono como ejemplo.
CornSeedPacketAlternate<public> := module:
Name<public><localizes> : message = "Corn seed pack"
Description<public><localizes> : message = "Special price! Only today!"
ShortDescription<public><localizes> : message = "Special offer half price!"
corn_seed_pack_alternate<public> := class(entitlement_offer):
var Name<override> : message = CornSeedPacketAlternate.Name
var Description<override> : message = CornSeedPacketAlternate.Description
var ShortDescription<override> : message = CornSeedPacketAlternate.ShortDescription
var Icon<override> : texture = # Your texture here
Ofertas combinadas
Las ofertas combinadas se definen en Verse y pueden contener una combinación de diferentes ofertas, conjuntos de la misma oferta o una mezcla de ambos. Al igual que las ofertas simples, las ofertas combinadas especifican su propio precio, nombre y descripción, y tienen un icono que las distingue de los privilegios y ofertas. También puedes anidar ofertas incluyendo lotes dentro de una oferta combinada. Un ejemplo sería un lote por tiempo limitado que incluya una pala y un paquete de semillas de maíz. Esto te permite utilizar lotes más pequeños como bloques de construcción para lotes combinados más grandes.
Los tipos de lotes estándar son:
Lote acumulado: un lote que contiene varias ofertas del mismo privilegio, normalmente a un precio reducido.
Lote con varias ofertas: un lote que combina ofertas para varios privilegios y que también puede incluir una mezcla de ofertas acumuladas y ofertas normales.
La profundidad de las ofertas anidadas no puede superar 5 o la transacción fallará. Intenta limitar las ofertas anidadas siempre que sea posible.
Creación de un lote acumulado
Este fragmento de código define un lote acumulado de semillas de maíz. Un lote contiene una matriz de tuplas de ofertas, que incluye la oferta definida y un int que indica el número de ofertas. En este caso, habría dos ofertas corn_seed_pack en este lote. Se proporciona un icono para este ejemplo.
CornSeedPacketBundle<public> := module:
Name<public><localizes> : message = "Corn seed pack bundle"
Description<public><localizes> : message = "Two packs of corn seeds. Opening a pack yields 10 corn seeds for planting."
ShortDescription<public><localizes> : message = "Two packs of corn seeds containing 10 corn seeds for planting."
corn_seed_pack_bundle<public> := class(bundle_offer):
var Name<override> : message = CornSeedPacketBundle.Name
var Description<override> : message = CornSeedPacketBundle.Description
var ShortDescription<override> : message = CornSeedPacketBundle.ShortDescription
var Icon<override> : texture = # your texture here
Creación de lotes con varias ofertas
Es posible que los jugadores quieran evitar realizar múltiples transacciones, por lo que puedes crear un lote que incluya varias ofertas que incorporen distintos privilegios. Este fragmento de código crea un lote con varias ofertas que proporciona al jugador el número máximo de paquetes de maíz y una pala.
StarterBundle<public> := module:
Name<public><localizes> : message = "Starter bundle"
Description<public><localizes> : message = "Everything a new player needs. Get fully stocked to start quickly! A shovel that digs holes, and ten packs of corn seeds each containing 10 corn seeds for planting."
ShortDescription<public><localizes> : message = "A shovel that digs holes, and ten packs of corn seeds each containing 10 corn seeds for planting."
starter_bundle<public> := class(bundle_offer):
var Name<override> : message = StarterBundle.Name
var Description<override> : message = StarterBundle.Description
var ShortDescription<override> : message = StarterBundle.ShortDescription
var Icon<override> : texture = # your texture here
En Verse, los lotes no contienen privilegios directamente. Lo que contienen son ofertas que tienen sus propias definiciones de privilegio.
Ofertas creadas dinámicamente
Una oferta creada dinámicamente es una oferta o una oferta combinada generada en tiempo de ejecución en Verse. Algunos casos de uso habituales de las ofertas dinámicas podrían ser:
Una oferta por la cantidad máxima de madera que un jugador puede tener para un juego de fabricación.
Un lote para maximizar las pociones de salud y maná a la entrada de una mazmorra para un juego de exploración de mazmorras.
Para simplificar, únelas a algo sencillo, como un botón o un letrero. En el código de Verse, esto seguiría el flujo: OnInteraction > llamar a BuyOffer.
Este fragmento de código muestra una forma de vender un paquete de semillas de maíz hasta el máximo que un jugador puede tener. Si falla la compra, se muestra un mensaje de error.
TryBuyOffer(Player : player)<suspends>:void =
Purchases := GetPurchasedEntitlements(Player, Entitlements.corn_seed_pack)
var NumPlayerCornSeedPacks : int = 0
if (Purchase := Purchases[0]):
set NumPlayerCornSeedPacks = Purchase(1)
# Limit to at least 1 packet.
# If the player has the maximum amount, the offer displays with a disabled purchase button.
NumCornSeedPacks := Max(1, Entitlements.corn_seed_pack{}.MaxCount - NumPlayerCornSeedPacks)
Reglas de validación de ofertas
Una oferta o lote válidos deben cumplir las siguientes directrices. Las compras que no cumplan estos requisitos no pasarán el proceso de moderación. Las reglas que definen una oferta válida son las siguientes:
La profundidad de las ofertas anidadas no puede superar 5.
El número total de identificadores de privilegio no puede superar los 100 por oferta. Esto significa que la cantidad total de privilegios diferentes vendidos al mismo tiempo es de 100 como máximo.
El precio de la oferta debe estar comprendido entre 50 y 5000 paVos, y solo puede ser múltiplo de 50.
El texto predeterminado de la propiedad
Namede una oferta no puede superar los 50 caracteres.El texto predeterminado de la propiedad
Descriptionde una oferta no puede superar los 500 caracteres.El texto predeterminado de la propiedad
ShortDescriptionde una oferta no puede superar los 100 caracteres.Una oferta debe contener al menos un privilegio.
Una oferta no puede contener una cantidad de un privilegio superior al recuento máximo (propiedad
MaxCount) del privilegio.Una oferta no puede contener un privilegio duradero con
MaxCount> 1.
Puedes optar por establecer restricciones sobre dónde se muestran tus ofertas y quién puede verlas. Si quieres más información, consulta Restricciones de las transacciones en la isla.
Cómo crear una tienda
Ahora que ya tienes tus privilegios y las ofertas y los lotes configurados, ¡necesitas un lugar donde venderlos!
La interfaz de usuario predeterminada
La IU de tienda predeterminada se abre con una lista de todos los privilegios y las ofertas que has añadido. El primer privilegio de la lista aparece resaltado y muestra una descripción general del privilegio en una ventana junto a la lista.
Las tiendas pueden tener varias páginas.
Las listas con más de cinco elementos son desplazables.
Un jugador inicia el proceso de compra llamando al método BuyOffer o utilizando la tienda predeterminada con el método ShowOffersDialog. A continuación se muestran algunos ejemplos de dispositivos que puedes utilizar para integrar el proceso de compra en tu tienda en el diseño de tu juego:
Dispositivo Volumen
Dispositivo Cronómetro de Scene Graph
PNJ
Dispositivo de conversación
A la hora de diseñar una tienda, lo más recomendable es sugerir al jugador que elija abrir un proceso de compra. Omitir esta opción y obligar a los jugadores a abrir el flujo de compra elimina la capacidad de decisión de los jugadores y conlleva el riesgo de que estos se sientan insatisfechos.
Todas las ofertas tienen los botones Comprar e Inspeccionar, que abren ventanas del mercado para comprar un objeto o ver qué incluye una oferta. Solo los lotes tienen un botón Inspeccionar lote.
Si seleccionas el botón Cerrar, se cerrará el mercado.
La experiencia en la tienda está totalmente controlada por el desarrollador:
Tú decides qué objetos o propiedades del juego quieres ofrecer a tus jugadores.
Tú fijas el precio de cada oferta u oferta combinada.
Puedes presentar tu propia tienda o utilizar la interfaz de usuario prediseñada de Fortnite.
La IU de la tienda
Este fragmento define una devolución de llamada de evento genérica que abre la interfaz de usuario predefinida de la tienda de Fortnite. La devolución de llamada puede originarse con una suscripción, al pulsar un botón, con un evento de conversación, etc.
OnEvent(Agent:agent):void=
if(Player:= player[Agent]):
spawn{ShowOffersDialog(Player, array{
ExampleOffers.shovel{},
ExampleOffers.cornseedpacket{}
})}
Cómo gestionar las compras
Este fragmento de código contiene una oferta de compra genérica. Si falla la compra, se muestra un mensaje de error.
TryBuyOffer(Player:player, Offer : offer)<suspends>:void =
Result := BuyOffer(Player, Offer)
if (not Result?):
Print("Failed to buy the {offer.name} offer.")Para ayudarte a depurar las compras fallidas, incluye una forma de identificar qué compra ha fallado en el mensaje de error, por ejemplo, incluyendo el nombre de la oferta en el mensaje de error anterior.
Funciones adicionales
Objetos aleatorios de pago
Hay dos formas de ofrecer objetos aleatorios de pago en tu isla:
Puedes ofrecerlas directamente para su compra con paVos.
Puedes ofrecerlas indirectamente permitiendo a los jugadores comprar privilegios con paVos que luego se pueden canjear, o influir en la probabilidad de recibir una recompensa aleatoria.
Al crear un objeto que concede una recompensa aleatoria, debes activar la propiedad PaidRandomItem estableciéndola en true.
Si ofreces contenido que se puede utilizar para canjear una recompensa aleatoria, debes utilizar la función RestrictPaidRandomItems para evitar que los jugadores sin acceso adquieran la recompensa aleatoria.
OnEvent(Agent:agent):void=
if (Player := player[Agent]):
if (RestrictPaidRandomItems[Player]):
Print("Player is not allowed to purchase PaidRandomItems.")
else:
Print("Player is allowed to purchase PaidRandomItems.")
Mensajes directos para comprar
Si tu isla tiene mensajes directos para comprar, debes utilizar la función RestrictDirectPromptsToPurchase para determinar si un jugador cumple los requisitos para ver el mensaje.
OnEvent(Agent:agent):void=
if (Player:= player[Agent]):
if (RestrictDirectPromptsToPurchase[Player]):
Print("Player is not allowed to receive direct purchase prompts.")
else:
Print("Player is allowed to receive direct purchase prompts.")
Relevante para el juego
Si el objeto que vendes ofrece a los jugadores una ventaja significativa en tu isla, debes activar la opción ConsequentialToGameplay.
Los objetos relevantes para el juego incluyen cualquier momento en el que, si se compran, proporcionarían a los jugadores una ventaja significativa en el juego. Esto podría ser directo (por ejemplo, un objeto que aumenta la velocidad de progreso, el poder o las capacidades del jugador en el juego) o indirecto (por ejemplo, un objeto que da acceso a otro objeto que influye significativamente en la rapidez con la que el jugador puede progresar en el juego o en sus probabilidades de ganar).
Si existe una alternativa gratuita al objeto que vendes para todos los jugadores en el momento en que se presenta la oferta y que proporcione la misma ventaja, no es necesario que actives la opción ConsequentialToGameplay. Si un objeto del juego tiene un impacto incidental pero irrelevante en la jugabilidad, como ocurre con las paletas de colores de los trajes, que tienen visibilidades ligeramente diferentes en distintos entornos, o con los emoticonos, que producen diferentes movimientos corporales, no se considera relevante.
# The base entitlement you should define for ALL of your entitlements in your experience.
my_island_entitlement := class<abstract><castable>(entitlement){}
CornSeedPacket<public> := module:
Name<public><localizes> : message = "Corn seed pack"
Description<public><localizes> : message = "A pack of corn seeds. Opening a pack yields 10 corn seeds for planting."
ShortDescription<public><localizes> : message = "Contains 10 corn seeds for planting."
cornseedpacket<public> := class<concrete>(my_island_entitlement):
var Name<override>:message = CornSeedPacket.Name