Je recherche une solution pour un comportement "Options de clic droit".
Fondamentalement, chaque élément d'un jeu, lorsqu'il est cliqué avec le bouton droit, peut afficher un ensemble d'options en fonction de l'objet.
Exemples de clic droit pour différents scénarios :
Inventaire: le casque affiche les options (équiper, utiliser, déposer, description)
Banque: le casque affiche les options (Take 1, Take X, Take All, Description)
Étage: le casque affiche les options (prendre, marcher ici, description)
De toute évidence, chaque option pointe en quelque sorte vers une certaine méthode qui fait ce qui est dit. Cela fait partie du problème que j'essaie de comprendre. Avec autant d'options de potention pour un seul article, comment pourrais-je avoir mes classes conçues de manière à ne pas être extrêmement désordonnées?
- J'ai pensé à l'héritage mais cela pourrait être très long et la chaîne pourrait être énorme.
- J'ai pensé à utiliser des interfaces, mais cela me limiterait probablement un peu car je ne serais pas en mesure de charger les données d'élément à partir d'un fichier Xml et de les placer dans une classe générique "Élément".
Je fonde mon résultat final souhaité sur un jeu appelé Runescape. Chaque objet peut être cliqué avec le bouton droit dans le jeu et selon ce qu'il est et où il se trouve (inventaire, sol, banque, etc.) affiche un ensemble différent d'options disponibles pour le joueur avec lequel interagir.
Comment pourrais-je y parvenir? Quelle approche dois-je adopter pour tout d'abord, décider quelles options DEVRAIENT être affichées et une fois cliqué, comment appeler la méthode correspondante.
J'utilise C # et Unity3D, mais aucun des exemples fournis ne doit être lié à l'un ou l'autre car je suis après un modèle par opposition au code réel.
Toute aide est très appréciée et si je n'ai pas été clair dans ma question ou les résultats souhaités, veuillez poster un commentaire et je m'y attacherai dès que possible.
Voici ce que j'ai essayé jusqu'à présent:
- J'ai en fait réussi à implémenter une classe "Item" générique qui contient toutes les valeurs pour différents types d'objets (attaque supplémentaire, défense supplémentaire, coût etc ...). Ces variables sont remplies par les données d'un fichier Xml.
- J'ai pensé à placer toutes les méthodes d'interaction possibles à l'intérieur de la classe Item mais je pense que c'est une forme incroyablement désordonnée et pauvre. J'ai probablement adopté la mauvaise approche pour implémenter ce type de système en utilisant uniquement une seule classe et non une sous-classification dans différents éléments, mais c'est la seule façon de charger les données à partir d'un fichier XML et de les stocker dans la classe.
- La raison pour laquelle j'ai choisi de charger tous mes articles à partir d'un fichier Xml est due au fait que ce jeu a la possibilité de plus de 40000 articles. Si mes calculs sont corrects, une classe pour chaque élément est un grand nombre de classes.
la source
Réponses:
Comme pour tout dans le développement de logiciels, il n'y a pas de solution idéale. Seule la solution idéale pour vous et votre projet. Voici quelques exemples que vous pourriez utiliser.
Option 1: le modèle procédural
L'
ancienneméthodeobsolète de lavieille école.Tous les éléments sont des types de données simples et anciens sans aucune méthode, mais de nombreux attributs publics qui représentent toutes les propriétés qu'un élément pourrait avoir, y compris certains indicateurs booléens comme
isEdible
,isEquipable
etc., qui déterminent les entrées de menu contextuel disponibles pour lui (peut-être pourriez-vous également se passer de ces drapeaux lorsque vous pouvez le dériver des valeurs d'autres attributs). Ayez quelques méthodes commeEat
,Equip
etc. dans votre classe de joueur qui prend un élément et qui a toute la logique pour le traiter selon les valeurs d'attribut.Option 2: le modèle orienté objet
Il s'agit plus d'une solution OOP-by-the-book qui est basée sur l'héritage et le polymorphisme.
Avoir une classe
Item
de base dont héritent d' autres éléments commeEdibleItem
,EquipableItem
etc. La classe de base doit avoir une méthode publiqueGetContextMenuEntriesForBank
,GetContextMenuEntriesForFloor
etc. qui retourne une liste deContextMenuEntry
. Chaque classe héritée remplacerait ces méthodes pour renvoyer les entrées du menu contextuel appropriées pour ce type d'élément. Il peut également appeler la même méthode de la classe de base pour obtenir des entrées par défaut applicables à tout type d'élément. LeContextMenuEntry
serait une classe avec une méthodePerform
qui appelle ensuite la méthode appropriée à partir de l'élément qui l'a créé (vous pouvez utiliser un délégué pour cela).Concernant vos problèmes d'implémentation de ce modèle lors de la lecture des données du fichier XML: Examinez d'abord le nœud XML de chaque élément pour déterminer le type d'élément, puis utilisez un code spécialisé pour chaque type pour créer une instance de la sous-classe appropriée.
Option 3: le modèle basé sur les composants
Ce modèle utilise la composition au lieu de l'héritage et est plus proche de la façon dont le reste d'Unity fonctionne. Selon la façon dont vous structurez votre jeu, il peut être possible / avantageux d'utiliser le système de composants Unity pour cela ... ou non, votre kilométrage peut varier.
Chaque objet de classe
Item
aurait une liste des composants commeEquipable
,Edible
,Sellable
,Drinkable
, etc. Un élément peut avoir une ou aucune de chaque composant (par exemple, un casque en chocolat serait à la foisEquipable
etEdible
, quand il n'est pas un complot critique objet de quête égalementSellable
). La logique de programmation propre au composant est implémentée dans ce composant. Lorsque l'utilisateur clique avec le bouton droit sur un élément, les composants de l'élément sont itérés et des entrées de menu contextuel sont ajoutées pour chaque composant existant. Lorsque l'utilisateur sélectionne l'une de ces entrées, le composant qui a ajouté cette entrée traite l'option.Vous pouvez représenter cela dans votre fichier XML en ayant un sous-nœud pour chaque composant. Exemple:
la source
Donc, Mike Hunt, votre question m'intéressait tellement, j'ai décidé de mettre en œuvre une solution complète. Après trois heures à essayer différentes choses, je me suis retrouvé avec cette solution étape par étape:
(Veuillez noter que ce n'est PAS un très bon code, donc j'accepterai toutes les modifications)
Création du panneau de contenu
(Ce panneau sera un conteneur pour nos boutons de menu contextuel)
UI Panel
anchor
en bas à gauchewidth
à 300 (comme vous le souhaitez)Vertical Layout Group
et définirChild Alignment
en haut au centre,Child Force Expand
sur largeur (pas sur hauteur)Content Size Fitter
et définir laVertical Fit
taille minimale(À ce stade, notre panneau se réduira à une ligne. C'est normal. Ce panneau acceptera les boutons comme des enfants, les alignera verticalement et s'étirera à la hauteur du contenu résumé)
Création d'un exemple de bouton
(Ce bouton sera instancié et personnalisé pour afficher les éléments du menu contextuel)
anchor
en haut à gaucheLayout Element
, définiMin Height
sur 30,Preferred Height
sur 30Création d'un script ContextMenu.cs
(Ce script a une méthode qui crée et affiche le menu contextuel)
ContentPanel
préfabriqué dans l'emplacement correspondant et faites glisser Canvas lui-même vers l'emplacementCanvas
.Création d'un script ItemController.cs
Cube
), Placez-le pour qu'il soit visible par la caméra et attachez-y ce script. Glissez-déposez lesampleButton
préfabriqué dans l'emplacement correspondant.Maintenant, essayez de l'exécuter. Lorsque vous cliquez avec le bouton droit sur l'objet, le menu contextuel doit apparaître, rempli avec la liste que nous avons créée. Appuyez sur les boutons pour imprimer dans la console du texte et le menu contextuel sera détruit.
Améliorations possibles:
Exemple de projet (Unity Personal 5.2.0, plug-in VisualStudio): https://drive.google.com/file/d/0B7iGjyVbWvFwUnRQRVVaOGdDc2M/view?usp=sharing
la source