Lors du développement d'un jeu sur Unity, je suis tombé sur une tâche intéressante: comment créer un temps d'action extensible d'effets négatifs ou positifs sur un personnage.
En bref, j'ai un personnage auquel certains effets peuvent être appliqués, tels que l'affaiblissement, le gain, l'augmentation de la vitesse, la diminution de la vitesse et d'autres. Pour informer le joueur de l'effet d'un effet, le jeu fournit une ligne d'état.
Les premières versions de cette ligne contenaient des icônes sombres de tous les états et lorsque l'effet se produisait, la lumière souhaitée s'allumait.

Chaque statut avait de la corutine, ce qui annulait l'effet après un certain temps.
Il y a un inconvénient assez important dans cette décision. Si, à la suite de certains événements du jeu, le même effet est appliqué au personnage après un temps plus court que la durée de l'effet similaire précédent, il peut y avoir deux versions des événements.
- Tout à fait faux: une deuxième corutine est lancée en parallèle avec la première. Lorsque le premier est terminé, il revient à ses valeurs d'origine, c'est-à-dire que l'effet est supprimé avant que la deuxième coroutine ait terminé son travail.

- Également faux, mais dans certains cas acceptable: annulez la première coroutine et exécutez la seconde. Dans ce cas, la durée de l'effet sera égale à la durée du premier effet jusqu'à ce que la coroutine soit annulée + la durée de la deuxième coroutine.

Les deux méthodes sont inacceptables pour ma tâche, car je dois prolonger la durée de l'effet, de sorte que j'obtienne la somme de la durée de chaque effet, quel que soit le nombre de fois où l'effet est appliqué.
Si le personnage marche sur les pointes, sa jambe est conditionnellement endommagée et il ne peut pas continuer à se déplacer à la même vitesse. Disons que la vitesse diminue de 5 secondes. Si après 3 secondes le personnage marche sur d'autres pointes, alors la vitesse devrait être réduite de 5 secondes supplémentaires. Autrement dit, 3 secondes se sont écoulées, 2 + 5 secondes à gauche des nouvelles pointes. La durée de l'effet devrait durer encore 7 secondes à partir du moment de l'attaque sur les deuxièmes pointes (10 au total).
Et avec l'aide de la coroutine, je n'ai pas trouvé de solution au problème, car il est impossible de trouver le temps restant jusqu'à la fin de la coroutine pour l'ajouter à la nouvelle coroutine.
La solution que j'ai trouvée pour ce problème est d'utiliser un dictionnaire. Son avantage sur List est que le dictionnaire a une clé et une valeur, ce qui signifie que je peux accéder à n'importe quelle valeur par clé. De plus, cette solution vous permet de vous débarrasser des icônes de statut permanent dans la ligne et d'inclure celles nécessaires selon les besoins et de les placer dans les positions de la ligne dans l'ordre où elles se produisent.
Dictionary<string, float> statusTime = new Dictionary<string, float>();
Dans ce cas, le dictionnaire est plus avantageux que l'utilisation de la file d'attente, car la file d'attente fonctionne selon les principes du premier entré, premier sorti, mais la durée des effets est différente, ce qui signifie que le statut à supprimer peut ne pas être le premier de la file d'attente.
Pour cela, j'ai ajouté trois méthodes.
AddstatusAjoutez le statut souhaité au dictionnaire, si un tel statut existe déjà dans le dictionnaire, ajoutez la durée. S'il n'y a pas d'état, nous calculons l'heure de fin et l'ajoutons au dictionnaire.
private void AddStatus(string status, float duration) { if (statusTime.ContainsKey(status)) { statusTime[status] += duration; } else { float endTime = Time.timeSinceLevelLoad + duration; statusTime.Add(status, endTime); } }
RemoveStatusNous supprimons le statut du dictionnaire, restaurons les valeurs d'origine.
private void RemoveStatus(string status) { statusTime.Remove(status); RestoreStats(status); }
CheckstatusS'il existe des statuts dans le dictionnaire, nous vérifions si leur temps est écoulé.
S'il a expiré, supprimez le statut du dictionnaire. Étant donné que le changement de dictionnaire dans la boucle rend impossible la synchronisation des valeurs du dictionnaire, nous jetons les clés du dictionnaire ici dans une liste régulière.
private void CheckStatuses() { if (statusTime.Count > 0) { float currTime = Time.timeSinceLevelLoad; List<string> statuses = new List<string>(statusTime.Keys); foreach (string stat in statuses) { if (currTime > statusTime[stat]) { RemoveStatus(stat); } } } }
Des avantages, évidemment, c'est un temps d'effet extensible. Autrement dit, le problème est résolu.
Mais un inconvénient assez important est présent ici. La vérification des statuts se fait dans Mettre à jour chaque trame. Dans mon jeu, il y a un maximum de 4 joueurs, ce qui signifie que cette méthode sera exécutée 4 fois par trame en parallèle. Avec 4 caractères, je pense que ce n'est pas critique, mais je suis sûr qu'avec plus de caractères, cela peut entraîner des problèmes de performances. Il convient également de noter que la méthode est protégée en vérifiant la présence d'éléments dans le dictionnaire, et avec un dictionnaire vide, la charge doit être réduite.
En regardant vers l'avenir (qui est encore complètement brumeux pour ce jeu), je suis également confiant dans cette décision en mode en ligne, car une vérification des statuts des joueurs n'aura lieu que pour le joueur local actuel, et pas pour tous les joueurs instanciés.