Comment répartir équitablement les ressources entre les usines lorsque les ressources sont presque épuisées?

12

La ressource principale de mon jeu est la masse , stockée sous la forme d'un nombre à virgule flottante qui change avec le temps. Les nœuds de ressources augmentent la masse et les usines la drainent. Par exemple, si j'ai un nœud de ressource produisant 5 masses par seconde, je gagnerai en 5 * deltaTmasse à chaque étape du jeu. La masse est affichée arrondie à l'entier le plus proche et les indicateurs de gain / perte sont affichés par dixièmes.

Comment dois-je gérer la masse atteignant zéro? Cela crée une condition de concurrence si plusieurs usines tentent de construire en même temps: les usines en premier dans la file d'attente ou qui drainent moins de ressources ont la priorité une fois que plus de ressources arrivent et donc se construisent plus rapidement que les autres.

Comment puis-je y faire face? Dois-je sauter l'étape complètement?

Foule
la source
Bah, mon commentaire n'a pas sauvé. J'avais une meilleure explication. Fondamentalement, j'ai une ressource qui est accessible à chaque étape par chaque objet. Chaque objet ajoute ou soustrait de la ressource. Mon problème est que si la ressource atteint 0, je ne sais pas quoi faire. Dois-je faire une sorte de file d'attente? Dois-je sauter l'étape d'un objet. Quelle?
Mob
3
Tournoi à la ronde. Problème résolu.
Patrick Hughes
La réponse de Roy ci-dessous combinée avec le commentaire décrit un système à tour de rôle décent, facile à entretenir et à régler. Tant que votre problème de conception immédiat est résolu, tout va bien =)
Patrick Hughes

Réponses:

9

Je suis d'accord avec Petr: il n'y a pas de moyen défini de le faire. La façon dont vous voulez le faire dépend de la façon dont vous voulez concevoir votre jeu.

Dans cette circonstance, cependant, je pense qu'il est immédiatement évident le type de mécanicien que vous essayez d'utiliser: vous voulez juste que les choses produisent le plus rapidement possible, dans la quantité de masse dont vous disposez.

Produire dans les limites de sa capacité

Je vais prendre une feuille du livre de Supreme Commander, car vous faites un système très semblable au leur: si vous produisez au-dessus de la capacité, la meilleure façon de gérer cela est de ralentir la production dans tous les domaines. La réduction de la capacité de production est en fait assez simple.

Un mécanicien de vitesse de production

À chaque étape de la mise à jour, vos usines ne produisent pas seulement une quantité définie: elles fonctionnent à une vitesse de production , qui détermine les progrès qu'elles font à chaque étape et la masse qu'elles utilisent. Lorsque vous produisez à 75% de capacité, vos usines progressent de 75% à chaque étape et consomment 75% de la masse par rapport à 100% de capacité.

Pour calculer la vitesse de production, avant de construire quoi que ce soit, vous devez interroger vos usines pour déterminer les ressources totales qui seraient utilisées à cette étape à pleine capacité. Ensuite, vous effectuez un calcul simple:

production speed = (total mass capacity / mass required this step)
if (production speed > 1.0) production speed = 1.0

Disons que vous avez besoin de 125 masses pour produire à pleine capacité, mais que vous n'avez que 100 masses pour cette étape. Cette équation vous donne une vitesse de production de 0,8 (la représentation décimale de 80%). Lorsque vous dites à vos usines d' exécuter réellement leur construction , vous leur donnez cette valeur pour leur dire à quelle vitesse elles construisent: et maintenant votre production est ralentie à tous les niveaux.

Alternatives

Vous pouvez également commencer à fermer temporairement des usines jusqu'à ce que la capacité de production soit libérée, et il pourrait être très intéressant de voir que cela arrive aux usines plus éloignées des générateurs lorsqu'elles sont à très faible capacité.

Des ressources multiples?

À vous de voir comment vous gérez cela; il y a beaucoup d'options. Le plus simple est probablement de calculer une capacité de production pour chaque ressource, puis de choisir la plus faible , de sorte que votre ressource la plus faible devienne un goulot d'étranglement pour tout le reste.

