En los juegos de carreras, es habitual que los jugadores tengan una posición de salida diferente en función de lo bien que lo hayan hecho en una ronda anterior. Anima a los jugadores a terminar la carrera rápidamente aunque no estén en primer lugar para que empiecen por delante de los demás jugadores.
Para conseguirlo, el juego necesita saber en qué ronda están los jugadores y el orden de llegada de los corredores debe persistir en todas las rondas, pero no en todas las sesiones de juego. Una variable `weak_map` de sesión en Verse restablece sus datos en cada ronda, por lo que esta información de la ronda debe almacenarse con cada jugador mediante una variable `weak_map` de jugador y reiniciarse al terminar el juego.
Actualmente, un proyecto solo puede tener hasta dos variables `weak_map` de jugador. Si tu proyecto ya tiene una variable `weak_map` de jugador, es recomendable que la segunda registre la información de la ronda para diferenciar los datos que siempre deben persistir de los datos que restablecerás después de que el juego termine o un jugador abandone la sesión.
También es importante saber en qué ronda están los jugadores para aplicar la lógica específica de cada ronda y restablecer la información de la última ronda. Actualmente no existe una API para obtener la ronda actual, por lo que esta información también debe registrarse en los datos persistentes de cada jugador.
En resumen, necesitarás una variable `weak_map` de jugador que tenga al menos la siguiente información:
Orden de llegada
Última ronda completada
Las secciones siguientes te muestran cómo configurar estos datos y la lógica de las rondas. Encontrarás el código completo al final de la página.
Cómo registrar la última ronda completada
Sigue estos pasos para configurar los datos persistentes de cada jugador y registrar la última ronda completada.
Crea una clase de persistencia denominada
player_circuit_infopara almacenar la información de los jugadores a lo largo de las rondas. Esta clase debe tener los campos para representar el último orden de llegada del jugador,LastRoundFinishOrder, y su última ronda completada,LastCompletedRound. Estos campos se inicializan con-1para representar valores no válidos, de modo que sepas cuándo estos campos contienen realmente información útil.Verse# Tracks the number of and in what order a player finished the previous round. player_circuit_info<public> := class<final><persistable>: Version:int = 0 LastRoundFinishOrder:int = -1 LastCompletedRound<public>:int = -1Crea una variable `weak_map` de mapa de jugador utilizando la clase
player_circuit_infopara mantener la información de la ronda con los jugadores.Verse# A persistable map that maps each player to # what order they finished the previous round. var CircuitInfo<public>:weak_map(player, player_circuit_info) = map{}Como práctica recomendada para trabajar con datos de persistencia, crea un constructor para que la clase de persistencia pueda actualizar fácilmente la información de cada jugador. Para obtener más información, consulta Cómo utilizar constructores para actualizaciones parciales.
Verse# Creates a new player_circuit_info from the given older player_circuit_info. MakePlayerCircuitInfo<constructor>(OldPlayerCircuitInfo:player_circuit_info)<transacts> := player_circuit_info: Version := OldPlayerCircuitInfo.Version LastRoundFinishOrder := OldPlayerCircuitInfo.LastRoundFinishOrder LastCompletedRound := OldPlayerCircuitInfo.LastCompletedRoundAhora que has definido estructuras para estos datos, añade una función para registrar el orden de llegada de un jugador y actualizar sus datos de persistencia. Esta función utiliza el constructor realizado en el paso anterior para actualizar parcialmente los datos de la única información que te interesa: el orden de llegada.
Verse# Creates a new player_circuit_info for the given player with the order they finished the round in. RecordPlayerFinishOrder<public>(Agent:agent, FinishOrder:int)<decides><transacts>:void= Player := player[Agent] Player.IsActive[] PlayerCircuitInfo:player_circuit_info = if: Info := CircuitInfo[Player] then: Info else: player_circuit_info{}Crea otra función para actualizar solo la última ronda completada por el jugador.
Verse# Updates a player's player_circuit_info with their last completed round. UpdateRound<public>(Agent:agent, CompletedRound:int)<decides><transacts>:void= Player := player[Agent] Player.IsActive[] PlayerCircuitInfo := CircuitInfo[Player] set CircuitInfo[Player] = player_circuit_info: MakePlayerCircuitInfo<constructor>(PlayerCircuitInfo) LastCompletedRound := CompletedRoundAhora que puedes registrar la última ronda completada por el jugador, crea una función para calcular la última ronda completada de la partida comprobando qué jugadores tienen la última ronda registrada. Tienes que comprobar todos los jugadores para tener en cuenta los jugadores que puedan haberse unido a la sesión en curso. La variable de la última ronda completada se inicializa con
-1para representar datos no válidos. Si algún jugador tiene un valor mayor que-1, significa que una ronda ya ha terminado.Verse# Returns the highest last completed round among all players. GetLastCompletedRound<public>(Players:[]player, TotalRounds:int)<transacts>:int= var LastCompletedRound:int = -1 for: Player : Players Player.IsActive[] PlayerCircuitInfo := CircuitInfo[Player] do: # Update LastCompletedRound if this player has the highest last completed round. else if:Crea un dispositivo de Verse para comprobar que el orden de finalización de rondas y jugadores funciona como se espera. Asegúrate de que tu proyecto está configurado para varias rondas. Para ello, establece la propiedad TotalRounds en Ajustes de la isla.
Verse# A Verse-authored creative device that can be placed in a level test_round_info_device := class(creative_device): # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= Players := GetPlayspace().GetPlayers() CurrentRound := GetLastCompletedRound(Players) + 1 Print("Current round is {CurrentRound}") for:
Cómo restablecer la información de la ronda cuando el jugador abandona
Los datos persistentes del jugador para la información de la ronda deben restablecerse cuando un jugador abandona durante la partida. Puedes suscribirte al evento PlayerRemovedEvent del espacio de juego para saber cuándo se van.
Sigue estos pasos para restablecer la información de la ronda cuando un jugador abandona:
Crea una función para restablecer los datos de persistencia del jugador para la información de la ronda. Esto significa establecer los valores en
-1o lo que decidas para representar los datos no válidos de esos campos. Esta implementación opta por qué datos deben restablecerse en caso de que añadas otra información más adelante a la clase persistente que no deba restablecerse aquí.Verse# Resets a player's player_circuit_info. ResetCircuitInfo<public>(Agent:agent)<decides><transacts>:void= Player := player[Agent] Player.IsActive[] PlayerCircuitInfo := CircuitInfo[Player] set CircuitInfo[Player] = player_circuit_info: MakePlayerCircuitInfo<constructor>(PlayerCircuitInfo) LastRoundFinishOrder := -1 LastCompletedRound := -1Crea una función denominada
OnPlayerRemovedpara restablecer la información de la ronda cuando un jugador abandona.Verse# When a player is removed from the race, reset their circuit to prevent their # stats from showing up on billboards and player references. OnPlayerRemoved(Player:player):void= # Reset circuit info when player leaves the game. if: ResetCircuitInfo[Player] else: Print("Unable to reset circuit info for player")Configura la función
OnPlayerRemovedque se llamará cuando un jugador abandone la partida. Puedes hacerlo suscribiéndote al eventoGetPlayspace().PlayerRemovedEvent().Verse# A Verse-authored creative device that can be placed in a level test_round_info_device := class(creative_device): # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= GetPlayspace().PlayerRemovedEvent().Subscribe(OnPlayerRemoved) Players := GetPlayspace().GetPlayers() CurrentRound := GetLastCompletedRound(Players) + 1Haz una prueba para verificar que se restablece la información del jugador que abandona el juego.
Cómo restablecer la información de la ronda al final de la partida
La función OnBegin de un dispositivo de Verse se ejecuta al inicio de cada ronda. Este es un buen momento para determinar si un jugador tiene datos persistentes inesperados, por ejemplo, si su última ronda completada coincide con el número total de rondas. Si es así, tienes que restablecer los datos del jugador. Actualmente no existe ninguna API para conocer el número total de rondas de una partida. En su lugar, debes añadir una propiedad editable al dispositivo de Verse para el total de rondas en el código Verse y asegurarte de que coincide con la propiedad TotalRounds en Ajustes de la isla.
Sigue estos pasos para restablecer la información de la ronda cuando el juego haya terminado:
Añade una propiedad editable a tu dispositivo de Verse para el número total de rondas del juego. TotalRounds no debe ser menor o igual que
0, así que limita los valores de la propiedad a mayor o igual que1.Verse# A Verse-authored creative device that can be placed in a level test_round_info_device := class(creative_device): # The total number of rounds in the race. @editable TotalRounds:type {Rounds:int where 1 <= Rounds} = 3 # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= GetPlayspace().PlayerRemovedEvent().Subscribe(OnPlayerRemoved)Actualiza la función de
GetLastCompletedRoundpara restablecer los datos de persistencia del jugador de la última ronda completada si es mayor que el número esperado de rondas en el juego.Verse# Returns the highest last completed round among all players. GetLastCompletedRound<public>(Players:[]player, TotalRounds:int)<transacts>:int= var LastCompletedRound:int = -1 for: Player : Players Player.IsActive[] PlayerCircuitInfo := CircuitInfo[Player] do: # If player's recorded info is greater than the total rounds for whatever reason, # then need to reset the player's circuit info because they shouldn't have more than what's allowed.Actualiza la llamada a
GetLastCompletedRoundpara pasar el total de rondas como argumento y restablecer la información de las rondas de los jugadores si están en un estado inesperado.Verse# A Verse-authored creative device that can be placed in a level test_round_info_device := class(creative_device): # The total number of rounds in the race. @editable TotalRounds:type {Rounds:int where 1 <= Rounds} = 3 # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= GetPlayspace().PlayerRemovedEvent().Subscribe(OnPlayerRemoved)Haz una prueba para verificar que la información de la ronda del jugador se restablece incluso después de jugar y completar todas las rondas.
Cómo añadir lógica basada en la ronda actual
Ahora, puedes utilizar esta información para tener una lógica personalizada en función de la ronda en la que se encuentren los jugadores. Por ejemplo, podrías mostrar una clasificación local para la primera ronda de una partida.
Llamar a GetLastCompletedRound() cada vez que necesitas saber qué ronda se está jugando no es lo idóneo. En su lugar, puedes hacerlo una vez por ronda y registrar la información de la ronda en una variable `weak_map` de sesión, de modo que todo el código de Verse del proyecto pueda acceder a este valor en cualquier momento sin necesidad de volver a calcularlo cada vez.
Este es un gran ejemplo para mostrar las diferencias y el razonamiento para utilizar la variable `weak_map` de sesión y la variable `weak_map` de jugador en tu código:
Las variables `weak_map` de sesión son útiles para elementos únicos y para almacenar datos de la ronda actual que no quieras volver a calcular cada vez.
Las variables `weak_map` del jugador están diseñadas para la información que debe mantenerse a lo largo de varias rondas y sesiones de juego, pero que debe asociarse a jugadores individuales.
Sigue estos pasos para configurar una variable `weak_map` de sesión para almacenar la ronda actual.
Crea una clase para almacenar la información de la ronda. Necesitas al menos un campo para
CurrentRound, pero podrías incluir otra información de la ronda que quieras guardar en todo tu código Verse, como las posiciones iniciales y los vehículos de los jugadores. InicializaCurrentRounden-1para representar datos no válidos.Verseround_info := class: CurrentRound:int = -1Crea una variable `weak_map` de sesión utilizando la clase
round_infopara almacenar la información de la ronda con la sesión.Verse# Maps the current session to its associated round info. var RoundInfo:weak_map(session, round_info) = map{}Añade una función getter para obtener la ronda actual de la variable `weak_map` de la sesión.
VerseGetRound<public>()<decides><transacts>:int= RoundInfo[GetSession()].CurrentRoundAñade una función para obtener la ronda actual y almacenarla en la variable `weak_map` de la sesión.
VerseRecordCurrentRound<public>(Players:[]player, TotalRounds:int):void= var CurrentRoundInfo:round_info = if: Info := RoundInfo[GetSession()] then: Info else: LastCompletedRound := GetLastCompletedRound(Players, TotalRounds) round_info: CurrentRound := LastCompletedRound + 1Actualiza tu dispositivo de Verse para utilizar la nueva función
RecordCurrentRoundy llama aGetRoundcuando necesites saber de qué ronda se trata.Verse# A Verse-authored creative device that can be placed in a level test_round_info_device := class(creative_device): # The total number of rounds in the race. @editable TotalRounds:type {Rounds:int where 1 <= Rounds} = 3 # Runs when the device is started in a running game OnBegin<override>()<suspends>:void= GetPlayspace().PlayerRemovedEvent().Subscribe(OnPlayerRemoved)
Ahora que esta información se almacena en una variable `weak_map` de sesión, puedes añadir fácilmente lógica personalizada para las rondas. Por ejemplo, puedes comprobar si es la primera ronda y configurar una sala y un área de visualización de la clasificación para los jugadores.
# Returns true if this is the first round of the game.
IsFirstRound<public>(RoundToCheck:int)<decides><transacts>:void=
RoundToCheck <= 0Por tu cuenta
Consulta Juego de carreras con persistencia de Verse para saber cómo utilizar este código en un juego de carreras para determinar el orden de salida de los jugadores.
Después de comprobar la plantilla, prueba lo siguiente:
Añade información adicional de la ronda, por ejemplo, qué vehículo se asigna al jugador.
Teletransporta a los jugadores a diferentes zonas del mapa al principio de cada ronda.
¿Qué otros juegos se te ocurren que utilicen una lógica específica para cada ronda?
Código completo
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# A persistable map that maps each player to
# what order they finished the previous round.
var CircuitInfo<public>:weak_map(player, player_circuit_info) = map{}
# Maps the current session to its associated round info.
var RoundInfo:weak_map(session, round_info) = map{}