(RPG) Conception de table de baisse

18

Je suppose que cette question concerne davantage les jeux comme MMO et les jeux de type Diablo.

Quelles sont les conceptions habituelles pour la mise en œuvre d'une table de dépôt, où un monstre peut déposer différents types d'objets en fonction d'un pourcentage? Je suppose que le moyen le plus simple consiste à avoir un dictionnaire de `` pondération en pourcentage '' pour les types d'élément, mais cela est difficile à étendre si nous souhaitons introduire de nouveaux types d'élément (par exemple, lorsque l'expansion D2 inclut des runes et de nouveaux éléments de classe)

Extrakun
la source
4
Pourquoi est-il difficile d'étendre les dictionnaires de pourcentage lors de l'ajout de nouveaux éléments? Je veux dire si vous n'avez pas besoin d'avoir tous les pourcentages pour faire une somme de 100% (et ce n'est le cas que si vous voulez qu'un monstre laisse toujours tomber un seul élément, ce qui est assez étrange pour moi), je ne vois pas de problème.
2010 à 10h48
1
Dites Orc => {'poignard', 'épée' 'armure'}, et j'ai un nouveau type d'objet, disons rune; Je devrai mettre à jour tous les dictionnaires associés à chaque type de monstre directement. Bien sûr, ce n'est rien d'autre qu'une autre couche d'indirection ne peut résoudre. La question est donc de savoir à quoi ressemble ce calque?
Extrakun
Je ne sais pas pourquoi vous pensez que la mise à jour d'un dictionnaire est difficile. En Python, l'extension d'un dictionnaire avec de nouvelles valeurs se fait avec une seule méthode, par exemple. Pourriez-vous préciser où vous pensez que la difficulté est?
Kylotan
2
Extrakun, si vous regardez ma réponse ci-dessous, il y a une réponse à votre question "une autre couche d'indirection". Au lieu de traiter les gouttes comme une table plate, vous pouvez les créer à partir d'expressions imbriquées. Si vous autorisez les macros nommées (c'est-à-dire les fonctions), vous pouvez réutiliser des morceaux d'une table de dépôt entre différentes entités.
munificent
2
Vous venez de tomber sur la «prise» du développement de jeux. Bien sûr, vous pouvez créer un jeu en deux jours, mais vient ensuite les cinq années d'ajout de contenu. Et l'ajout de contenu est épuisant. BROYAGE.
Tor Valamo

Réponses:

22

Pour un roguelike sur lequel je travaillais, j'ai implémenté un système basé sur les données assez flexible pour générer des gouttes. Je l'ai documenté ici . C'est essentiellement un petit DSL pour sélectionner un certain nombre d'éléments choisis au hasard.

Une simple goutte ressemble à:

1-10 copper coin

Cela dit simplement de laisser tomber un nombre aléatoire de pièces de cuivre entre 1 et 10. Les choses deviennent plus flexibles lorsque vous ajoutez des branches:

one of
    turquoise stone (50%)
    onyx stone (25%)
    malachite stone (15%)
    jade stone (10%)

Un "un de" sélectionne une de ses branches enfants en fonction des probabilités données, puis l'évalue. Les gouttes peuvent déposer plusieurs éléments:

any of
    turquoise stone (50%)
    onyx stone (25%)
    malachite stone (15%)
    jade stone (10%)

Cela évaluera toutes les sous- branches et les supprimera si un jet contre leur probabilité passe. Il existe également d'autres branches pour sélectionner un élément en fonction du donjon et du niveau du joueur.

Parce que celles-ci peuvent devenir complexes, cela vous permet également de définir des macros nommées, essentiellement des fonctions qui développent une expression de branche et peuvent être réutilisées en plusieurs suppressions. De cette façon, si, par exemple, tous les nains déposent le même type de butin, vous pouvez créer une seule macro pour cela et l'utiliser sur tous ces types de monstres au lieu de copier et coller d'énormes tables de dépôt.

Un exemple de chute d' un monstre :

:: ancient dragon
    glyph   = D
    groups  = dragon
    drops
        (coins)
        2-3(1:8) one of
            (any-weapon)
            (any-armor)

Ici, (coins), (any-weapon)et (any-armor)sont tous les appels macro:

(any-armor)
    one of
        (shield)
        (helm)
        (boots)
        (gloves)
        (cloak)
        (robe)
        (soft-armor)
        (hard-armor)

qui à son tour appelle des choses comme:

(cloak)
    one near level
        cloak (10)
        velvet cloak (20)
        fur-lined cloak (50)

