Muchas experiencias usan las estadísticas de jugador para realizar un seguimiento de la experiencia de los jugadores con el transcurso del tiempo. Las estadísticas de puntajes más altos, cantidad de partidas ganadas, tiempo total de juego y objetos recogidos proporcionan a los jugadores un panorama general de cuánto han avanzado, y son recursos muy buenos para hacer que los jugadores regresen a tu experiencia.
Verse Persistence es una herramienta eficaz que te permite agregar datos persistentes a tus secuencias de comandos de Verse. Los datos persistentes se guardan por jugador y por isla, y son los mismos entre sesiones de juego. Con los datos persistentes podrás realizar un seguimiento del progreso de los jugadores entre sesiones de juego y desbloquearás una variedad de experiencias de juego únicas e interesantes que antes no eran posibles en UEFN.
En este tutorial, se mostrará cómo crear una tabla personalizada de las estadísticas de los jugadores con Verse y cómo configurarlas para que sean permanentes en varias sesiones de tu experiencia. Después de terminar este tutorial, consulta Cómo crear tu propia tabla de clasificación en el juego en Verse para aprender a utilizar la persistencia y compilar las tablas de clasificación en el juego.
Funciones usadas del lenguaje Verse
Clase: en este ejemplo, se crea una clase de Verse que administra una única estadística, así como una clase persistente que rastrea a un grupo de estadísticas para un único jugador.
Constructor: un constructor es una función especial que crea una instancia de la clase a la que está asociado.
Weak_map: un weak_map es un simple mapa sobre el que no se puede iterar. Los datos persistentes de Verse deben almacenarse en la variable weak_map.
Configuración del nivel
En este ejemplo, se utilizan las utilerías y los dispositivos que aparecen a continuación.
2 dispositivos de botón: cuando el jugador interactúa con el dispositivo, se añade un punto a su puntuación actual. Usarás otro dispositivo de botón para simular el final de una partida, adjudicando victorias o derrotas al jugador según su puntuación actual.
1 dispositivo de cartelera: a menudo, es importante mostrar datos persistentes al jugador. A veces esto se hace con fines de prueba, y otras, para potenciar la participación del jugador o mostrar el progreso. Si bien los requisitos de cuándo mostrar los datos y qué datos mostrar varían de acuerdo con cada experiencia, en este ejemplo, mostrarás datos estadísticos para puntuación, puntuación alta, victorias y derrotas en un dispositivo de cartel publicitario.
Cómo realizar un seguimiento persistente de las estadísticas del jugador
Primero, es importante definir de qué estadísticas deseas realizar un seguimiento por jugador. Por ejemplo, es posible que quieras realizar un seguimiento del puntaje histórico de un jugador, su clasificación actual o su mejor tiempo en una vuelta. En este ejemplo, vas a realizar un seguimiento de la puntuación, las victorias y las derrotas en una tabla de valores estadísticos para cada jugador. Para hacerlo, usarás una clase nueva, player_stats_table, que será tu clase persistente principal.
Sigue estos pasos para crear tu clase player_stats_table:
Crea un archivo de Verse nuevo con el explorador de Verse denominado
player_stats_table.verse.En el archivo de Verse nuevo, crea una clase nueva que se llame
player_stats_table. Añade los modificadores<persistable>y<final>a la clase. El modificador<persistable>permite que los datos de la clase sean persistentes y requiere el modificador<final>, ya que los datos persistentes no pueden anularse ni utilizarse para crear una subclase.Verseusing { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # Tracks different persistable stats for each player. player_stats_table := class<final><persistable>:En tu
player_stats_table, añade tres valoresintdenominadosScore(puntuación),Wins(victorias) yLosses(derrotas). Estos valores permiten realizar un seguimiento de la puntuación acumulada, las victorias y las derrotas para cada jugador respectivamente. También, añade un valorintcon el nombreVersionpara realizar un seguimiento de la versión actual de tuplayer_stats_table.Verse# Tracks different persistable stats for each player. player_stats_table := class<final><persistable>: # The version of the current stats table. Version<public>:int = 0 # The score of a player. Score<public>:int = 0 # The number of wins for a player. Wins<public>:int = 0Para crear una instancia de la
clase player_stats_table, usarás una función de<constructor>. Este constructor es obligatorio porque la persistencia de Verse no permite que las clases que contienen campos de variables sean persistentes. Si usas un constructor, podrás actualizar los valores de tu clase persistente. Para ello, crea una copia de una estadística persistente existente que sea variable, actualiza la copia y, a continuación, reemplaza la instancia original de la clase por los valores modificados. Añade la función de constructorMakePlayerStatsTable()nueva a tu archivo. Este constructor tomará una instancia original (anterior) de la claseplayer_stats_tabley creará una nueva a partir de los valores originales dados.Verse# Creates a new player_stats_table with the same values as the previous player_stats_table. MakePlayerStatsTable<constructor>(OldTable:player_stats_table)<transacts> := player_stats_table: Version := OldTable.Version Score := OldTable.Score Wins := OldTable.Wins Losses := OldTable.LossesPara realizar un seguimiento de todas tus
player_stats_tables, usarás unweak_mappersistente deplayeren las instancias deplayer_stats_table. Agrega este mapa débil a tu archivo.Verse# Maps players to a table of their player stats. var PlayerStatsMap:weak_map(player, player_stats_table) = map{}Ahora, tu clase completa de
player_stats_tabledebería verse así:Verseusing { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # Tracks different persistable stats for each player. player_stats_table := class<final><persistable>: # The version of the current stats table. Version<public>:int = 0 # The score of a player.
Cómo administrar las estadísticas de jugador para todos los jugadores
Con tu clase player_stats_table, puedes realizar un seguimiento de las estadísticas de un jugador individual, pero aún no tienes forma de administrarlas. Es necesario que actualices las tablas de estadísticas para cada jugador cada vez que gana puntos, y según el diseño de tu experiencia, puede haber muchos jugadores a la vez.
Para solucionar esto, usarás otra clase para administrar las estadísticas de todos los jugadores, y registrarás los cambios de las estadísticas cada vez que un jugador obtenga una victoria, experimente una derrota o gane puntos. Sigue los pasos a continuación para configurar la clase de administrador.
Crea un archivo de Verse nuevo con el explorador de Verse denominado
player_stats_manager. En ese archivo, crea una claseplayer_stats_managernueva.Verseusing { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # Manages and updates player_stat_tables for each player. player_stats_manager := class():Tu
player_stats_managertiene que hacer varias cosas. Tiene que configurar unaplayer_stats_tablepara un jugador, actualizar las estadísticasScore,WinsyLossespor jugador, y regresar laplayer_stats_tablepara un jugador. Manejarás cada una de estas características en funciones por separado. Añade una funciónInitializePlayer()nueva a la definición de la claseplayer_stats_manager. Esta función inicializará las estadísticas para el jugador dado.Verse# Initialize stats for the given player. InitializePlayer(Player:player):void=En
InitializePlayer(), comprueba si el jugador dado ya existe en elPlayerStatsMap. De lo contrario, establece el valor de ese jugador en el mapa en unaplayer_stats_tablenueva. Tu funciónInitializePlayer()completa debería verse de la siguiente manera:Verse# Initialize stats for the given player. InitializePlayer(Player:player):void= if: not PlayerStatsMap[Player] set PlayerStatsMap[Player] = player_stats_table{} else: Print("Unable to initialize player stats")Añade una función
InitializeAllPlayers()nueva a la definición de la claseplayer_stats_manager. Esta función toma una matriz de jugadores y llama aInitializePlayer()en todos ellos. Tu funciónInitializeAllPlayers()completa debería verse de la siguiente manera:Verse# Initialize stats for all current players. InitializeAllPlayers(Players:[]player):void = for (Player : Players): InitializePlayer(Player)Si deseas devolver las estadísticas para un jugador específico, necesitas una función que devuelva la
player_stats_tablede ese jugador. Añade una funciónGetPlayerStats()nueva a la definición de la claseplayer_stats_managerque tome a un agente. Añade el modificador<decides><transacts>para permitir la falla y la reversión de esta función en el caso donde no exista la tabla de estadísticas de un jugador. EnGetPlayerStats(), crea una nueva variable,PlayerStats, deplayer_stats_table.Verse# Return the player_stats_table for the provided Agent. GetPlayerStats(Agent:agent)<decides><transacts>:player_stats_table= var PlayerStats:player_stats_table = player_stats_table{}En una expresión
if, proyecta elagentetransferido a esta función a unjugadory, luego, obtén laplayer_stats_tablepara ese jugador dePlayerStatsMap. Luego, llama aMakePlayerStatsTable()para establecerPlayerStatsen esa tabla. Por último, devuelvePlayerStats. Tu funciónGetPlayerStats()completa debería verse de la siguiente manera:Verse# Return the player_stats_table for the provided Agent. GetPlayerStats(Agent:agent)<decides><transacts>:player_stats_table= var PlayerStats:player_stats_table = player_stats_table{} if: Player := player[Agent] PlayerStatsTable := PlayerStatsMap[Player] set PlayerStats = MakePlayerStatsTable(PlayerStatsTable) PlayerStatsPara actualizar las estadísticas de puntuación, victorias y derrotas, vas a crear funciones para cada estadística correspondiente. Añade una nueva función llamada
AddScore()a tu archivoplayer_stats_manager. Esta función necesita que el agente otorgue puntuaciones y el númerointde puntos para otorgar.Verse# Adds to the given Agent's score and updates both their stats table # in PlayerStatsManager and the billboard in the level. AddScore<public>(Agent:agent, NewScore:int):void=Para actualizar los datos, primero se confirma que el jugador tenga datos válidos en el
weak_mappersistente y, luego, esos datos se reemplazan por una copia actualizada de la clase. Para manejar esto en la puntuación, obtén la puntuación del jugador dePlayerStatsTable; luego, establece la tabla enPlayerStatsMapcon el resultado de construir unaplayer_stats_tablenueva medianteMakePlayerStatsTable()y, así, transferir la puntuación actual más la puntuación nueva. Cuando trabajas con una clase que contiene varios campos, el constructor de la clase te permite actualizar con facilidad un único campo sin copiar de forma explícita todos los campos cada vez que quieres hacer una actualización. Tu funciónAddScore()debería verse de la siguiente manera:Verse# Adds to the given Agent's score and updates both their stats table # in PlayerStatsManager and the billboard in the level. AddScore<public>(Agent:agent, NewScore:int):void= if: Player := player[Agent] PlayerStatsTable := PlayerStatsMap[Player] CurrentScore := PlayerStatsTable.Score set PlayerStatsMap[Player] = player_stats_table: MakePlayerStatsTable<constructor>(PlayerStatsTable) Score := CurrentScore + NewScoreRepite este proceso para las victorias y las derrotas, y suma
NewWinsyNewLossesa las victorias o las derrotas del jugador respectivamente cuando llames aMakePlayerStatsTable().Verse# Adds to the given Agent's wins and updates both their stats table # in PlayerStatsManager and the billboard in the level. AddWin<public>(Agent:agent, NewWins:int):void= if: Player := player[Agent] PlayerStatsTable := PlayerStatsMap[Player] CurrentWins := PlayerStatsTable.Wins set PlayerStatsMap[Player] = player_stats_table: MakePlayerStatsTable<constructor>(PlayerStatsTable) Wins := CurrentWins + NewWinsTu archivo
player_stats_managerfinal debe verse de la siguiente manera.Verseusing { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } # Manages and updates player_stat_tables for each player. player_stats_manager := class(): # Return the player_stats_table for the provided Agent. GetPlayerStats(Agent:agent)<decides><transacts>:player_stats_table= var PlayerStats:player_stats_table = player_stats_table{}
Cómo probar la persistencia con dispositivos
Ahora que configuraste las clases de persistencia, es hora de que las pruebes en tu nivel.
Crea un dispositivo nuevo de Verse llamado player_stats_example. Consulta Cómo crear tu propio dispositivo con Verse para conocer los pasos.
En la parte superior de la definición de la clase
player_stats_example, añade los siguientes campos:Un
button_deviceeditable denominadoScorePointsButton. Cada vez que se activa, este botón se agrega a la puntuación del jugador.Verse# Adds to the activating player's score. @editable ScorePointsButton:button_device = button_device{}Un
billboard_deviceeditable denominadoStatsBillboard. Esto mostrará la puntuación, la puntuación alta, las victorias y las derrotas del jugador.Verse# Displays the player's Score, High Score, Wins, and Losses @editable StatsBillboard:billboard_device = billboard_device{}Un button_device editable denominado
CheckWinButton. Este botón restablece la puntuación de cada jugador y le adjudica una victoria o una derrota de acuerdo con su puntuación.Verse# Resets the player's score and award them a win or a loss # depending if their current score is greater than WinScore. @editable CheckWinButton:button_device = button_device{}Un
inteditable denominadoWinScore. Se trata de la puntuación que deben tener los jugadores para que se les conceda una victoria después de que se active elCheckWinButton.Verse# The score players need to reach to be awarded a win after # the CheckWinButton is activated. @editable WinScore:int = 10Un
inteditable denominadoAwardScore. Es la puntuación que reciben los jugadores cuando interactúan con el botón.Verse# The amount of score to award per button press. @editable AwardScore:int = 1Un
player_stats_managerdenominadoPlayerStatsManager. Se encarga de administrar y actualizar las estadísticas para todos los jugadores.Verse# Manages and updates stats for each player. PlayerStatsManager:player_stats_manager = player_stats_manager{}Mensaje denominado StatsMessage que toma cuatro enteros a un agente: puntuación, MaxScore, victorias y derrotas. Lo utilizarás para mostrar las estadísticas de un jugador en el cartel publicitario.
Verse# Displays a player's stats on a billboard. StatsMessage<localizes>(Player:agent, Score:int, Wins:int, Losses:int):message = "{Player}, Stats:\n Score: {Score}\n Wins: {Wins}\n Losses: {Losses}"
Compila tu código y arrastra tu dispositivo creado con Verse a tu isla. Consulta Cómo añadir el dispositivo de Verse a tu nivel para ver los pasos.
En el panel de detalles de tu dispositivo, asigna el dispositivo de botón de tu nivel a ScorePointsButton y el dispositivo de cartelera a StatsBillboard.
Para mostrar las estadísticas de un determinado jugador en el StatsBillboard, añade una función
UpdateStatsBillboard()nueva a la definición de la claseplayer_stats_example. Esta función toma al agente cuyas estadísticas se van a mostrar.Verse# Retrieves the stats of the given player and displays their stats # on the StatsBillboard. UpdateStatsBillboard(Agent:agent):void=En
UpdateStatsBillboard(), obtén las estadísticas actuales del agente determinado; para ello, llama a la funciónGetPlayerStats[]del administrador de estadísticas. Luego, llama aSetText()en el StatsBillboard pasando unStatsMessage()nuevo. Para construir esteStatsMessage(), consulta las estadísticas actuales del agente para acceder y conocer su puntuación, sus victorias y sus derrotas. Tu funciónUpdateStatsBillboard()completa debería verse de la siguiente manera:Verse# Retrieves the stats of the given player and displays their stats # on the StatsBillboard. UpdateStatsBillboard(Agent:agent):void= if: # Get the current stats of the given agent. CurrentPlayerStats := PlayerStatsManager.GetPlayerStats[Agent] then: StatsBillboard.SetText( StatsMessage( Player := Agent,Añade una función
AddScore()nueva a la definición de la claseplayer_stats_example. Esta función toma un agente y aumenta su puntuación cada vez que este interactúa con el ScorePointsButton.Verse# Adds to the given player's score and updates both their stats table # in PlayerStatsManager and the billboard in the level. AddScore(Agent:agent):void=En
AddScore(), obtén las estadísticas actuales del agente dado, así como también su puntuación actual. A continuación, llama aAddScore()desde elPlayerStatsManager, pasando al agente y laAwardScorepara concederle una puntuación nueva. Por último, llama aUpdateStatsBillboard(), pasando al agente dado. Tu funciónAddScore()completa debería verse de la siguiente manera:Verse# Adds to the given player's score and updates both their stats table # in PlayerStatsManager and the billboard in the level. AddScore(Agent:agent):void= if: CurrentPlayerStats := PlayerStatsManager.GetPlayerStats[Agent] CurrentScore := CurrentPlayerStats.Score then: Print("Current Score is: {CurrentScore}") PlayerStatsManager.AddScore(Agent, AwardScore) UpdateStatsBillboard(Agent)Para adjudicar una victoria o una derrota a un jugador cuando se interactúa con el botón CheckWin, añade una función
CheckWin()nueva a la definición de la clase player_stats_manager.Verse# Awards a player a win or a loss when they interact # with the CheckWinButton. CheckWin(Agent:agent):void=Primero, define una
CurrentScorevariable para realizar un seguimiento a la puntuación actual del agente. Luego, como con la funciónAddScore(), recupera su puntuación actual de la tabla de estadísticas del jugador.Verse# Awards a player a win or a loss when they interact # with the CheckWinButton. CheckWin(Agent:agent):void= var CurrentScore:int = 0 if: PlayerStats := PlayerStatsManager.GetPlayerStats[Agent] set CurrentScore = PlayerStats.ScoreSi la puntuación actual del agente es superior a
WinScore, es necesario que registres una victoria en elPlayerStatsManager. De lo contrario, registra una derrota. Por último, llama aAddScore()para restablecer la puntuación del agente con unaCurrentScorenegativa. Luego, muestra las estadísticas del agente en la cartelera de estadísticas. Tu funciónCheckWin()completa debería verse de la siguiente manera:Verse# Awards a player a win or a loss when they interact # with the CheckWinButton. CheckWin(Agent:agent):void= var CurrentScore:int = 0 if: PlayerStats := PlayerStatsManager.GetPlayerStats[Agent] set CurrentScore = PlayerStats.Score then: Print("Current Score is: {CurrentScore}") if:En
OnBegin(), suscribe elScorePointsButton.InteractedWithEventaAddScore()y elCheckWinButton.InteractedWithEventaCheckWin(). Luego, llama aGetPlayers()para obtener la matriz de cada jugador del juego e inicializa todos los jugadores con la funciónInitializeAllPlayers()del administrador de estadísticas.Verse# Runs when the device is started in a running game OnBegin<override>()<suspends>:void= # Register Button Events ScorePointsButton.InteractedWithEvent.Subscribe(AddScore) CheckWinButton.InteractedWithEvent.Subscribe(CheckWin) Players := GetPlayspace().GetPlayers() # Initialize player stats PlayerStatsManager.InitializeAllPlayers(Players)Guarda tu código y compílalo.
Cómo probar la persistencia en tu nivel
Puedes probar los datos de persistencia en una sesión de edición, pero estos datos se restablecerán cuando salgas de la sesión y la vuelvas a iniciar. Para que los datos persistan en todas las sesiones, tendrás que iniciar una sesión de prueba de juego y cambiar cierta configuración en los ajustes de la isla. Para obtener información sobre cómo configurar tu isla para probar los datos persistentes en las sesiones de edición y de prueba de juego, consulta Cómo realizar pruebas con datos persistentes en la página de datos persistentes.
Después de configurar la sesión, cuando realizas la prueba de juego de tu nivel, tras interactuar con el botón ScorePoints, debería aumentar la puntuación del jugador, y esa actualización debe aparecer en el cartel publicitario. Interactuar con el botón CheckWin debería aumentar el número de victorias o derrotas del jugador según su puntuación. Después de regresar a la sala y volver a entrar a la isla, las estadísticas del jugador deben persistir y el número de victorias o derrotas totales y su puntuación alta deben aparecer en el cartel publicitario cada vez que se actualiza.
Hazlo por tu cuenta
Al completar esta guía, aprendiste a utilizar Verse para crear datos persistentes que se pueden rastrear por jugador y que persisten en todas las sesiones de juego. Ahora piensa en cómo puedes adaptar la persistencia para elevar tu propia experiencia
¿Puedes crear un sistema de archivos de guardado que recuerde el último punto de control al que llegó un jugador?
¿Y si un sistema pudiera recordar con qué personajes hablaste y la relación que tienes actualmente con ellos?
¿Y si un sistema otorgara a los jugadores solo una cantidad limitada de tiempo en todas las sesiones para lograr objetivos y restableciera su progreso en caso de que fallen?
Código completo
Este es el código completo compilado en el tutorial de esta sección.
player_stats_table.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Tracks different persistable stats for each player.
player_stats_table := class<final><persistable>:
# The version of the current stats table.
Version<public>:int = 0
# The score of a player.
player_stats_manager.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Manages and updates player_stat_tables for each player.
player_stats_manager := class():
# Return the player_stats_table for the provided Agent.
GetPlayerStats(Agent:agent)<decides><transacts>:player_stats_table=
var PlayerStats:player_stats_table = player_stats_table{}
player_stats_example.verse
using { /Fortnite.com/Devices }
using { /Fortnite.com/Game }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# A Verse-authored creative device that can be placed in a level
player_stats_example := class(creative_device):
# Adds to the activating player's score.
@editable