Muchas experiencias utilizan las estadísticas de jugador para realizar un seguimiento de los datos de experiencia de los jugadores en el transcurso del tiempo. Las estadísticas como la puntuación más alta, la cantidad total de partidas ganadas, el tiempo total de juego y los objetos conseguidos transmiten a los jugadores una sensación de avance y son una forma estupenda de animarles a volver a tu experiencia.
Verse Persistence es una herramienta potente que permite añadir datos persistentes a las secuencias de comandos de Verse. Los datos persistentes se guardan por jugador y por isla, y se mantienen inalterados entre sesiones de juego. Los datos persistentes te permitirán realizar un seguimiento del progreso de los jugadores entre sesiones de juego y te abrirán las puertas a una variedad de experiencias de juego únicas e interesantes que hasta ahora no estaban disponibles en UEFN.
Este tutorial te enseñará a crear una tabla personalizada de estadísticas de los jugadores mediante Verse y a configurarlas para que se mantengan en las diferentes reproducciones de tu experiencia. Después de terminar este tutorial, echa un vistazo a Cómo crear tu propia tabla de clasificación dentro del juego en Verse para obtener más información sobre el uso de la persistencia para crear tablas de clasificación en el juego.
Funciones del lenguaje Verse utilizadas
Clase: este ejemplo crea una clase de Verse encargada de gestionar una única estadística, así como una clase persistente que realiza el seguimiento de 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 mapa simple en el cual no se puede iterar. Los datos de persistencia de Verse se deben almacenar en un weak_map.
Cómo configurar el nivel
Este ejemplo utiliza los siguientes elementos y dispositivos.
Dos dispositivos Botón: cuando el jugador interactúa con el dispositivo, suma un punto a su puntuación actual. Utilizarás otro dispositivo Botón para simular el final de una partida, que se sumará a las victorias o derrotas del jugador según su puntuación actual.
Un dispositivo Valla publicitaria: muchas veces es importante mostrar al jugador los datos persistentes. Algunas veces esto se hace con fines de prueba y otras para impulsar la implicación de los jugadores o mostrar el progreso. Si bien los requisitos de cuándo mostrar datos y qué datos mostrar variarán de una experiencia a otra, en este ejemplo se mostrarán los datos de estadísticas de puntuación, puntuación máxima, victorias y derrotas en un dispositivo Valla publicitaria.
Cómo hacer un seguimiento de las estadísticas persistentes del jugador
Antes de nada, es importante definir qué estadísticas quieres registrar por cada jugador. Por ejemplo, puedes hacer un seguimiento de la puntuación histórica de un jugador, su clasificación actual o su mejor tiempo en una vuelta. En este ejemplo, realizarás un seguimiento de la puntuación, las victorias y las derrotas en una tabla de valores de estadísticas para cada jugador. Para ello, crearás una nueva clase, player_stats_table, que será tu clase persistente principal.
Sigue estos pasos para crear la clase player_stats_table:
Crea un nuevo archivo de Verse utilizando el explorador de Verse con el nombre
player_stats_table.verse.En el nuevo archivo de Verse, crea una nueva clase con el nombre
player_stats_table. Añade los modificadores<persistable>y<final>a tu clase. El modificador<persistable>permite que los datos de la clase puedan ser persistentes y requiere el modificador<final>, ya que los datos persistentes no se pueden anular ni subclasificar.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 valores deintcon los nombresScore,WinsyLosses. Registrarán la puntuación, las victorias y las derrotas de cada jugador, respectivamente. Asimismo, añade unintdenominadoVersionpara realizar un seguimiento de la versión actual deplayer_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, utilizarás una función<constructor>. Este constructor es obligatorio porque la persistencia de Verse no permite que las clases que contienen campos variables puedan ser persistentes. La utilización de un constructor te permitirá actualizar los valores de tu clase persistente creando una copia de una estadística persistente existente que sea variable, actualizar la copia y, a continuación, reemplazar la instancia original de la clase con los valores modificados. Añade una nueva función de constructorMakePlayerStatsTable()a tu archivo. Este constructor recibirá una instancia original (anterior) de la claseplayer_stats_tabley creará una nueva a partir de los valores originales indicados.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 las
player_stats_tables, tendrás que utilizar unweak_mappersistente de instancias deplayeraplayer_stats_table. Añade este weak_map a tu archivo.Verse# Maps players to a table of their player stats. var PlayerStatsMap:weak_map(player, player_stats_table) = map{}Tu clase
player_stats_tablefinalizada debería tener ahora el siguiente aspecto: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 gestionar las estadísticas de todos los jugadores
La clase player_stats_table te permite realizar un seguimiento de las estadísticas de un jugador individual, pero todavía no dispones de una forma de gestionarlas. Tienes que actualizar las tablas de estadísticas de cada jugador siempre que consiga una puntuación, y dependiendo del diseño de tu experiencia es posible que haya muchos jugadores a la vez.
Para solucionar esto, tendrás que utilizar otra clase para gestionar las estadísticas de todos los jugadores y registrar los cambios de estadísticas cada vez que un jugador gane, pierda u obtenga puntuación. Sigue los pasos que se indican a continuación para configurar tu clase de gestor.
Crea un nuevo archivo de Verse utilizando el explorador de Verse con el nombre
player_stats_manager. En ese archivo, crea una nueva claseplayer_stats_manager.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 clase
player_stats_managertiene que realizar varias funciones. Tiene que configurar unaplayer_stats_tablepara un jugador, actualizar los valores deScore,WinsyLossespor jugador, y devolver laplayer_stats_tablepara un jugador. Gestionarás cada una de ellas en funciones separadas. Añade una nueva funciónInitializePlayer()a la definición de tu claseplayer_stats_manager. Esta función inicializará las estadísticas del jugador indicado.Verse# Initialize stats for the given player. InitializePlayer(Player:player):void=En
InitializePlayer(), comprueba si el jugador indicado ya existe en elPlayerStatsMap. En caso contrario, establece el valor de ese jugador en el mapa en una nuevaplayer_stats_table. Tu funciónInitializePlayer()finalizada debería tener el siguiente aspecto: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 nueva función
InitializeAllPlayers()a la definición de tu claseplayer_stats_manager. Esta función recibe una matriz de jugadores y llama aInitializePlayer()en cada uno de ellos. Tu funciónInitializeAllPlayers()finalizada debería tener el siguiente aspecto:Verse# Initialize stats for all current players. InitializeAllPlayers(Players:[]player):void = for (Player : Players): InitializePlayer(Player)Para devolver las estadísticas de un jugador determinado, necesitas una función que devuelva la
player_stats_tablede ese jugador. Añade una nueva funciónGetPlayerStats()a la definición de la claseplayer_stats_managerque recibe un agente. Añade el modificador<decides><transacts>para permitir que esta función pueda fallar y revertirse en el caso de que la tabla de estadísticas de un jugador no exista. EnGetPlayerStats(), crea una nueva variablePlayerStatsdeplayer_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, convierte elAgentpasado a esta función en unPlayer, y luego recupera laplayer_stats_tablepara ese jugador desdePlayerStatsMap. Después, establecePlayerStatsen esa tabla llamando aMakePlayerStatsTable(). Por último, devuelvePlayerStats. Tu funciónGetPlayerStats()finalizada debería tener el siguiente aspecto: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 cada una de las estadísticas de Score, Wins y Losses, crearás funciones para cada estadística respectiva. Añade una nueva función denominada
AddScore()a tu archivoplayer_stats_manager. Esta función recibe el agente al que concede puntos y el númerointde puntos para concederlos.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=Los datos se actualizan comprobando primero que el jugador tiene datos válidos en el
weak_mappersistente y, a continuación, sustituyendo esos datos por una copia actualizada de la clase. Para gestionar esto para la puntuación, recupera la puntuación del jugador de laPlayerStatsTable, después establece la tabla enPlayerStatsMapcomo el resultado de crear una nuevaplayer_stats_tablemedianteMakePlayerStatsTable()(pasando la puntuación actual más la nueva). Cuando estás trabajando con una clase que contiene varios campos, el constructor de clase te permite actualizar fácilmente un solo campo sin copiar explícitamente todos los campos cada vez que deseas efectuar una actualización. Tu funciónAddScore()debería tener el siguiente aspecto: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 añadiendo
NewWinsyNewLossesa las victorias o derrotas del jugador respectivamente al llamar 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 final
player_stats_managerdebería tener el siguiente aspecto.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 realizar pruebas de persistencia con dispositivos
Ahora que has configurado las clases de persistencia, es el momento de probarlas en tu nivel.
Crea un nuevo dispositivo de Verse con el nombre player_stats_example. Consulta Cómo crear tu propio dispositivo con Verse para ver los pasos.
En la parte superior de la definición de la clase
player_stats_example, añade los siguientes campos:Un
button_deviceeditable con el nombreScorePointsButton. Este botón aumenta la puntuación del jugador cada vez que se activa.Verse# Adds to the activating player's score. @editable ScorePointsButton:button_device = button_device{}Un
billboard_deviceeditable con el nombreStatsBillboard. Este mostrará la puntuación, la puntuación más 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 con el nombre
CheckWinButton. Este botón reinicia la puntuación de cada jugador y le concede una victoria o una derrota en función de la puntuación del jugador.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 con el nombreWinScore. Esta es la puntuación que los jugadores tienen que alcanzar para que se les conceda una victoria después de que se active el botónCheckWinButton.Verse# The score players need to reach to be awarded a win after # the CheckWinButton is activated. @editable WinScore:int = 10Un
inteditable con el nombreAwardScore. Esta es la puntuación que reciben los jugadores al interactuar con el botón.Verse# The amount of score to award per button press. @editable AwardScore:int = 1Un
player_stats_managercon el nombrePlayerStatsManager. Este se encargará de gestionar y actualizar las estadísticas de todos los jugadores.Verse# Manages and updates stats for each player. PlayerStatsManager:player_stats_manager = player_stats_manager{}Un mensaje denominado StatsMessage que toma los cuatro enteros de un agente: Score, MaxScore, Wins y Losses. Utilizarás este mensaje para mostrar las estadísticas de un jugador en la valla publicitaria.
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 el código y suelta el dispositivo con autorización de Verse en tu isla. Consulta Cómo añadir el dispositivo de Verse al nivel para ver los pasos a seguir.
En el panel Detalles de tu dispositivo, asigna el dispositivo Botón de tu nivel a ScorePointsButton y asigna el dispositivo Valla publicitaria a StatsBillboard.
Para mostrar las estadísticas de un jugador determinado en StatsBillboard, añade una nueva función
UpdateStatsBillboard()a la definición de tu claseplayer_stats_example. Esta función recibe el agente cuyas estadísticas se desean 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 indicado llamando a la funciónGetPlayerStats[]del gestor de estadísticas. A continuación, llama aSetText()en StatsBillboard pasando un nuevoStatsMessage(). Para construir esteStatsMessage(), obtén los valores Score, Wins, y Losses del agente accediendo a ellos desde las estadísticas actuales del agente. Tu funciónUpdateStatsBillboard()finalizada debería tener el siguiente aspecto: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 nueva función
AddScore()a la definición de tu claseplayer_stats_example. Esta función recibe un agente y añade puntos a la puntuación de ese agente cada vez que interactúa con el botón 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 indicado, así como su puntuación actual. A continuación, llama aAddScore()desdePlayerStatsManager, pasando el agente yAwardScorepara otorgarles una nueva puntuación. Por último, llama aUpdateStatsBillboard(), pasando el agente indicado. Tu funciónAddScore()finalizada debería tener el siguiente aspecto: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 conceder a un jugador una victoria o una derrota al interactuar con el botón CheckWin, añade una nueva función
CheckWin()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 variable
CurrentScorepara hacer un seguimiento de la puntuación actual del agente. A continuación, al igual que con la funciónAddScore(), recupera su puntuación actual de la tabla de estadísticas de jugadores.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 mayor que el valor
WinScore, tendrás que registrar una victoria en elPlayerStatsManager. En caso contrario, registra una derrota. Por último, restablece la puntuación del agente llamando aAddScore()con unCurrentScorenegativo y luego muestra las estadísticas del agente en la valla publicitaria de estadísticas. Tu funciónCheckWin()finalizada debería tener el siguiente aspecto: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(). Después, obtén la matriz de cada jugador del juego llamando aGetPlayers(), e inicialízalos todos con la funciónInitializeAllPlayers()del gestor 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 realizar pruebas de persistencia en tu nivel
Puedes probar tus datos de persistencia en una sesión de edición, pero estos datos se reiniciarán cuando cierres y vuelvas a comenzar la sesión. Para que tus datos se mantengan entre sesiones, tendrás que abrir una sesión de prueba y cambiar algunos ajustes en la configuración de la isla. Para obtener más información sobre cómo configurar la isla para probar datos persistentes tanto en sesiones de edición como de prueba de juego, consulta Cómo realizar pruebas con datos persistentes en la página de datos persistentes.
Después de configurar tu sesión, cuando realices una prueba de juego del nivel, la interacción con el botón ScorePoints debería añadir puntos a la puntuación del jugador y mostrar esa actualización en la valla publicitaria. La interacción con el botón CheckWin debería añadir victorias o derrotas al jugador en función de su puntuación. Tras volver a la sala y entrar de nuevo en tu isla, las estadísticas del jugador deberían mantenerse y su total de victorias/derrotas y puntuación más alta deberían mostrarse en la valla publicitaria cada vez que se actualice.
Por tu cuenta
Al completar esta guía, habrás aprendido a utilizar Verse para crear datos persistentes registrados por jugador que se mantienen entre sesiones de juego. Ahora ya puedes decidir cómo adaptar la persistencia para mejorar tu experiencia.
¿Puedes crear un sistema de archivos de guardado que recuerde el último punto de control alcanzado por un jugador?
¿Qué te parece un sistema capaz de recordar con qué personajes has hablado y tu relación con cada uno de ellos?
¿Y qué tal un sistema que solo concede a los jugadores una cantidad limitada de tiempo entre sesiones para alcanzar objetivos y reinicia el progreso si fallan?
Código completo
A continuación encontrarás el código completo creado en este tutorial:
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