Comment puis-je définir des éléments dans mon RPG comme le jeu Java?

21

Je travaille avec désinvolture sur un jeu de type RPG en Java, mais j'ai du mal à comprendre comment je peux avoir des éléments qui peuvent faire beaucoup de choses différentes sans créer une classe différente pour chaque élément.

Par exemple, comment créer une hache qui pourrait couper des arbres et attaquer des monstres?

Si j'étends le hachage ou la classe d'armes, je ne peux pas étendre l'autre classe.

Si j'ai le hachage et l'arme comme interface, j'aurai beaucoup de code en double lorsqu'un poignard peut également attaquer des monstres et qu'une hache différente peut couper des arbres.

J'espère qu'il existe un moyen d'avoir une seule classe d'objet et de charger les éléments et leurs capacités respectives à partir d'un fichier. Si cela est possible, comment le faire? Si ce n'est pas le cas, quelle est la meilleure façon d'avoir des objets dans un jeu?

MESLewis
la source

Réponses:

15

La réponse de Gregory Weir est ma préférée pour savoir comment structurer les instances d'élément afin de remplir plusieurs rôles.

Pour charger à partir d'un fichier:

Tout d'abord, utilisez YAML. YAML est un langage de description de données complet; il peut être analysé relativement rapidement, lu et édité par l'homme, prend en charge les données binaires et des bibliothèques existent pour la plupart des langages de programmation, y compris Java. Cela résout le "comment puis-je obtenir des données de fichiers dans des objets?"

Deuxièmement, utilisez le modèle de poids de mouche . La plupart des données que vous lisez à partir de ces fichiers sont statiques. Cela ne changera pas par instance ("la hache fait 1d10 dégâts de base et casse le bois mais pas la pierre" - c'est vrai pour les cinq axes d'un joueur). Ce que vous lisez réellement à partir des fichiers YAML sont ces définitions platoniques, et vos instances d'éléments individuelles ont des références sans propriétaire (et constantes) à celles-ci, ainsi que des données par instance telles que "Combien de swings avant de me briser?", "Le joueur a-t-il donné moi un nom personnalisé? ", et ainsi de suite.

En partageant les données inter-instances dans un seul objet, vous conservez beaucoup de mémoire et simplifiez la mise à jour des éléments sans état de jeu persistant (sauvegarde des jeux ou base de données des joueurs).

Votre structure de classe ressemble donc à:

  • classe Item - Une instance par article
    • Possède une instance d'arme
    • Possède une instance d'outil
    • A un nom personnalisé, etc.
  • Arme de classe - (jusqu'à) une instance par objet
    • Is-a ItemComponent
    • Fait référence à WeaponDef
    • A un niveau d'enchantement bonus, etc.
  • Outil de classe - (jusqu'à) une instance par élément
    • Is-a ItemComponent
    • Se réfère à ToolDef
    • A une durabilité, etc.
  • class WeaponDef - Une instance par type d'arme
    • Lire à partir d'un fichier, les champs doivent être constants.
    • A un montant de dégâts de base, 1 ou 2 mains, etc.
  • class ToolDef - Une instance par type d'outil
    • Lire à partir d'un fichier, les champs doivent être constants.
    • Dispose d'une durabilité de base, de matériaux pouvant se casser, etc.
Marko Zajc
la source
18

Le modèle de conception Composant (pas Composite) est idéal à cet effet: http://gameprogrammingpatterns.com/component.html

Fondamentalement, une hache serait une instance de la classe Item qui contenait un WeaponComponent et un ToolComponent (peut-être). Pour tester si quelque chose peut être utilisé comme une arme, vérifiez s'il a un WeaponComponent attaché, puis parlez à cette instance WeaponComponent pour obtenir les informations sur l'arme de l'élément.

Le chargement à partir d'un fichier est bien sûr un exercice distinct.

Gregory Avery-Weir
la source
Et bien sûr, une fois que vous avez des composants, vous pouvez à nouveau faire bon usage des interfaces. Votre type Axe peut implémenter IChopper et IWeapon mais peut ensuite exposer le comportement du composant pour celui-ci, vous permettant de réutiliser à la fois le type et l'implémentation selon vos besoins et de couper le test des composants. Si tous les axes ont les mêmes capacités mais des statistiques différentes, alors vous êtes en or. Si vous avez besoin que les éléments aient des capacités uniques, vous devrez peut-être implémenter une collection de composants de jeu et demander à vos routines de mise à jour d'interroger les objets pour savoir ce qu'ils peuvent faire via les composants présents.
CodexArcanum
6
@CodexArcanum: "Votre type Axe peut implémenter IChopper et IWeapon mais peut ensuite exposer le comportement du composant pour lui" - Quel est l'intérêt de cela? Il gonfle simplement votre hiérarchie de classe. Le motif du composant est que vous n'avez pas besoin d'une classe Axe ou d'une interface IChopper ou d'une interface IWeapon, juste des composants concrets Chopper et Weapon, et un élément de niveau supérieur.
Je travaille actuellement sur un système de composants pour mes objets de jeu, et je n'ai vraiment qu'une seule plainte majeure concernant la façon dont le motif est utilisé. Compte tenu des composants de l'arme, de l'habillement et des consommables, un article pourrait théoriquement être "corrompu" en termes d'objets qui ne peuvent pas être à la fois des armes et des vêtements, ou un vêtement qui est également consommable. Logiquement, un élément ne peut être qu'un "composant majeur", mais en restreignant les composants, vous supprimez le besoin d'un système de composants tous ensemble. Ainsi, l'un des défauts fondamentaux d'un système par ailleurs incroyable
Krythic