Dans les jeux de course, il est fréquent que les joueurs aient une position de départ différente en fonction de leurs performances lors de la manche précédente. Cela encourage les joueurs à terminer la course rapidement, même s'ils ne sont pas en première position.
Pour ce faire, le jeu doit pouvoir identifier la manche dans laquelle se trouvent les joueurs, et l'ordre d'arrivée des coureurs doit persister dans toutes les manches, mais pas dans toutes les sessions de jeu. Une variable `weak_map` de session dans Verse réinitialise ses données à chaque manche, de sorte que ces informations de manches doivent être stockées avec chaque joueur en utilisant une variable `weak_map` de joueur, puis réinitialisées après la fin de la partie.
Actuellement, un projet ne peut disposer que de deux variables `weak_map` de joueur au maximum. Si votre projet dispose déjà d'une variable `weak_map` de joueur, faites en sorte que la deuxième enregistre les informations de manche afin de différencier les données devant persister de celles à réinitialiser après la fin de la partie ou lorsqu'un joueur quitte la session.
Il est par ailleurs important de savoir dans quelle manche les joueurs se trouvent actuellement afin d'appliquer la logique appropriée et de réinitialiser les informations de la dernière manche. Dans la mesure où il n'existe actuellement aucune API pour connaître la manche en cours, vous devez également enregistrer ces informations dans les données persistantes de chaque joueur.
En bref, vous devez disposer d'une variable `weak_map` de joueur qui contienne au moins les informations suivantes :
Ordre d'arrivée
Dernière manche terminée
Dans les sections suivantes, nous vous expliquons comment configurer ces données et la logique de manche. Le code complet se trouve en bas de page.
Enregistrer la dernière manche terminée
Procédez comme suit pour configurer les données persistantes de chaque joueur et enregistrer la dernière manche terminée.
Créez une classe persistable nommée
player_circuit_infopour stocker les informations des joueurs au cours des manches. Cette classe doit contenir les champs représentant le dernier ordre d'arrivée du joueur,LastRoundFinishOrder, et la dernière manche qu'il a terminée,LastCompletedRound. Ces champs sont initialisés avec-1pour représenter les valeurs non valides, afin que vous sachiez quand ces champs contiennent réellement des informations utiles.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 = -1Créez une variable `weak_map` de joueur en utilisant la classe
player_circuit_info, pour assurer la persistance des informations de manches de chaque joueur.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{}Il est recommandé de créer un constructeur pour la classe persistable afin de faciliter la mise à jour des informations de chaque joueur. Pour en savoir plus, consultez la rubrique Utiliser des constructeurs pour les mises à jour partielles.
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.LastCompletedRoundMaintenant que vous avez défini des structures pour ces données, ajoutez une fonction pour enregistrer l'ordre d'arrivée d'un joueur et mettre à jour ses données persistantes. Cette fonction utilise le constructeur créé à l'étape précédente pour mettre partiellement à jour les données relatives à l'unique information qui vous intéresse : l'ordre d'arrivée.
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{}Créez une autre fonction pour mettre à jour uniquement la dernière manche terminée du joueur.
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 := CompletedRoundMaintenant que vous pouvez enregistrer la dernière manche terminée du joueur, créez une fonction pour calculer la dernière manche terminée de la partie en identifiant les joueurs dont la dernière manche a été enregistrée. Vous devez vérifier tous les joueurs pour tenir compte de ceux susceptibles d'avoir rejoint la session en cours. La variable de dernière manche terminée est initialisée avec
-1, pour représenter les données non valides. Si l'un des joueurs se voit attribuer une valeur supérieure à-1, la manche est déjà terminée.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:Créez un appareil Verse pour vérifier que l'ordre d'arrivée des manches et des joueurs fonctionne comme prévu. Assurez-vous d'avoir configuré votre projet pour plusieurs manches, en définissant la propriété Manches totales dans Paramètres de l'île.
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:
Réinitialiser les informations de manches lorsqu'un joueur quitte le jeu
Il convient de réinitialiser les données persistantes du joueur relatives aux manches lorsqu'un joueur quitte le jeu en cours de partie. Vous pouvez vous abonner à l'événement PlayerRemovedEvent de l'espace de jeu pour savoir si un joueur quitte le jeu.
Procédez comme suit pour réinitialiser les informations relatives aux manches lorsqu'un joueur quitte le jeu :
Créez une fonction pour réinitialiser les données persistantes du joueur relatives aux informations de manches. Vous devez pour cela définir les valeurs sur
-1ou sur toute autre valeur que vous décidez d'attribuer aux données non valides de ces champs. Cette implémentation permet de déterminer les données devant être réinitialisées au cas où vous ajouteriez ultérieurement d'autres informations à la classe persistante qui ne doivent pas être réinitialisées ici.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 := -1Créez une fonction nommée
OnPlayerRemovedpour réinitialiser les informations de manches lorsqu'un joueur quitte le jeu.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")Configurez la fonction
OnPlayerRemovedde manière à l'appeler lorsqu'un joueur quitte le jeu, en vous abonnant à l'événementGetPlayspace().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) + 1Assurez-vous de la bonne réinitialisation des informations lorsqu'un joueur quitte le jeu.
Réinitialiser les informations de manches à la fin de la partie
La fonction OnBegin d'un appareil Verse s'exécute au début de chaque manche. C'est pour vous l'occasion de déterminer si les données persistantes d'un joueur sont incorrectes, par exemple si la dernière manche terminée est la même que le nombre total de manches. Si tel est le cas, vous devez réinitialiser les données du joueur. Il n'existe actuellement aucune API permettant de connaître le nombre total de manches d'une partie. Vous devez pour cela ajouter une propriété modifiable à l'appareil Verse pour obtenir le nombre total de manches dans le code Verse et vous assurer qu'elle correspond à la propriété Manches totales dans Paramètres de l'île.
Procédez comme suit pour réinitialiser les informations sur les manches une fois la partie terminée :
Ajoutez une propriété modifiable à votre appareil Verse pour connaître le nombre total de manches dans la partie. La propriété TotalRounds ne doit pas être inférieure ou égale à
0. Par conséquent, définissez des valeurs supérieures ou égales à1.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)Mettez à jour la fonction
GetLastCompletedRoundpour réinitialiser les données persistantes du joueur relatives à la dernière manche terminée si elles sont supérieures au nombre prévu de manches dans la partie.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.Mettez à jour l'appel à
GetLastCompletedRoundde manière à transmettre le nombre total de manches en tant qu'argument, pour réinitialiser les informations de manches des joueurs s'ils sont dans un état inattendu.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)Assurez-vous de la bonne réinitialisation des infos de manches des joueurs, même lorsqu'ils ont participé à toutes les manches et les ont toutes terminées.
Ajout d'une logique basée sur la manche actuelle
Vous pouvez maintenant utiliser ces informations pour créer une logique personnalisée en fonction de la manche dans laquelle se trouvent les joueurs. Par exemple, vous pouvez afficher un classement local pour la première manche d'une partie.
Il n'est pas recommandé d'appeler GetLastCompletedRound() à chaque fois que vous souhaitez connaître la manche en cours. Choisissez plutôt d'appeler `GetLastCompletedRound()` une fois par manche et d'enregistrer les informations associées dans une variable `weak_map` de session, de sorte que le code Verse du projet puisse accéder à cette valeur à tout moment sans avoir à la recalculer systématiquement.
Vous pourrez ainsi découvrir les différences entre la variable `weak_map` de session et la variable `weak_map` de joueur dans votre code :
Les variables `weak_map` de session sont utiles pour les singletons et le stockage de données de la manche en cours qu'il n'est pas souhaitable de recalculer systématiquement.
Les variables `weak_map` de joueur sont conçues pour les informations qui doivent persister d'une manche à l'autre et d'une session de jeu à une autre, mais qui doivent être associées à des joueurs distincts.
Procédez comme suit pour configurer une variable `weak_map` de session en vue d'enregistrer la manche en cours.
Créez une classe pour stocker les informations relatives à la manche. Vous devez disposer d'au moins un champ pour
CurrentRound, bien que vous puissiez inclure d'autres informations de manches en vue de les enregistrer dans votre code Verse, par exemple les positions de départ et les véhicules des joueurs. InitialisezCurrentRoundsur-1pour représenter les données non valides.Verseround_info := class: CurrentRound:int = -1Créez une variable `weak_map` de session en utilisant la classe
round_infopour stocker les infos de manches avec la session.Verse# Maps the current session to its associated round info. var RoundInfo:weak_map(session, round_info) = map{}Ajoutez une fonction getter pour obtenir la manche en cours à partir de la variable `weak_map` de session.
VerseGetRound<public>()<decides><transacts>:int= RoundInfo[GetSession()].CurrentRoundAjoutez une fonction pour obtenir la manche en cours et la stocker dans la variable `weak_map` de session.
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 + 1Modifiez votre appareil Verse de manière à utiliser la nouvelle fonction
RecordCurrentRoundet appelezGetRoundlorsque vous souhaitez connaître la manche en cours.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)
Maintenant que vous avez enregistré ces informations dans une variable `weak_map` de session, vous pouvez facilement ajouter une logique personnalisée pour les manches. Par exemple, vous pouvez vérifier s'il s'agit de la première manche, et configurer un salon et une zone d'affichage du classement pour les joueurs.
# Returns true if this is the first round of the game.
IsFirstRound<public>(RoundToCheck:int)<decides><transacts>:void=
RoundToCheck <= 0À vous de jouer
Consultez Circuit de course avec persistance Verse pour savoir comment utiliser ce code dans un jeu de course et déterminer l'ordre de départ des joueurs.
Après avoir consulté le modèle, essayez ce qui suit :
Ajoutez des informations de manche supplémentaires, comme le véhicule attribué au joueur.
Téléporter les joueurs vers différentes zones de la carte au début de chaque manche.
Selon vous, quels autres jeux utilisent une logique propre à la manche ?
Code complet
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{}