La mise en œuvre de modèles de conception de programmation de jeux communs dans votre projet Unity peut vous aider à construire et à maintenir efficacement une base de code propre, organisée et lisible. Les modèles de conception réduisent le temps de refactoring et de test, accélérant les processus de développement et contribuant à une base solide pour faire croître votre jeu, votre équipe et votre entreprise.
Pensez aux modèles de conception non pas comme des solutions finies que vous pouvez copier et coller dans votre code, mais comme des outils supplémentaires qui peuvent vous aider à construire des applications plus grandes et évolutives.
Cette page explique le modèle de conception de commande.
Le contenu ici est basé sur le livre électronique gratuit, Niveau supérieur de votre code avec des modèles de programmation de jeux.
Découvrez d'autres articles de la série sur les modèles de conception de programmation de jeux Unity sur le hub des meilleures pratiques Unity ou via ces liens :
Le modèle de conception de programmation de commande est l'un des modèles originaux du Gang of Four et est utile chaque fois que vous souhaitez suivre une série spécifique d'actions. Vous avez probablement vu le modèle de commande à l'œuvre si vous avez joué à un jeu qui utilise la fonctionnalité annuler/rétablir ou qui garde l'historique de vos saisies dans une liste. Imaginez un jeu de stratégie où l'utilisateur peut planifier plusieurs tours avant de les exécuter réellement. C'est le modèle de commande.
Le modèle de commande permet de représenter les actions sous forme d'objets. Encapsuler des actions en tant qu'objets vous permet de créer un système flexible et extensible pour contrôler le comportement des GameObjects en réponse aux entrées de l'utilisateur. Cela fonctionne en encapsulant un ou plusieurs appels de méthode en tant qu'objet de commande plutôt qu'en invoquant une méthode directement. Ensuite, vous pouvez stocker ces objets de commande dans une collection, comme une file d'attente ou une pile, qui fonctionne comme un petit tampon.
Stocker des objets de commande de cette manière vous permet de contrôler le timing de leur exécution en retardant potentiellement une série d'actions pour une lecture ultérieure. De même, vous pouvez les refaire ou les annuler et ajouter une flexibilité supplémentaire pour contrôler l'exécution de chaque objet de commande.
Voici quelques applications courantes du modèle dans différents genres de jeux :
- Dans un jeu de stratégie en temps réel, le modèle de commande pourrait être utilisé pour mettre en file d'attente les actions des unités et des bâtiments. Le jeu exécuterait ensuite chaque commande à mesure que les ressources deviennent disponibles.
- Dans un jeu de stratégie au tour par tour, le joueur pouvait sélectionner une unité puis stocker ses mouvements ou actions dans une file d'attente ou une autre collection. À la fin du tour, le jeu exécuterait toutes les commandes dans la file d'attente du joueur.
- Dans un jeu de puzzle, le modèle de commande pourrait permettre au joueur d'annuler et de rétablir des actions.
- Dans un jeu de combat, lire les pressions de boutons ou les mouvements de manette dans une liste de commandes spécifique pourrait aboutir à des combos et des mouvements spéciaux.
Essayez le projet d'exemple sur GitHub qui démontre différents modèles de conception de programmation dans le contexte du développement de jeux, y compris le modèle de commande.
Dans cet échantillon, le joueur peut se déplacer dans un labyrinthe en cliquant sur les boutons sur le côté gauche. Alors que votre joueur se déplace, vous pouvez voir une traînée de mouvement. Mais plus important encore, vous pouvez annuler et rétablir vos actions précédentes.
Pour trouver la scène correspondante dans le projet, allez dans le dossier nommé "9 Commande."
Pour mettre en œuvre le modèle de commande, vous aurez besoin d'un objet général qui contiendra votre action. Cet objet de commande contiendra la logique à exécuter et comment l'annuler.
Il existe plusieurs façons de mettre cela en œuvre, mais voici une version simple utilisant une interface appelée ICommand :
interface publique ICommand
{
void Exécuter();
void Annuler();
}
Dans ce cas, chaque action de jeu appliquera l'interface ICommand (vous pourriez également implémenter cela avec une classe abstraite).
Chaque objet de commande sera responsable de ses propres Exécuter et Annuler méthodes. Donc, ajouter plus de commandes à votre jeu n'affectera aucune des commandes existantes.
La CommandInvoker classe est alors responsable de l'exécution et de l'annulation des commandes. En plus des ExecuteCommand et UndoCommand méthodes, il dispose d'une pile d'annulation pour contenir la séquence des objets de commande.
Dans le projet d'exemple, vous pouvez déplacer votre joueur dans un petit labyrinthe. Une option simple pour déplacer la position du joueur est de créer un PlayerMover.
Pour ce faire, vous devrez passer un Vector3 dans la méthode Move pour guider le joueur le long des quatre directions de la boussole. Vous pouvez également utiliser un raycast pour détecter les murs dans le LayerMask approprié. Bien sûr, la mise en œuvre de ce que vous souhaitez appliquer au modèle de commande est distincte du modèle lui-même.
Pour suivre le modèle de commande, capturez la méthode PlayerMover’s Move en tant qu'objet. Au lieu d'appeler Move directement, créez une nouvelle classe, MoveCommand, qui implémente l'interface ICommand.
commande publique de déplacement : ICommand
{
DéplacerJoueur playerMover;
Mouvement Vector3;
commande de déplacement(JoueurDéplaceur joueur, Vecteur3 vecteurDeDéplacement)
{
ce.joueurDeplacement = joueur;
ce.mouvement = moveVector;
}
public void Exécuter()
{
joueurDéplacer.Déplacer(mouvement);
}
public void Annuler()
{
joueurDéplacer.Déplacer(-mouvement);
}
}
Quelle que soit la logique que vous souhaitez accomplir, cela va ici, alors invoquez Move avec le vecteur de mouvement.
ICommand a également besoin d'une Undo méthode pour restaurer la scène à son état précédent. Dans ce cas, la Annuler logique soustrait le vecteur de mouvement, poussant essentiellement le joueur dans la direction opposée.
La MoveCommand stocke tous les paramètres dont elle a besoin pour s'exécuter. Configurez-les avec un constructeur. Dans ce cas, vous enregistrez le composant approprié PlayerMover et le vecteur de mouvement.
Une fois que vous avez créé l'objet de commande et enregistré ses paramètres nécessaires, utilisez les méthodes statiques CommandInvoker’s ExecuteCommand et UndoCommand pour passer votre MoveCommand. Cela exécute la CommandeDéplacer Exécuter ou Annuler et suit l'objet de commande dans la pile d'annulation.
Le InputManager n'appelle pas directement la méthode Move du PlayerMover. Au lieu de cela, ajoutez une méthode supplémentaire, RunMoveCommand, pour créer une nouvelle MoveCommand et l'envoyer au CommandInvoker.
Ensuite, configurez les différents événements onClick des boutons de l'interface utilisateur pour appeler RunPlayerCommand avec les quatre vecteurs de mouvement.
Consultez le projet d'exemple pour les détails d'implémentation du InputManager. Vous pouvez également configurer votre propre entrée en utilisant le clavier ou la manette de jeu. Votre joueur peut maintenant naviguer dans le labyrinthe. Cliquez sur le bouton Annuler pour revenir au carré de départ.
La mise en œuvre de la rejouabilité ou de l'annulation est aussi simple que de générer une collection d'objets de commande. Vous pouvez également utiliser le tampon de commande pour rejouer des actions en séquence avec des contrôles spécifiques.
Par exemple, pensez à un jeu de combat où une série de clics de boutons spécifiques déclenche un mouvement ou une attaque combinée. Stocker les actions des joueurs avec le modèle de commande rend la configuration de ces combos beaucoup plus simple.
D'un autre côté, le modèle de commande introduit plus de structure, tout comme les autres modèles de conception. Vous devrez décider où ces classes et interfaces supplémentaires apportent suffisamment d'avantages pour déployer des objets de commande dans votre application.
Une fois que vous avez appris les bases, vous pouvez affecter le timing des commandes et les lire en succession ou à l'envers, selon le contexte.
Considérez ce qui suit lors de l'incorporation du modèle de commande :
- Créer plus de commandes: Le projet d'exemple n'inclut qu'un seul type d'objet de commande, le MoveCommand. Vous pouvez créer un nombre quelconque d'objets de commande qui implémentent ICommand et les suivre en utilisant le CommandInvoker.
- Ajouter la fonctionnalité de refaire est une question d'ajouter une autre pile : Lorsque vous annulez un objet de commande, poussez-le sur une pile séparée qui suit les opérations de rétablissement. De cette façon, vous pouvez rapidement parcourir l'historique des annulations ou refaire ces actions. Videz la pile de rétablissement lorsque l'utilisateur invoque un mouvement entièrement nouveau (vous pouvez trouver une implémentation dans le projet d'exemple).
- Utilisez une collection différente pour votre tampon d'objets de commande : Une file d'attente pourrait être plus pratique si vous souhaitez un comportement de premier entré, premier sorti (FIFO). Si vous utilisez une liste, suivez l'index actif actuel ; les commandes avant l'index actif sont annulables. Les commandes après l'index sont réitérables.
- Limiter la taille des piles : Les opérations d'annulation et de rétablissement peuvent rapidement devenir incontrôlables. Limitez les piles au nombre minimum de commandes.
- Passer tous les paramètres nécessaires dans le constructeur: Cela aide à encapsuler la logique comme on le voit dans l'exemple MoveCommand.
- Le CommandInvoker, comme d'autres objets externes, ne voit pas le fonctionnement interne de l'objet de commande, se contentant d'invoquer Exécuter ou Annuler. Donnez à l'objet de commande toutes les données nécessaires pour fonctionner lors de l'appel du constructeur.
Découvrez plus de conseils sur l'utilisation des modèles de conception dans vos applications Unity, ainsi que les principes SOLID, dans le livre électronique gratuit Améliorez votre code avec des modèles de programmation de jeux.
Vous pouvez trouver tous les e-books et articles techniques avancés sur Unity dans le hub meilleures pratiques. Les e-books sont également disponibles sur la page meilleures pratiques avancées dans la documentation.