39 votes

Mise en œuvre de systèmes de réussite dans les jeux modernes et complexes

De nombreux jeux créés de nos jours sont dotés de leur propre système de réussite qui récompense les joueurs/utilisateurs pour avoir accompli certaines tâches. Le système de badges ici sur stackoverflow est exactement le même.

Il y a cependant quelques problèmes pour lesquels je n'ai pas pu trouver de bonnes solutions.

Les systèmes d'accomplissement doivent être attentifs à certains événements en permanence. Pensez à un jeu qui propose 20 à 30 accomplissements pour, par exemple, le combat. Le serveur doit vérifier ces événements (par exemple, le joueur a évité un combat). x attaques de l'adversaire dans cette bataille ou le joueur a marché x miles) tout le temps .

  • Comment un serveur peut-il gérer une telle quantité d'opérations sans ralentir et peut-être même tomber en panne ?

Les systèmes d'accomplissement ont généralement besoin de données qui ne sont utilisées que dans le moteur principal du jeu et qui ne seraient pas nécessaires de toute façon s'il n'y avait pas ces méchants accomplissements (pensez par exemple à la fréquence à laquelle le joueur a sauté pendant chaque combat, vous ne voulez pas stocker toutes ces informations dans une base de données). Ce que je veux dire, c'est que dans certains cas, la seule façon d'ajouter un succès serait d'ajouter le code qui vérifie son état actuel au cœur du jeu, et c'est généralement une très mauvaise idée.

  • Comment les systèmes d'accomplissement interagissent-ils avec le cœur du jeu qui contient les dernières informations inutiles ? (voir les exemples ci-dessus)

  • Comment sont-ils séparés du cœur du jeu ?

Mes exemples peuvent sembler "inoffensifs", mais pensez aux plus de 1000 réalisations actuellement disponibles dans le programme World of Warcraft et les nombreux, nombreux joueurs en ligne en même temps, par exemple.

25voto

ire_and_curses Points 32802

Les systèmes d'accomplissement ne sont en fait qu'une forme d'enregistrement. Pour un système comme celui-ci, publier/s'abonner est une bonne approche. Dans ce cas, les joueurs publient des informations les concernant, et les composants logiciels intéressés (qui gèrent les réalisations individuelles) peuvent s'y abonner. Cela vous permet de surveiller les valeurs publiques avec un code de journalisation spécialisé, sans affecter la logique de base du jeu.

Prenons l'exemple de votre "joueur a parcouru x kilomètres". J'implémenterais la distance parcourue en tant que champ dans l'objet joueur, car il s'agit d'une valeur simple à incrémenter et qui ne nécessite pas d'espace croissant dans le temps. Un succès qui récompense les joueurs qui marchent 10 miles est alors un abonné de ce champ. S'il y avait beaucoup de joueurs, il serait logique d'agréger cette valeur avec un ou plusieurs niveaux intermédiaires de courtiers. Par exemple, s'il y a 1 million de joueurs dans le jeu, vous pourriez agréger les valeurs avec 1000 courtiers, chacun étant responsable du suivi de 1000 joueurs individuels. La réalisation s'abonne alors à ces courtiers, plutôt qu'à tous les joueurs directement. Bien entendu, la hiérarchie optimale et le nombre d'abonnés dépendent de l'implémentation.

Dans le cas de votre exemple de combat, les joueurs pourraient publier les détails de leur dernier combat exactement de la même manière. Une réalisation qui surveille les sauts lors des combats s'abonnerait à ces informations et vérifierait le nombre de sauts. Puisqu'aucun état historique n'est requis, cela n'augmente pas non plus avec le temps. Encore une fois, il n'est pas nécessaire de modifier le code principal ; il suffit de pouvoir accéder à certaines valeurs.

Notez également que la plupart des récompenses ne doivent pas être instantanées. Cela vous laisse une certaine marge de manœuvre pour gérer votre trafic. Dans l'exemple précédent, vous pouvez ne pas mettre à jour la distance parcourue publiée par le courtier tant qu'un joueur n'a pas parcouru un kilomètre supplémentaire ou qu'un jour s'est écoulé depuis la dernière mise à jour (en incrémentant en interne jusque-là). Il s'agit en fait d'une forme de mise en cache ; les paramètres exacts dépendront de votre problème.

4voto

racarate Points 310

Vous pouvez même le faire si vous n'avez pas accès à la source, par exemple dans les émulateurs de jeux vidéo. Un simple outil de balayage de la mémoire peut être écrit pour trouver le score affiché, par exemple. Une fois que vous l'avez, votre système d'accomplissement est aussi simple que d'interroger cet emplacement de mémoire à chaque image et de voir si son "score" actuel ou autre est supérieur à son meilleur score. Ce qui est bien avec les émulateurs de jeux vidéo, c'est que les emplacements de mémoire sont déterministes (pas de système d'exploitation).

3voto

Adam Points 17726

Il y a deux façons de procéder dans les jeux normaux.

  1. Jeux hors ligne : rien d'aussi complexe que pub/sub - c'est vraiment exagéré. A la place, vous utilisez simplement une grande carte / un dictionnaire, et vous enregistrez des "événements" nommés. Ensuite, toutes les X images, ou Y secondes (ou, généralement : "chaque fois que quelque chose meurt, et 1x à la fin du niveau"), vous itérez à travers les réalisations et faites une vérification rapide. Lorsque les concepteurs veulent qu'un nouvel événement soit enregistré, il est trivial pour un programmeur d'ajouter une ligne de code pour l'enregistrer.

NB : pub/sub n'est pas adapté à cela IME car les concepteurs ne veulent jamais "when player.distance = 50". Ce qu'ils veulent en fait, c'est "quand la distance du joueur, telle que perçue par quelqu'un qui regarde l'écran, semble avoir dépassé le premier village, ou au moins 4 largeurs d'écran vers la droite" -- c'est à dire beaucoup plus vague et abstrait qu'un simple compteur.

En pratique, cela signifie que la logique est appliquée au moment où le changement se produit (avant même que l'événement ne soit publié), ce qui est une mauvaise façon d'utiliser la fonction Pub/Sub. Certains moteurs de jeu facilitent l'utilisation de la "logique au point de réception" (la partie "sub"), mais ce n'est pas la majorité, je pense.

  1. Jeux en ligne : presque identiques, sauf que vous stockez des "pions" (int qui monte), et généralement aussi : des "deltas" (tampons circulaires de ce qui s'est passé d'une image à l'autre), et : des "événements" (des choses complexes qui se sont produites dans le jeu et qui peuvent être codées en dur avec un seul ID et un tableau de paramètres de taille fixe). Ces événements sont ensuite exposés via SNMP, par exemple, pour que d'autres serveurs puissent les collecter. à faible coût CPU et de manière asynchrone

c'est-à-dire presque la même chose que le point 1 ci-dessus, sauf que vous faites attention à faire deux choses :

  • Utilisation de la mémoire à taille fixe ; et si les serveurs de "lecture" sont hors ligne pendant un certain temps, les réalisations gagnées pendant cette période devront être regagnées (bien que vous puissiez généralement demander à un membre du service clientèle de parcourir manuellement les journaux du système principal et de déterminer que la réalisation a "probablement" été gagnée, et de l'attribuer manuellement).
  • Frais généraux très faibles ; SNMP est une bonne norme pour cela, et la plupart des équipes que je connais finissent par l'utiliser.

1voto

ebsbk Points 2033

Si l'architecture de votre jeu est Pilotage par les événements alors vous pouvez mettre en place un système de réalisations en utilisant machines à états finis .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X