J'essaie d'écrire un court "jeu" où un joueur fait le tour et combat des monstres mais je n'ai aucune idée de comment gérer le combat.
Par exemple, disons que j'ai un "guerrier" et un "troll". Comment les deux se combattent-ils? Je sais que je peux faire quelque chose comme
Conan = Warrior.new();
CaveTroll = Troll.new();
Conan.attack(CaveTroll);
CaveTroll.attack(Conan);
Mais quelle partie du jeu contrôle le monstre? Dois-je simplement coller la séquence ci-dessus en boucle jusqu'à ce que l'un d'eux meure? Ou le "moteur" du jeu doit-il avoir une partie qui traite spécifiquement du combat? Ou est-ce un aspect de l'intelligence artificielle du Troll qui doit prendre soin de ses actions?
De plus, qui / quoi détermine les actions que le monstre entreprend? Peut-être qu'un troll peut frapper, donner des coups de pied, mordre, lancer des sorts, boire des potions, utiliser un objet magique. Le moteur de jeu détermine-t-il quelle action le Troll prend ou est-ce quelque chose que la classe Troll gère?
Désolé, je ne peux pas être plus précis, mais j'ai besoin de conseils sur la direction à suivre.
Réponses:
J'imagine une séquence de bataille comme un mini-jeu dans votre jeu. Les ticks de mise à jour (ou turn ticks) sont dirigés vers un composant gérant ces événements. Cette approche encapsule la logique de séquence de bataille dans une classe distincte, laissant votre boucle de jeu principale libre pour la transition entre les états de jeu.
La classe de séquence de bataille ressemblerait à ceci:
Votre Troll et votre Guerrier héritent tous deux d'une superclasse commune appelée Entité. Dans HandleTurn, l'entité attaquante est autorisée à se déplacer. Cela équivaut à une routine de réflexion sur l'IA.
La méthode de combat décide de ce que l'entité va faire. Notez que cela n'a pas besoin d'impliquer l'entité adverse, comme boire une potion ou s'enfuir.
Mise à jour: pour prendre en charge plusieurs monstres et un groupe de joueurs, vous introduisez une classe de groupe:
La classe de groupe remplacera toutes les occurrences d'entité dans la classe BattleSequence. La sélection et l'attaque seront gérées par la classe Entity elle-même, afin que l'IA puisse prendre en compte l'ensemble du groupe lors de la sélection de la meilleure ligne de conduite.
la source
J'aurais un objet Combat dédié qui gère le combat. Il encapsulerait l'état de combat complet, y compris des éléments tels que la liste des personnages joueurs, la liste des ennemis, le tour en cours, le champ de bataille, etc. Le combat peut alors avoir une méthode de mise à jour qui gère la logique de combat. Ce n'est pas une bonne idée de simplement mettre le code de combat dans une boucle simple, car cela se terminerait très rapidement. Normalement, vous auriez un timing et différentes étapes de bataille.
Pour les actions entreprises, vous pouvez certainement le rendre aléatoire, mais cela n'aurait aucun sens pour un monstre avec des HP complets de lancer un sort de guérison. Il est utile d'avoir une logique de base pour déterminer quelle action entreprendre. Par exemple, certaines actions pourraient avoir plus de priorité que d'autres (par exemple, les trolls donnent un coup de pied 30% du temps), ainsi que d'autres conditions pour rendre les batailles plus intéressantes (par exemple, lorsque les HP trolls sont inférieurs à 10% des HP complets, il y a 20% chance de lancer un sort de soin, sinon la chance est de 1%). Cela pourrait être aussi complexe que vous le souhaitez.
Je pense que la classe de monstre devrait gérer la sélection de l'action à effectuer, l'objet de bataille demande au monstre une action et le monstre fait un choix puis procède à l'appliquer. Une idée est d'avoir un objet de stratégie que vous connectez aux monstres et qui sélectionne dans la liste des actions de monstres possibles en fonction des priorités, des catégories et des conditions assignées à chaque action de combat. Ensuite, vous pouvez avoir une classe OffensiveStrategy par exemple qui priorise les attaques sur les compétences défensives, et une autre CautiousStrategy qui est plus susceptible de guérir. Un boss peut être en mesure de changer dynamiquement sa stratégie en fonction de son état actuel.
Une dernière chose. Vous voudrez peut-être que les personnages joueurs et les monstres héritent de la même classe, être des instances de la même classe (acteur ou combattant par exemple), ou partager un objet commun qui encapsule la fonctionnalité commune. Cela réduit la duplication de code et cela vous permettrait également d'avoir des PNJ contrôlés par l'IA de votre côté qui peuvent mettre en œuvre les mêmes stratégies que vous avez déjà codées pour les monstres.
la source
Oui, vous devez avoir une partie spéciale dans votre moteur qui gère le combat.
Je ne sais pas exactement comment vous faites votre combat, mais je suppose que les joueurs errent dans le monde du jeu, rencontrent des monstres et la bataille se déroule en temps réel. Si c'est le cas, le troll a besoin de connaître les environs dans une certaine zone, peut-être de définir dans quelle mesure le troll peut voir quelque chose en face (le troll gère cela).
À propos de l'IA, je pense que le moteur doit le gérer lui-même, alors disons que vous avez plus d'un type d'ennemi qui peut faire la même chose (mordre), vous pouvez simplement assigner l'IA à un autre monstre et c'est parti!
la source
Votre joueur et votre troll ne sont que des ensembles de données, ce que nous appelons le modèle de données qui décrit votre monde. La vie, l'inventaire, les capacités d'attaque, leur connaissance du monde même - tout se compose du modèle de données.
Conservez un seul objet Model principal contenant toutes les données décrivant votre monde. Il contiendra des informations générales sur le monde telles que la difficulté, les paramètres physiques, etc. Il contiendra également une liste / tableau de données d' entités spécifiques comme je l'ai décrit ci-dessus. Ce modèle principal peut se composer de nombreux sous-objets afin de décrire votre monde. Nulle part dans votre modèle vous ne devriez avoir de fonctions qui contrôlent la logique du jeu ou la logique d'affichage; les getters sont la seule exception, et ne seraient utilisés que pour vous permettre d'obtenir plus facilement les données du modèle (si les membres du public ne font pas déjà l'affaire).
Ensuite, créez des fonctions dans une ou plusieurs classes "contrôleur"; vous pouvez tous les écrire en tant que fonctions d'assistance dans votre classe principale, bien que cela puisse devenir un peu volumineux après un certain temps. Ceux-ci seront appelés à chaque mise à jour pour agir sur les données des entités à différentes fins (mouvement, attaque, etc.). Garder ces fonctions en dehors d'une classe d'entité est plus efficace en termes de ressources, et une fois que vous saurez ce qui décrit votre entité, vous saurez automatiquement quelles fonctions doivent agir sur elle.
Une note finale est qu'il est également utile de séparer votre logique d'affichage de votre logique de jeu. La logique d'affichage serait: "Où puis-je dessiner cela à l'écran et dans quelle couleur?" contre la logique du jeu étant ce que j'ai décrit dans le pseudcode ci-dessus.
(Note du développeur: lors de l'utilisation des classes, cela suit une approche de programmation fonctionnelle qui considère toutes les méthodes comme étant idéalement sans état, permettant un modèle de données et une approche de traitement propres qui minimisent les bogues causés par l'état conservé. FP est le MVC ultime, car il atteint les MVC objectif de séparation explicite des préoccupations. Voir cette question .)
la source