doppelgreener
la source
Je pense que vous n'avez même pas besoin de dire à l'usine de produire à une vitesse de 80%, car tout ce que votre usine crée utilise une quantité fixe de masse. Par exemple: vous construisez un réservoir qui prend 100 masses à construire, normalement l'usine peut utiliser 2 masses à chaque cycle. Cela signifie qu'il faut 50 cycles pour terminer le réservoir et chaque cycle vous ajoutez 2 à la masse actuelle des réservoirs. Maintenant, vous n'avez qu'une seule masse disponible, cela signifie ce cycle, la masse actuellement dépensée des réservoirs augmente de 1 au lieu de 2. Après chaque cycle, vérifiez simplement la masse actuelle par rapport à la masse totale requise pour voir si le réservoir est complètement construit ou non.
Thomas
Si vous avez 0 masse disponible, n'ajoutez simplement aucune masse au réservoir. Le temps qu'il faut pour construire quelque chose de cette façon peut varier en fonction de votre revenu de masse. si vous avez 2 usines qui peuvent utiliser 2 masses / cycle et seulement 3 revenus, le réservoir 1 est construit en 50 cycles, le réservoir 2 en 100. Une autre façon est de diviser la quantité totale de masse disponible sur toutes les usines qui l'utilisent (sont construire activement quelque chose). La quantité totale de masse qu'une usine peut utiliser pourrait être améliorée en ajoutant des niveaux à l'usine. Par exemple, au niveau 1, ils peuvent dépenser 2 masses, au niveau 2: 3 masses etc. etc.
Thomas
@Thomas Ajouter de la masse à un produit en cours de fabrication semble une manière trop complexe par rapport à la simple réalisation d'un pourcentage du produit. D'autant plus que votre usine doit tout savoir sur votre système de ressources au lieu d'une simple propriété "taux de production". Si le résultat pour le joueur est le même, gardez l'implémentation aussi simple que possible. Cela facilite également les modifications futures, par exemple lorsque vous ajoutez / supprimez des ressources.
Hackworth
@Hackworth J'ai tendance à être en désaccord, l'usine n'a pas besoin de connaître le système de ressources. L'usine ne sait que ce qu'elle construit et à quelle distance. Le système de ressources indique simplement à l'usine d'ajouter un montant X à la construction. De cette façon, vous n'avez pas besoin de calculer le pourcentage du revenu des ressources de cette usine et vous n'avez pas besoin de convertir le revenu des ressources en pourcentage d'achèvement supplémentaire.
Thomas
6

Bien que j'aime la réponse de Jonathan Hobbs, je pense qu'un système de file d'attente est encore plus simple:

Queue<Factory> queue = ...;
int numFactories = ...;

Update()
{
    int resources = GetAllResourcesForThisStep();
    for(int i = 0; i < numFactories; i++)
    {
        if(queue.Peak().RequiredResources <= resources)
        {
            Factory f = queue.Pop();
            resources -= f.RequiredResources;
            queue.Push(f);
        }
        else
        {
            break;
        }
    }
}

Cela fonctionnera probablement en moyenne de la même manière que la mise en œuvre de Jonathan. Cependant, la solution de Jonathan pourrait poser des problèmes si la vitesse de travail est définie très bas et mon implémentation pourrait avoir une usine avec une demande de ressources très élevée pour ce cadre, si elle bloquait d'autres usines pour plusieurs cadres.

Roy T.
la source
+1 Je suis en train de développer un jeu avec des ressources doubles, un peu comme dans la question, et quand j'arriverai à résoudre le problème de verrouillage de l'offre, je prévois d'utiliser quelque chose de similaire. Pas ce code exact, mais l'idée derrière. Les consommateurs qui sont en mesure d'utiliser les ressources en une seule fois obtiendront une priorité inférieure au cours de la suivante. Je prévois également d'ajouter un indicateur pour indiquer si ce consommateur est prioritaire et de donner le contrôle de cet indicateur à l'utilisateur.
John McDonald
Méfiez-vous de la famine si vous leur donnez des priorités distinctes. :)
Roy T.
La famine avec des priorités séparées serait le but cependant. Avez-vous déjà joué à Settlers 4 ou à Knights & Merchants? Si vous construisez trop de bâtiments, les ressources limitées vont à des bâtiments aléatoires et il faut une éternité pour terminer quoi que ce soit. Mais ils vous permettent également de choisir si un bâtiment est important ou non, auquel cas les ressources iront d'abord à ces bâtiments importants. La clé est de ne jamais trop construire, ou si vous le faites, trop construire le moins possible.
John McDonald
5

Je développe un système d'approvisionnement similaire dans mon propre jeu, j'ai donc également réfléchi à la façon de résoudre le problème de blocage de l'offre et le favoritisme. Pour illustrer le problème, je vais créer un exemple simple:

