Le système de capacités du personnage est peut-être le plus exigeant de flexibilité du jeu. Il est impossible de prévoir au stade de la conception quels sorts apparaîtront dans la version finale ou dans les mises à jour ultérieures. Ce post portera sur la façon dont j'ai résumé le processus d'exécution des capacités.
La capacité elle-même n'est rien d'autre qu'un ensemble d'actions. L'interface minimale de la capacité se compose d'une méthode: «appliquer», mais pas si simple sur les difficultés sous la coupe.

Chaque capacité commence par une série de vérifications pour voir si elle peut être appliquée. Parmi eux, il y en a des ordinaires, comme vérifier la recharge, la disponibilité du mana, vérifier la distance et autres. Il est déjà évident ici que toutes les vérifications ne sont pas nécessaires pour toutes les capacités. Par exemple, il existe des capacités appliquées à n'importe quelle distance. Autrement dit, différentes capacités nécessitent différents ensembles de vérifications avant l'exécution. Cependant, il est clair que de nombreuses vérifications seront répétées, et souvent de nombreuses capacités nécessitent le même ensemble de vérifications.
Au total, une partie des contrôles sera répétée logiquement, ce qui signifie qu'ils doivent être modifiés comme convenu, c'est-à-dire immédiatement en tous lieux. De plus, les ensembles de parties des contrôles dans le cas général seront différents.
Si des parties de vérifications sont sélectionnées dans des objets distincts qui implémentent une interface et intégrées dans une liste liée individuellement, nous obtenons une chaîne de responsabilités de modèle.

Dans le cas d'une vérification réussie dans le lien, la vérification dans le lien suivant commencera, s'il n'y a pas de lien suivant, alors la vérification entière peut être considérée comme réussie. En plus de la vérification elle-même, le lien peut également contenir un gestionnaire d'erreurs. Par exemple, si lors de la vérification du mana, il s'est avéré que ce n'était pas suffisant, le lien peut en informer le joueur.
En utilisant la chaîne de fonctions, pour la capacité [Tir puissant], nous pouvons facilement insérer un lien supplémentaire qui vérifie si le personnage porte un arc ou un lien qui vérifie que le personnage a un niveau de santé inférieur à 30% pour la capacité [Second souffle].
Revenons en arrière et rappelons qu'il existe des chaînes de contrôles qui sont les mêmes pour de nombreuses capacités. Soulignons l'essence de la demande d'accomplissement de capacité et décrivons chacun des types de chaînes de test avec sa classe.
La demande n'est nécessaire que pour établir une chaîne de tâches, la lancer et l'annuler lorsque le joueur donne la commande appropriée.

Nous allons déjà créer des chaînes dans les implémentations de requêtes.
À l'heure actuelle, nous avons déjà appris à faire des tests flexibles de la capacité à exécuter des capacités. Maintenant, si le test réussit, vous devez toujours remplir la capacité.
J'ai préféré le faire sans changer les interfaces, en ajoutant le dernier lien toujours réussi que la capacité effectue comme effet secondaire. Voici un exemple d'implémentation de celui-ci:
public class TerminalChecker: ICastChecker { CastChecker next { get; set; } ISkill skill; public TerminalChecker(ISkill skill) { this.skill = skill; } public bool check() { skill.cast(); return true; } }
Cette implémentation nous permet de faire des requêtes asynchrones. Ceci est utile lorsque nous avons besoin d'informations supplémentaires de l'utilisateur. Par exemple, une capacité doit être appliquée à une zone que le joueur sélectionne avec la souris. Bien sûr, vous ne pouvez pas arrêter le jeu pour le moment.
Maintenant, nous devons faire correspondre les demandes avec les capacités. Nous le ferons, bien sûr, en utilisant le polymorphisme en ajoutant une propriété à l'interface de capacité. À ce stade, nous avons étendu la capacité de cette interface:

Après tout le travail effectué, réfléchissons à ce qu'est une capacité. Dans l'implémentation actuelle, il s'agit d'un ensemble d'actions précédé d'une série de vérifications. Notez qu'à un niveau élevé, nous ne sommes en aucun cas dépendants d'une logique de jeu spécifique. Avec l'idée initiale de décrire le système de capacités appliqué aux sorts, nous avons eu un système qui, selon certaines règles, nous donne ou ne permet pas d'effectuer des actions arbitraires.
En raison de cette propriété, ce système peut décrire toute modification du monde du jeu. Par exemple, une transaction de vente ou une équipe de construction de bâtiments.
Jetons un coup d'œil à tout en général

Dans cet exemple, une capacité Sprint est une capacité normale sans cible; la classe qui implémente la demande de telles capacités est NontargetCastRequest, qui à son tour forme une chaîne de vérifications de ManaChecker, CooldownChecker et TerminalChecker.
Le code d'appel ne dépend pas des détails de la mise en œuvre de ce système, c'est-à-dire que nous ne briserons pas la logique du jeu en ajoutant ou en modifiant la capacité.
C'est le système des capacités des personnages sous une forme minimale. Ce modèle n'a pas les moyens d'alerter le code appelant, de transférer des capacités à l'interface utilisateur et d'autres détails de la vie. Vous pouvez y penser vous-même.