Architecture de commande de la forteresse naine

21

Quelle est la manière la plus élégante d'implémenter un système de commande de commandes pour l'IA? par exemple dans une forteresse naine lorsque vous marquez une zone boisée pour la coupe de bois, les nains feraient alors la séquence suivante:

  1. Allez à l'arbre
  2. Hacher l'arbre
  3. Livrer du bois au stock
  4. Allez dans un autre arbre
  5. etc..

J'ai déjà une commande de pile qui fonctionne non. 1 qui passe de l'état inactif à la tuile de destination de l'arbre.

Ce dont j'ai peur, c'est de savoir comment cela pourrait devenir compliqué lorsque je crée plus de commandes comme celle-ci:

Construire une maison

  1. Aller au stock
  2. amener du bois dans la zone de construction
  3. retourner au stock
  4. Apportez de la pierre dans la zone de construction
  5. animer l'image-objet du bâtiment

Plantation

  1. Aller au stock
  2. apporter des semences à la parcelle agricole

Brassage

  1. Aller au stock
  2. Amener la plante à l'arrêt
  3. animer le sprite de brassage

Donc, ma question est, comment puis-je implémenter un système de commande de commande comme une forteresse naine et éviter le code spaghetti en même temps? y a-t-il des structures de données que je dois étudier? Dois-je placer la séquence de commandes sur un fichier xml distinct?

Jed T.
la source
1
La forteresse naine ne dispose pas d'un tel système. Les nains se voient assigner une tâche à la fois, et les nains inactifs chercheront quelque chose à faire. ("Hé, il y a un arbre marqué pour être coupé - je devrais le couper!" / "Hé, il y a du bois qui n'est pas en stock - je devrais en
apporter
1
Les nains ne sont rien assignés par le joueur, mais sont des tâches "assignées" par le système, qui est exactement l'architecture décrite par Jed T. ci-dessus. Créez un ordre et le système affecte des tâches de composants individuels afin de remplir cet ordre.
Attackfarm
2
Notez que cela s'appelle Allocation et Planification des Tâches, et est largement étudié dans plusieurs domaines d'ingénierie. Vous trouverez de nombreux articles sur ce problème, qui pourraient être intéressants.
TonioElGringo
@Attackfarm Le système ne décide pas à l'avance de toutes les tâches; il n'assigne pas non plus plusieurs tâches au même nain. Une tâche est initialement affectée et lorsqu'elle se termine, elle a pour conséquence de rendre une autre tâche disponible.
user253751
2
Cela ressemble à un excellent cas d'utilisation pour la planification d'actions orientées
problématique

Réponses:

27

Au début, vous voyez que vos commandes se présentent sous la forme d'une liste , donc votre premier instinct pourrait être de recréer cette structure, et chaque nain parcourra cette liste en séquence. Ce que je suggère cependant, c'est de diviser la liste en étapes , chaque étape ayant des conditions préalables , puis vous exécutez la commande entière à l'envers . Permettez-moi de démontrer avec un exemple:

Coupe de bois

  • Suis-je porteur de bois et en stock? Oui : déposez-le
  • Suis-je porteur de bois? Oui : aller à un stock
  • Suis-je à un arbre? Oui : hachez-le
  • Non à tous ci-dessus - : allez dans un arbre

Les avantages de ceci sont:

  • Très simple à mettre en œuvre
  • Flexible - vous pouvez librement décomposer cette liste, ajouter des éléments, supprimer des éléments, combiner des éléments
  • Aucun état - vous pouvez exécuter cette liste à partir du haut pour n'importe quel nain dans n'importe quel état, et le nain fera simplement la bonne chose TM

Désavantages:

  • Il est facile de rester coincé dans les boucles, car il n'y a pas d'état et pas de conscience d'être coincé

Logiquement, vous pouvez représenter ces commandes sous la forme d'un organigramme, qui est exécuté à partir du haut à chaque fois, et ce que vous faites dépend si vous répondez oui / non à chaque étape. Que vous implémentiez cela dans du code ou dans un fichier externe comme XML, c'est à vous.

congusbongus
la source
2
Cela a également l'avantage de laisser les commandes de remplacement de statut, ai-je faim? si oui, laissez tout tomber et réglez la tâche sur "manger", manger étant similaire au travail de transport du bois.
Ratchet Freak
7
@ratchetfreak "Je sais que la sécurité de ma forteresse dépend de ma lutte contre ce monstre pour qu'il n'attaque pas les civils, mais ça alors, mon estomac a juste grogné!" Essayez de ne pas trop ressembler à DF à cet égard: P
Colonel Thirty Two
Je pense que cela ressemble à ce qui est utilisé (ou du moins utilisé) qui a permis à l'artefact buggé de planepacked (cela était dû à un élément interdit, ce qui a provoqué ladite boucle)
Destrictor
3
@ColonelThirtyTwo Où est le dedans fun? ;)
Lasse
Je recommande fortement de ne pas utiliser la planification d'actions symboliques déclaratives pour cela. Il est fondamentalement impossible de déboguer et un comportement indésirable peut facilement survenir. Il est beaucoup plus facile de coder en dur les séquences d'actions pour chaque tâche de manière procédurale.
mklingen
10

