Structure de l'unité de jeu RTS

18

Je veux un moyen de faire beaucoup d'unités différentes sans avoir à programmer plusieurs fois des actions comme moveTo et Attack

La façon dont je le vois, il y a 2 façons de le faire.

  1. Une seule classe Unit générique avec des indicateurs qui spécifie ce qu'elle peut / ne peut pas faire (puis créez des instances dans un tableau statique et récupérez-les si nécessaire)
  2. Classe d'unité abstraite avec des méthodes abstraites pour des actions spécifiques à l'unité comme (Attaque, Récolte, Patrouille), qui doivent ensuite toutes être implémentées dans les sous - classes , même si l'unité ne peut réellement rien récolter.

la première façon de le faire semble la plus simple, mais je finirais par avoir beaucoup de code inutilisé pour la majorité des unités.

la deuxième façon pourrait également fonctionner. Mais si je décide d'avoir deux unités différentes qui peuvent récolter des ressources, je vais avoir exactement le même code dans deux classes différentes, ce qui ne semble pas être la bonne façon de le faire.

Est-ce même la bonne approche à ce problème?
Dans un jeu comme AoE, chaque unité a, ce que je suppose, une sorte de liste d'actions / ordres, j'aimerais vraiment savoir comment réaliser quelque chose de similaire, où je peux simplement coder chaque action / ordre une fois, et donnez-le ensuite à toutes les unités qui ont besoin de cette action.

Si je ne suis pas clair (très plausible) ou si vous avez besoin de plus d'informations sur ce que je recherche exactement, demandez-le moi dans un commentaire.

Daniel Holst
la source

Réponses:

25

Une approche courante consiste à avoir une approche basée sur les composants dans laquelle la classe de base "Unit" implémente simplement les aspects les plus fondamentaux que toutes les unités ont en commun, tandis que chaque unité a alors une liste de plusieurs composants-objets qui disent ce qu'elle peut faire et comment ça marche.

Par exemple, un réservoir peut avoir les composants Mobile, Destructible, Attacker, un immobile que la tourelle Destructible, Attackeret une moissonneuse Mobile, Destructible, Harvester. Ces classes incluraient alors tout le code nécessaire pour implémenter ces comportements. Les interactions entre les composants (un Attackerne peut qu'endommager ce qui est Destructible) peuvent être mises en œuvre en faisant vérifier au composant si l'autre unité a le composant requis, puis interagir directement avec ce composant.

L'avantage par rapport à un héritage de classe classique est que vous pouvez facilement combiner des capacités. Par exemple, lorsque vous souhaitez avoir une moissonneuse qui peut également attaquer, transporter l'infanterie et voler, il vous suffit d'ajouter les composants nécessaires. Vous pouvez également facilement ajouter et supprimer de nouvelles fonctionnalités sous forme de nouveaux composants sans avoir à gonfler la classe Unit de base.

Unity vous prend en charge dans une telle architecture, car l'ensemble du moteur est déjà basé sur des composants. Ainsi, des composants logiques comme ceux-ci peuvent être ajoutés sous forme de scripts.

Philipp
la source
Donc, dans l'unité, est-ce que je désactiverais et activerais les composants selon les besoins?.
Daniel Holst
@DanielHolst Non, vous devez les ajouter et les supprimer au besoin. Vous pouvez le faire dans l'éditeur Unity ou avec des scripts à l'aide de gameObject.AddComponentet gameObject.RemoveComponent.
Philipp
ah d'accord, mais disons pour une action / commande "moveTo". comment l'unité pourrait-elle savoir quand la commande est effectuée?, et comment puis-je mettre les commandes en file d'attente?
Daniel Holst
2
@DanielHolst Je pense que vous avez mal compris quelque chose. Le Movingcomposant signifie "cette unité est généralement capable de se déplacer". Le composant y est fixé en permanence, que l'unité se déplace ou non. Cela ne signifie pas qu'il bouge en ce moment . Bien que vous puissiez également le faire de cette façon en y ajoutant un MoveOrdercomposant et en le faisant retirer de l'unité lorsque la commande est exécutée ou annulée.
Philipp
1
@DanielHolst Maintenant, vous dérivez dans la direction de l'unité AI, qui est une toute autre boîte de vers. Une approche possible serait d'avoir une bibliothèque de composants AIScript qui supposent que certains composants sont présents ou modifient leur comportement en fonction des composants de l'unité. Mais c'est vraiment un sujet beaucoup trop complexe pour être traité dans un commentaire.
Philipp
4

De nombreux jeux utilisent un système basé sur les composants pour les entités, c'est-à-dire qu'un tas de comportements et de capacités peuvent être ajoutés à un type d'unité plus générique plutôt que d'être codés dans le cadre de la classe de l'entité (ou équivalent).

Ross Taylor-Turner
la source
serait-ce extrêmement difficile à mettre en œuvre?
Daniel Holst
Des modèles comme celui-ci sont utilisés pour faciliter la mise en œuvre dans l'ensemble. Si vous ne pouvez pas décider de l'approche à adopter, c'est une bonne idée de commencer aussi simplement que possible et d'élargir votre choix tout en étant plus fonctionnel. Une fois que vous avez une meilleure idée du problème, vous pouvez soit refaçonner ou réécrire pour une approche qui correspond mieux à votre situation.
Ross Taylor-Turner
1
@DanielHolst Je remarque que votre question a le Unitydrapeau. Unity possède déjà un système de composants intégré et privilégie fortement la composition plutôt que l'héritage . Une méthode simple consiste à créer un MonoBehaviourpour chacun de vos types d'action, puis à attacher à chaque type d'unité préfabriqué les actions qu'il peut effectuer (personnalisation des instances d'action avec des détails par type comme les valeurs des dommages et les coûts). Cela permet à votre unité de créer des données basées sur les données, de sorte que vous pouvez facilement créer de nombreux types d'unités personnalisés.
DMGregory
@DanielHolst Cela dépend de votre définition de "extrêmement difficile". Ma réponse va plus en détail sur la façon dont cela pourrait être mis en œuvre.
Philipp