Si vous avez une liste: [producteur1, consommateur1, consommateur2, consommateur3] et que vous mettez à jour dans l'ordre, à partir de l'offre = 0, vous obtiendrez ceci:

producer1 produces 5 mass. You now have 5 mass
consumer1 wants 3 mass. Success, you now have 2 mass
consumer2 wants 3 mass. Fail
consumer3 wants 3 mass. Fail
[next tick]
producer1 produces 5 mass. You now have 7 mass
consumer1 wants 3 mass. Success, you now have 4 mass
consumer2 wants 3 mass. Success, you now have 1 mass
consumer3 wants 3 mass. Fail
etc...

consumer1 obtient tout le plaisir, tandis que les consommateurs 2 et 3 meurent de faim jusqu'à ce que le consommateur 1 soit satisfait. Selon votre jeu, cela peut ne pas être souhaitable. Je sais que dans mon jeu, ce n'est pas le cas. Quand j'y arriverai, je vais créer une file d'attente où les consommateurs qui ont été nourris dans une tique se déplaceront à l'arrière de la file d'attente pour la prochaine tique, ce qui, je crois, est ce à quoi Roy T. s'attaque. L'exemple ci-dessus ressemblerait à ceci:

producer1 produces 5 mass. You now have 5 mass
consumer1 wants 3 mass. Success, you now have 2 mass. <-- Move to end of queue
consumer2 wants 3 mass. Fail
consumer3 wants 3 mass. Fail
[next tick]
producer1 produces 5 mass. You now have 7 mass
consumer2 wants 3 mass. Success, you now have 4 mass  <-- Note the order change
consumer3 wants 3 mass. Success, you now have 1 mass
consumer1 wants 3 mass. Fail
etc...

De cette façon, chacun obtiendra sa juste part des ressources.

Je prévois également d'implémenter une file d'attente supplémentaire à utiliser comme file d'attente prioritaire afin que l'utilisateur puisse sélectionner certaines structures pour avoir la priorité des ressources. La file d'attente prioritaire sera toujours servie avant la file d'attente standard. Assurez-vous que tous les producteurs sont mis à jour en premier, puis consommez toutes les ressources ensuite, sinon la file d'attente se brisera lorsque vous produirez des ressources à mi-chemin et que certains consommateurs sont déjà affamés.

Donc, pour récapituler: mettre à jour les producteurs, puis la file d'attente prioritaire, déplacer les consommateurs alimentés à la fin de la file d'attente prioritaire, puis mettre à jour la file d'attente standard, déplacer les consommateurs alimentés à la fin de la file d'attente standard.

John McDonald
la source
Pris à la limite, cela pourrait signifier qu'aucun consommateur ne termine tant que chaque consommateur ne peut pas terminer. Dans un scénario de chaîne de production réaliste, cela est peu probable et pourrait être assez désastreux si quelqu'un voulait avoir une file d'attente de construction pour une armée massive. Il sera pratiquement sans troupes pendant toute la durée de la construction de l'armée.
Cardin
Cette réponse a été ma pensée initiale lorsque j'ai lu la question. En outre, il convient de noter que la masse consommée par tick n'est pas nécessairement la masse pour créer une unité complète, mais plutôt le coût unitaire sur la durée requise, donc je ne suis pas sûr que les préoccupations de @ Cardin soient valables, à moins que votre unité le coût par tick est très proche de votre taux de collecte total. Je voudrais simplement que la file d'attente prioritaire soit explicitement gérée par le joueur, afin qu'il puisse décider qui meurt de faim.
brice
@Cardin, vous avez tout à fait raison, mais il peut également être utilisé comme mécanicien de jeu. Settlers 4, Knights & Merchants, Total Annihilation, Supreme Commander sont des jeux que je connais qui l'ont fait. L'astuce consiste à ne pas atteindre ce verrou d'alimentation, et si vous le faites, assurez-vous de sortir du verrou d'alimentation dès que possible. L'ajout d'une file d'attente prioritaire permet aux utilisateurs de sortir plus facilement.
John McDonald
3

Eh bien, je vais développer l'idée de John, puisque nous en avons discuté un peu dans le chat .

modifier: Cette solution n'est en fait préférable que si le consommable est pertinent pour la fréquence à laquelle l'usine doit obtenir un lot de ressources. Si c'est la même chose, alors vous pouvez en effet simplement utiliser une file d'attente.