Si vous pouvez faire des séquences assez générales, il n'y a pas beaucoup de code spaghetti.

En cas de livraison, par exemple: WorkTask fonctionne avec un WorkPlan. Le plan de travail indique quel type d'unité de ressources doit choisir, à partir de quel type de maison, en utilisant quelle animation de marche, en utilisant quelle animation de travail, le temps de travail et tous ces détails. Donc, à la fin, WorkTask pourrait ressembler à:

  1. Trouver% resource1% sur la carte
  2. Accédez à cet emplacement à l'aide de% animation_1%
  3. Travailler sur place en utilisant% animation_2% pendant% time%
  4. Prendre% req_resource1% dans% req_count1% count
  5. Accédez à% home% en utilisant% animation%
  6. Démarrez% animation_6% à l'intérieur pendant% time_2%
  7. etc..

Nous utilisons avec succès l'approche décrite. Nous avons ~ 15 tâches dans notre jeu. Quelques faits saillants:

  • Les tâches donnent des actions à l'unité (allez-y, entrez, sortez, allez ici, restez, travaillez, allez)
  • L'action se termine avec l'état Terminé ou Abandonné et le transmet à la tâche
  • Tout est codé en dur (pas besoin d'écrire l'analyseur, les méthodes d'interface, la compatibilité en arrière)
  • Chaque tâche implémente une classe de tâches abstraite avec seulement quelques méthodes courantes (créer, exécuter, enregistrer, charger)
  • Généralement, une tâche par module, mais des tâches similaires sont dans un module
  • Des tâches très similaires appartiennent à une classe et sont régies par quelques FI (livraison à domicile ou livraison à l'unité)
  • Chaque tâche nécessite un verrouillage et un déverrouillage appropriés des ressources (par exemple, si l'unité meurt à n'importe quelle étape, la ressource qu'il a verrouillée doit être libérée)
Kromster dit soutenir Monica
la source
2
C'est le système que nous utilisons dans notre jeu de forteresse naine. Les tâches sont accomplies par des arbres de comportement. Les ressources sont verrouillées par des comportements et déverrouillées en cas d'échec. C'est beaucoup plus robuste et facile à déboguer que l'approche de planification d'action décrite par la réponse la plus haute
mklingen
5

Il s'agit donc essentiellement d'un problème de tri topographique.

Vous avez un graphique, chaque nœud est une tâche qui doit être effectuée et certains nœuds dépendent de certains autres nœuds (cela est représenté par un bord dans le graphique du nœud dépendant au nœud dont il dépend). Vous voulez faire toutes les tâches, vous devez donc produire QUELQUE ordre des nœuds qui soit topographiquement OK (les nœuds dépendants sont après les nœuds dont ils dépendent).

Maintenant, il existe généralement de nombreux ordres de ce type (car certains nœuds n'ont pas de dépendances et peuvent être placés n'importe où, et certains nœuds ont les mêmes dépendances et ne dépendent pas les uns des autres, donc ils peuvent être dans n'importe quel ordre entre eux, et n'importe quel nœud peut être mis à n'importe quel endroit une fois que les dépendances sont terminées et avant que les nœuds en fonction ne le soient).

Il est également possible qu'il n'y ait aucun moyen de trier la topographie d'un graphique - cela se produit lorsqu'il y a des cycles dans le graphique (vous n'avez pas de bois, pour obtenir du bois dont vous avez besoin pour couper un arbre, pour couper l'arbre dont vous avez besoin d'une hache, pour vous faire une hache besoin de bois). Dans ce cas, l'algorithme devrait probablement indiquer au joueur que ces tâches ne peuvent pas être effectuées.

Vous pouvez également ajouter des priorités aux nœuds, et la tâche peut consister à trouver un tel ordre, parmi tous les ordres qui remplissent les dépendances, qui a les nœuds de priorité les plus importants exécutés en premier.

Vous pouvez également ajouter des tâches récurrentes - le moyen le plus simple sera probablement d'ajouter à nouveau la tâche avec délai d'attente au graphique à chaque fois qu'elle est effectuée.

Maintenant, comment le résoudre - http://en.wikipedia.org/wiki/Topological_sorting

Sebastian Pidek
la source