En los juegos de carreras, es habitual que los jugadores tengan una posición de salida diferente según su desempeño en una ronda anterior. Esto anima a los jugadores a terminar la carrera rápidamente incluso cuando no están en primera posición, de modo que empiezan 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 de mapa débil de sesión en Verse restablece sus datos cada ronda, por lo que esta información de ronda tiene que almacenarse con cada jugador, mediante una variable de mapa débil de jugador, y restablecerse después de que el juego termine.
Actualmente, un proyecto solo puede tener hasta dos variables de mapa débil de jugador. Si tu proyecto ya tiene una variable de mapa débil de jugador, es una buena idea 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 se encuentran los jugadores para aplicar la lógica específica de la ronda y restablecer la información de la ronda en 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 de mapa débil de jugador que tenga al menos la siguiente información:
Terminar pedido
Última ronda completada
En las siguientes secciones, aprenderás a configurar estos datos y la lógica de las rondas. Puedes encontrar el código completo al final de la página.
Registrar última ronda completada
Sigue estos pasos para configurar los datos persistentes de cada jugador y registrar la última ronda completada.
Crea una clase persistente llamada
player_circuit_infopara almacenar la información del jugador en todas 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, para que sepas cuándo estos campos realmente contienen 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 de mapa débil de jugador usando la clase
player_circuit_infopara que persista 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 persistentes, crea un constructor para la clase persistente a fin de poder actualizar la información de cada jugador con facilidad. Para obtener más detalles, consulta Cómo usar 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 definiste las estructuras para estos datos, agrega una función para registrar el orden de llegada de un jugador y actualizar sus datos persistentes. Esta función utiliza el constructor del 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 para 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 del juego comprobando qué jugadores tienen la última ronda registrada. Es necesario verificar todos los jugadores para tener en cuenta los jugadores que podrían haberse unido a la sesión en curso. La última variable de ronda completa se inicializa con
-1para representar datos no válidos. Si algún jugador tiene un valor superior a-1, significa que la ronda ya terminó.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 probar que el orden de finalización de rondas y jugadores funciona como se espera. Asegúrate de que tu proyecto esté configurado para rondas múltiples, configurando la propiedad TotalRounds en Ajustes de 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:
Restablecer la información de la ronda cuando el jugador se va
Los datos permanentes del jugador para la información de la ronda deben restablecerse cuando un jugador se va durante el juego. Puedes suscribirte al PlayerRemovedEvent del espacio de juego para saber cuándo abandonan.
Sigue estos pasos para restablecer la información de ronda cuando un jugador abandona:
Crea una función para restablecer los datos persistentes del jugador para la información de la ronda. Esto significa establecer los valores a
-1o lo que decidas para representar los datos no válidos para esos campos. Esta implementación determina qué datos deben restablecerse en caso de que añadas otra información posterior 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 llamada
OnPlayerRemovedpara restablecer la información de 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
OnPlayerRemovedpara que se active cuando un jugador abandone el juego, 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) + 1Realiza una prueba para verificar que un jugador que abandona el juego restablece su información.
Restablecer la información de la ronda al finalizar la partida
La función OnBegin para un dispositivo de Verse se ejecuta al comienzo de cada ronda. Este es un buen momento para determinar si un jugador tiene datos permanentes inesperados, como, por ejemplo, si su última ronda completada es la misma que el número total de rondas. Si es así, es necesario restablecer los datos del jugador. Actualmente no existe una API para conocer la cantidad total de rondas de una partida. En su lugar, tendrás que añadir una propiedad editable al dispositivo de Verse para el total de rondas en el código de Verse y asegurarte de que coincida con la propiedad TotalRounds en Ajustes de isla.
Sigue estos pasos para restablecer la información de rondas cuando el juego haya finalizado:
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 restringe 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 para
GetLastCompletedRoundpara restablecer los datos persistentes del jugador para 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, para restablecer la información de ronda del jugador si se encuentra 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)Prueba para verificar que la información de ronda del jugador se restablece incluso después de jugar y completar todas las rondas.
Cómo agregar lógica basada en la ronda actual
Ahora, puedes usar esta información para obtener una lógica personalizada según la ronda en la que se encuentren los jugadores. Por ejemplo, podrías mostrar una tabla de clasificación local para la primera ronda de una partida.
No es lo ideal llamar a GetLastCompletedRound() cada vez que necesites saber qué ronda se está jugando. En cambio, puedes hacer esto una vez por ronda y registrar la información en una variable de mapa débil de sesión para que todo el código Verse en el proyecto acceda a este valor en cualquier momento sin la necesidad de recalcularlo cada vez.
Este es un gran ejemplo para mostrar las diferencias y el razonamiento entre usar la variable de mapa débil de sesión y la variable de mapa débil de jugador en tu código:
Las variables de mapa de baja sesión son útiles para los singletons y para almacenar datos de la ronda actual que no deseas recalcular cada vez.
Las variables de mapa de debilidad del jugador están diseñadas para la información que debe persistir en varias rondas y sesiones de juego, pero que debe asociarse con jugadores individuales.
Sigue estos pasos para configurar una variable de mapa débil de sesión a fin de almacenar la ronda actual.
Crea una clase para almacenar la información de la ronda. Al menos necesitas un campo para
RondaActual, pero podrías incluir otra información de la ronda que quieras guardar en todo el código de Verse, como las posiciones iniciales y los vehículos de los jugadores. IniciaCurrentRounda-1para representar los datos no válidos.Verseround_info := class: CurrentRound:int = -1Crea una variable de mapa de sesión débil con 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 de mapa débil de sesión.
VerseGetRound<public>()<decides><transacts>:int= RoundInfo[GetSession()].CurrentRoundAgrega una función para obtener la ronda actual y almacenarla en la variable del mapa débil de 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 Verse para usar la nueva función
RecordCurrentRoundy llamar 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 de mapa débil de sesión, puedes añadir con facilidad una lógica personalizada para las rondas. Por ejemplo, puedes comprobar si es la primera ronda además de configurar una sala y un área de visualización de la tabla de 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 Carrera de circuito de carreras con persistencia de Verse para saber cómo usar este código en un juego de carreras para determinar el orden de salida de los jugadores.
Después de consultar la plantilla, intenta 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 de 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{}