Ma solution: toutes les usines répertoriées dans une file d'attente prioritaire. La priorité est augmentée car une usine souffre de la famine. Famine, priorité, mise à zéro lorsque l'usine a consommé des ressources. La priorité absolue va toujours obtenir le prochain lot de ressources.

Pour déterminer quelle usine obtient quelles ressources, dans une sorte de pseudo-code:

iterator i = factoryqueue.start()
bool starvation = false
while(i.next())
  if(i.ready)
    if (!starvation) 
      if (i.consumeAmount < resource.count) starvation = true
      else 
        i.consume(resource)
        i.priority = 0
    if (starvation)
      i.priority += 1

De cette façon, vos usines fabriqueront à tour de rôle 1 produit, si vous souhaitez ajuster en prenant en compte le montant consommé afin que les produits moins chers soient fabriqués plus fréquemment, vous pouvez augmenter la priorité de 1 / consommer le montant par exemple.

Toni
la source
J'aimerais voter en faveur de cela, mais je ne suis pas sûr de ce que cela est censé faire - il garde une trace de la famine, mais sinon (probablement) tourne simplement dans la file d'attente exactement comme d'habitude, et la famine et la priorité ne finissent jamais par apparaître faire n'importe quoi.
doppelgreener
la différence devient apparente si vous augmentez la priorité de + = 1 / amountThisFactoryConsumes, alors ceux qui nécessitent plus de ressources pour créer un produit seront un peu en retard, permettant aux moins chers de prendre proportionnellement plus de lots de ressources. Cela égaliserait le ratio ressources par usine. Cependant, ce n'est pas encore indéréglable, car le nombre de famine est défini sur le nombre magique 0 à chaque fois que les ressources sont consommées par l'usine, donc il ne sera pas mis en quarantaine pour être distribué de manière exactement égale lorsque le renouvellement des ressources est ponctué.
Toni
En fait, je ne sais plus si ce n'est pas garanti. J'aurais besoin de dessiner des graphiques et de les tester pour en être sûr.
Toni
oh, et la priorité est une qualité de la file d'attente prioritaire elle-même. Je ne vais pas m'embêter à expliquer comment en construire un. La file d'attente prioritaire elle-même est toujours triée en fonction de la valeur de priorité de ses membres.
Toni
+1 Comprenant qu'il s'agit d'une file d'attente prioritaire, son fonctionnement est désormais simple: parcourez la file d'attente et choisissez le plus tôt possible qui pourrait consommer des ressources. Si la capacité est fortement divisée (vous avez 1000 ressources cette fois, mais une centaine de builds de 100 ressources), cela ne devrait pas être un problème, et les choses se nourrissent assez bien. Même si quelque chose est bien au-dessus de vos ressources cette tique, cela pourrait éventuellement économiser suffisamment pour faire un peu de progrès - ce qui a pour effet de le ralentir ou de fermer les grandes choses entièrement en faveur de petites choses, ce qui est une bonne chose. J'aime beaucoup ça. :)
doppelgreener
2

Question étrange.

Mon problème est que si la ressource atteint 0, je ne sais pas quoi faire. Dois-je faire une sorte de file d'attente? Dois-je sauter l'étape d'un objet. Quelle?

Ce que vous devez faire dépend de la logique de jeu que vous créez. Vous pouvez faire une file d'attente, vous pouvez sauter. Cela dépend de la façon dont vous pensez que votre jeu devrait se comporter. Corrigez-moi, si je me trompe sur votre question.

Petr Abdulin
la source
1

Vous pouvez conserver un certain nombre de la demande totale de ressources par tick pour toutes les constructions. Si un stockage de ressources atteint moins que ce montant requis, alors toute construction s'arrêtera complètement jusqu'à ce que le stockage ait rassemblé suffisamment pour supporter au moins 1 tick de production. La production peut alors reprendre.

Ainsi, au lieu de stocker le taux de production sous forme de flotteur, il est binaire - votre usine produit à pleine vitesse ou non.

Cela étant dit, cette approche est essentiellement la même que la réponse de Jonathan, pour les cas spéciaux de taux de production 0,0 et 1,0 - un flotteur arbitraire f avec 0,0 <= f <= 1,0 est probablement plus élégant car vous n'obtenez pas de mouvements saccadés de la quantité de stockage , mais la logique devrait être un peu plus simple.

Hackworth
la source