Vous pouvez imbriquer des expressions de manière arbitraire profondément comme un véritable langage de programmation. Cela vous donne la composabilité qu'une approche basée sur une table simple ne donnera pas.

Comme tous les systèmes basés sur les données, vous pouvez vous submerger en créant des gouttes d'une complexité impénétrable, mais cela répond à mes objectifs:

  1. Être en mesure de spécifier les éléments qui sont complètement supprimés en dehors du code.
  2. Simple à implémenter le système de base dans le code.
  3. Soyez en mesure de régler les monstres spécifiques à laisser tomber afin que le joueur puisse faire une exploration orientée vers les objectifs. ("J'ai besoin d'un collier. Je vais chercher des nains car ils ont tendance à les laisser tomber.")

Le code C # qui implémente ceci est ici .

munificent
la source
C'est une implémentation que je n'ai jamais vue auparavant. Merci!
Extrakun
12

A Stendhal, nos tables de butin sont des listes. Chaque entrée contient le nom de l'article, une quantité min et max et la probabilité. La structure interne est très similaire à ce que nous affichons sur la page Web de la créature .

Il est important pour nous que les concepteurs de jeux qui ont une grande connaissance du monde puissent définir de telles choses. Autrement dit, sans comprendre la logique complexe au niveau du code de programme. Nous n'avons donc pas les définitions des créatures et des objets dans le code du programme, mais nous les avons déplacés vers des fichiers .xml tels que elves.xml ou club.xml . Nous avons un éditeur graphique pour eux, mais la plupart des concepteurs de jeux modifient directement le fichier .xml.

Afin de rendre les créatures et les objets facilement extensibles, nous utilisons un système de blocs de construction: Il n'y a pas de classe de programme pour "elf" ou "archer elf". Mais il existe un certain nombre de classes liées au comportement telles que "lâche", "patrouille", "agressif", "archer", "guérisseur". Les concepteurs peuvent définir de nouvelles créatures en sélectionnant ces comportements sans écrire de code de programme: Par exemple, pour créer un "elfe archer", dessinez un sprite elfe avec un arc et définissez-le comme "offensant", "archer". Définissez ensuite le niveau et les attributs similaires et ajoutez des objets elfiques à la table de butin.

Pour les articles, nous avons une approche similaire, mais elle est actuellement limitée à un seul comportement: un concepteur peut ajouter un nouvel article et définir un comportement tel que "ConsumableItem", "KeyItem" ou "AttackItem", "Spell", "Scroll" sans avoir à programmer la logique.

Hendrik Brummermann
la source
8

Dans les jeux de table D&D, il existe un concept de types de butin. La plupart des monstres tomberont d'une ou plusieurs tables et ces tables seront ce que vous mettriez à jour dans votre extension. Les monstres laisseraient tomber "65% de points communs, 10% de gemmes, 15% d'art, 10% d'outils", mais vous mettriez à jour ce qui était dans chacune de ces tables.

Par exemple, Gems contient des emplacements avec des plages aléatoires qui renvoient "1 gemme (25%) 2 gemmes (50%) 5 gemmes (75%) 100 gemmes". et lorsque vous souhaitez ajouter des gemmes runiques spéciales, mettez à jour le tableau à "1 gemme (25%) 2 gemmes (50%) 5 gemmes (75%) 100 gemmes (95%) 1 gemme runique".

Mais, d'autre part, si vous avez déjà une pondération en pourcentage, pourquoi ne pas simplement mettre à jour toutes les tables de monstres dans votre extension? Les tableaux comme celui-ci sont sûrement une petite charge utile par rapport aux textures et aux maillages. De plus, vous n'avez pas non plus besoin de maintenir les pourcentages à 100, c'est juste une hypothèse que vous avez faite pour commencer et vous pouvez calculer le total réel avant de générer votre valeur aléatoire. Si les pondérations totalisent 120, générez simplement une valeur de 1-120 au lieu de 1-100.

Richard Fabian
la source
3

À première vue, cela semble être le même que le problème de la "sélection aléatoire pondérée".

Algorithme pour déterminer des événements aléatoires

Attribuez des probabilités relatives à chaque événement, additionnez-les, puis choisissez un nombre aléatoire dans cette plage pour décider quel événement vous souhaitez.

Même si vous préférez utiliser des pourcentages - qui est le même système, juste mis à l'échelle à 100 - vous surestimez la difficulté à ajouter des éléments. Si vous avez 100%, puis ajoutez 20% dans une extension, divisez simplement toutes les valeurs par (120/100) et vous êtes de retour à un total de 100%.

Kylotan
la source