Pour réaliser l'effet visuel de clignotement sur les infiltrés, vous allez masquer et afficher à plusieurs reprises le personnage de chaque joueur. Vous voulez que cela se produise dans une fonction chaque fois qu'un infiltré subit des dégâts, mais vous devez également vous assurer que le reste de votre code continue de s'exécuter lorsque cette fonction est appelée. Cela devient encore plus compliqué pour les situations où vous avez plusieurs infiltrés. Il est possible que plusieurs infiltrés subissent des dégâts en même temps pendant une partie ; vous avez donc besoin d'un code capable de les gérer individuellement.
Pour réaliser ceci, vous allez faire un usage intensif de l'expression spawn. Générer une fonction vous permet de l'exécuter de manière asynchrone, sans mettre le reste de votre code en attente. En créant une fonction pour chaque infiltré, vous pouvez vous assurer que le clignotement de chaque infiltré se produit indépendamment des autres.
Procédez comme suit pour apprendre à faire vaciller le personnage de chaque infiltré lorsqu'il est blessé.
Créer la boucle de vacillement
- Ajoutez une nouvelle fonction
FlickerCharacter()à la définition de classeinvisibility_manager. Cette fonction prend unfort_characteret fait scintiller son personnage en le rendant visible puis invisible. Ajoutez le spécificateur<suspends>à cette fonction pour lui permettre de s'exécuter de manière asynchrone.# Fait clignoter les agents en masquant et montrant son fort_character à répétition FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("FlickerCharacter() appelé) - Dans
FlickerCharacter(), créez une boucleHide()sur leInCharacter, assortie d'une pause avecSleep()(d'une durée deFlickerRateSecondsdéfinie par vous antérieurement), suivie de l'affichage du personnage avecShow()et d'une nouvelle pause. Cela crée un effet de scintillement sur le personnage qui permet aux joueurs ennemis de le suivre, mais avec une certaine difficulté à viser en raison des courtes périodes d'invisibilité.# Fait clignoter les agents en masquant et montrant son fort_character à répétition FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("FlickerCharacter() appelé) # Masquer puis afficher en boucle le personnage pour créer un effet de scintillement. loop: InCharacter.Hide() Sleep(FlickerRateSeconds) InCharacter.Show() Sleep(FlickerRateSeconds)Sortir de la boucle
Vous avez besoin d'un moyen de sortir de cette fonction de boucle lorsque le personnage doit cesser de clignoter. La carte
PlayerVisibilitySecondsque vous avez créée précédemment suit la durée pendant laquelle un joueur peut clignoter, il vous faudra donc réduire cette durée à chaque boucle. Lorsque le temps restant atteint 0, le joueur doit cesser de clignoter et vous pouvez sortir de la boucle.
1. Obtenez la durée restante de scintillement d'un joueur en accédant au mappage PlayerVisibilitySeconds en utilisant InCharacter.GetAgent[] comme clé et stockez-la dans une variable TimeRemaining. Vous pouvez définir la durée restante dans le mappage dans la même expression, en diminuant la valeur de FlickerRateSeconds * 2. De cette façon, TimeRemaining devient la valeur de PlayerVisibilitySeconds après la résolution de l'expression set. Notez que FlickerRateSeconds doit être multiplié par 2 puisque vous appelez Sleep() deux fois par boucle.
# Fait clignoter les agents en masquant et montrant son fort_character à répétition
FlickerCharacter(InCharacter:fort_character)<suspends>:void=
Logger.Print("FlickerCharacter() appelé)
# Masquer puis afficher en boucle le personnage pour créer un effet de scintillement.
loop:
InCharacter.Hide()
Sleep(FlickerRateSeconds)
InCharacter.Show()
Sleep(FlickerRateSeconds)
# À chaque boucle, réduisez la durée pendant laquelle le personnage scintille à l’aide de FlickerRateSeconds.
# Si le temps restant atteint 0, interrompez la boucle.
if:
TimeRemaining := set PlayerVisibilitySeconds[InCharacter.GetAgent[]] -= FlickerRateSeconds * 2
- Vérifiez si
TimeRemainingest inférieur ou égal à 0, ce qui indique que le personnage doit arrêter de scintiller. Pour cela, appelezHide()sur le personnage pour le rendre à nouveau invisible, et sortez de la boucle à l'aide debreak. Votre fonctionFlickerCharacter()devrait être similaire à ce qui suit :# Fait clignoter les agents en masquant et montrant son fort_character à répétition FlickerCharacter(InCharacter:fort_character)<suspends>:void= Logger.Print("FlickerCharacter() appelé) # Masquer puis afficher en boucle le personnage pour créer un effet de scintillement. loop: InCharacter.Hide() Sleep(FlickerRateSeconds) InCharacter.Show() Sleep(FlickerRateSeconds) # À chaque boucle, réduisez la durée pendant laquelle le personnage scintille à l’aide de FlickerRateSeconds. # Si le temps restant atteint 0, interrompez la boucle. if: TimeRemaining := set PlayerVisibilitySeconds[InCharacter.GetAgent[]] -= FlickerRateSeconds * 2 TimeRemaining <= 0.0 then: InCharacter.Hide() break
Démarrage et réinitialisation des vacillements
Considérez ce qui se passe lorsque qu'un infiltré est blessé alors qu'il est déjà en train de vaciller. Dans ce cas, l’apparition d’une autre fonction FlickerCharacter() pourrait rapidement devenir ingérable, car chaque instance ultérieure de dégâts engendre une autre fonction. Vous pourriez donc vous retrouver avec des dizaines de fonctions agissant sur le même personnage. Au lieu de cela, la valeur du joueur dans PlayerVisibilitySeconds doit être réinitialisée chaque fois qu'il est blessé. Pour ce faire, vous allez définir une fonction pour vérifier si un joueur est en train de vaciller. Si tel est le cas, réinitialisez la durée pendant laquelle ils doivent vaciller. Sinon, générez un nouvel événement de vacillement pour ce personnage.
- Ajoutez une nouvelle fonction d'aide
IsFlickering()à la définition de classeinvisibility_manager, que vous utiliserez pour déterminer si un joueur scintille. Cette fonction prend un agent comme argument et renvoietruesi sa valeur dansPlayerVisibilitySecondsest supérieure à0,0. Ajoutez les spécificateursdecidesettransactsà cette fonction à la fois pour la rendre faillible, mais aussi pour pouvoir l'annuler en cas d'échec.# Indique si le joueur va encore clignoter IsFlickering(InAgent:agent)<decides><transacts>:void= PlayerVisibilitySeconds[InAgent] > 0.0 - Ajoutez une nouvelle fonction
StartOrResetFlickering()à la définition de classe `invisibility_manager. Cette fonction prend un agent comme argument et détermine si un joueur doit commencer ou réinitialiser le scintillement.# Démarre un nouvel événement de clignotement si l'agent était invisible, sinon # réinitialise le clignotement en cours de l'agent. StartOrResetFlickering(InAgent:agent):void= - Dans
StartOrResetFlickering(), vérifiez si l’agent donné ne vacille pas. Si ce n’est pas le cas, vous devez lancer un nouvel événement de vacillement pour cet agent. Récupérezfort_characterde cet agent et enregistrez-le dans une variableFortCharacter.# Démarre un nouvel événement de clignotement si l'agent était invisible, sinon # réinitialise le clignotement en cours de l'agent. StartOrResetFlickering(InAgent:agent):void= if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Attempting to start NEW FlickerEvent for this character") - Définissez la valeur de l'agent dans
PlayerVisibilitySecondsàVulnerableSeconds, puisspawnune nouvelle fonctionFlickerCharacter()pour cet agent, en passant leurFortCharacter.if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Attempting to start NEW FlickerEvent for this character") # Début d'un nouveau scintillement if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): spawn{FlickerCharacter(FortCharacter)} Logger.Print("FlickerEvent généré pour ce personnage") - Si l'agent scintillait déjà, il vous suffit de réinitialiser sa valeur dans
PlayerVisibilitySecondsàVulnerableSeconds. N'oubliez pas que la fonctionFlickerCharacter()précédente lit cette valeur de manière asynchrone, de sorte que si la valeur est réinitialisée pendant queFlickerCharacter()est exécuté en boucle, la boucle se poursuit sans arrêt. Votre fonctionStartOrResetFlickering()devrait être similaire à ce qui suit :# Démarre un nouvel événement de clignotement si l'agent était invisible, sinon # réinitialise le clignotement en cours de l'agent. StartOrResetFlickering(InAgent:agent):void= if (not IsFlickering[InAgent], FortCharacter := InAgent.GetFortCharacter[]): Logger.Print("Attempting to start NEW FlickerEvent for this character") # Début d'un nouveau scintillement if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): spawn{FlickerCharacter(FortCharacter)} Logger.Print("FlickerEvent généré pour ce personnage") else: # Réinitialiser les scintillements en cours if (set PlayerVisibilitySeconds[InAgent] = VulnerableSeconds): Logger.Print("Reset character's FlickerTimer to VulnerableSeconds")
Vacillement des infiltrés lorsqu’ils sont blessés
Pour relier toutes ces fonctions ensemble, vous allez définir une fonction qui gère ce qui se passe lorsqu'un infiltré est blessé. Tout comme avec FlickerCharacter(), vous devez suivre chaque infiltré individuellement afin de déterminer s'ils ont été endommagés. Pour cela, la fonction doit être asynchrone afin que vous puissiez en générer une pour chaque infiltré.
- Ajoutez une nouvelle fonction
OnInfiltratorDamaged()à la définition de classeinvisibility_manager. Cette fonction prend un agent et gère l'appel deStartOrResetFlickering()lorsque l'agent est endommagé. Ajoutez le spécificateur<suspends>à cette fonction pour lui permettre de s'exécuter de manière asynchrone.# Fait clignoter les agents toute fois qu'ils subissent des dégâts. OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Tentative de début de scintillement de ce personnage") - Récupérez la collection
fort_team_collectionpour l'espace de jeu actuel et enregistrez-la dans une variableTeamCollection. Récupérez ensuite lefort_characterde l'agent transmis à cette fonction.# Fait clignoter les agents toute fois qu'ils subissent des dégâts. OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Tentative de début de scintillement de ce personnage") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]): - Étant donné que cette fonction doit surveiller en permanence l'agent qui lui est transmis, elle doit effectuer une boucle. Cette boucle doit s'exécuter chaque fois que le personnage donné est blessé et appeler
StartOrResetFlickeringsur l'agent que la fonction surveille. Ajoutez une boucle àOnInfiltratorDamaged.# Fait clignoter les agents toute fois qu'ils subissent des dégâts. OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Tentative de début de scintillement de ce personnage") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]): loop: - À l'intérieur de la boucle, vérifiez si
IsVisibilitySharedest activé. Si tel est le cas, cela signifie que lorsqu'un infiltré est blessé, tous les infiltrés de l'équipe doivent commencer à scintiller. Si ce paramètre est activé, récupérez à la fois l'équipe de cet agent, mais aussi les joueurs de cette équipe via des appels àGetTeam[]etGetAgents[], respectivement.if (FortCharacter := InAgent.GetFortCharacter[]): loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): - Maintenant, dans une boucle
for, appelezStartOrResetFlickeringsur chaque coéquipier.if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Pour chaque coéquipier, configurez-les en PlayerVisibility secondes puis générez FlickerEvent for(Teammate:TeamAgents): Logger.Print("Calling StartOrResetFlickering on a Teammate") StartOrResetFlickering(Teammate) - Si la visibilité n'est pas partagée, appelez
StartOrResetFlickeringsur l'agent que cette fonction surveille.loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Pour chaque coéquipier, configurez-les en PlayerVisibility secondes puis générez FlickerEvent for(Teammate:TeamAgents): Logger.Print("Calling StartOrResetFlickering on a Teammate") StartOrResetFlickering(Teammate) else: # Faire scintiller simplement le personnage endommagé Logger.Print("Calling StartOrResetFlickering on InAgent") StartOrResetFlickering(InAgent) - Enfin, à la fin de la boucle,
Await()l'événementDamagedEvent()du personnage donné. De cette façon, la boucle n'est itérée que lorsqu'un personnage subit des dégâts. Notez que cette boucle s'exécutera au moins une fois au démarrage de la fonction, ce qui signifie au moins un appel àStartOrResetFlickering(). Pour cette raison, les infiltrés commencent le jeu en scintillant avant de devenir invisibles. Cela permet de rappeler aux infiltrés qu'ils sont invisibles, mais aussi que l'invisibilité n'est pas permanente. Votre fonctionOnInfiltratorDamaged()doit être similaire à ce qui suit :# Fait clignoter les agents toute fois qu'ils subissent des dégâts. OnInfiltratorDamaged(InAgent:agent)<suspends>:void= Logger.Print("Tentative de début de scintillement de ce personnage") TeamCollection := GetPlayspace().GetTeamCollection() if (FortCharacter := InAgent.GetFortCharacter[]): loop: if(IsVisibilityShared?, CurrentTeam := TeamCollection.GetTeam[InAgent], TeamAgents := TeamCollection.GetAgents[CurrentTeam]): # Pour chaque coéquipier, configurez-les en PlayerVisibility secondes puis générez FlickerEvent for(Teammate:TeamAgents): Logger.Print("Calling StartOrResetFlickering on a Teammate") StartOrResetFlickering(Teammate) else: # Faire scintiller simplement le personnage endommagé Logger.Print("Calling StartOrResetFlickering on InAgent") StartOrResetFlickering(InAgent) FortCharacter.DamagedEvent().Await()
Fonctions d'apparition pour les personnages au démarrage du jeu
De retour dans StartInvisibilityManager(), avant d'appeler Hide() sur le personnage d'un joueur, générez une fonction OnInfiltratorDamaged() pour ce Personnage. De cette façon, chaque Infiltrator dispose d'une fonction qui les surveille de manière asynchrone et gère toute la logique liée à leur scintillement. StartInvisibilityManager() devrait être similaire à ce qui suit :
StartInvisibilityManager<public>(AllTeams:[]team, AllPlayers:[]player, Infiltrators:team):void=
Logger.Print("Invisibility script started!")
set Teams = GetPlayspace().GetTeamCollection().GetTeams()
for(PlayerSpawner:PlayersSpawners):
PlayerSpawner.SpawnedEvent.Subscribe(OnPlayerSpawn)
Générez une fonction OnInfiltratorDamaged pour chaque joueur qui apparait dans l'équipe des
# infiltrés. Rendez ensuite leurs personnages invisibles.
for(TeamPlayer:AllPlayers):
if:
FortCharacter:fort_character = TeamPlayer.GetFortCharacter[]
CurrentTeam := GetPlayspace().GetTeamCollection().GetTeam[TeamPlayer]
Logger.Print("Got this player's current team")
Teams[0] = CurrentTeam
set PlayerVisibilitySeconds[TeamPlayer] = 0.0
Logger.Print("Added player to PlayerVisibilitySeconds")
then:
spawn{OnInfiltratorDamaged(TeamPlayer)}
Logger.Print("Player spawned as an infiltrator, making them invisible")
FortCharacter.Hide()
else:
Logger.Print("Ce joueur n’est pas un infiltré")
Enregistrez le script, développez-le, puis cliquez sur Lancer la session dans la barre d'outils de l'UEFN pour tester le niveau. Lorsque vous testez votre niveau, chaque infiltré doit vaciller lorsque le script démarre, puis doit devenir invisible. Lorsqu'ils sont blessés, ils doivent vaciller, soit individuellement soit en tant qu'équipe en fonction de ce que vous avez configuré avec IsVisibilityShared.

Étape suivante
Dans l'étape suivante de ce tutoriel, vous apprendrez à gérer les joueurs qui rejoignent une partie en cours.