Monday, April 18, 2016

unity - How to design context menus based on whatever the object is?


I'm looking for a solution for a "Right Click Options" behaviour.


Basically any and every item in a game, when right clicked, can display a set of options based on whatever the object is.


Right click examples for different scenarios:


Inventory: Helmet shows options (Equip, Use, Drop, Description)


Bank: Helmet shows options (Take 1, Take X, Take All, Description)


Floor: Helmet shows options (Take, Walk Here, Description)


Obviously each option somehow points to a certain method that does what is says. This is part of the issue I'm trying to figure out. With so many potention options for a single item, how would I have my classes designed in such a way as to not be extremely messy?



  • I've thought about inheritance but that could be really long winded and the chain could be huge.


  • I've thought about using interfaces, but this would probably restrict me a little as I wouldn't be able to load item data from an Xml file and place it into a generic "Item" class.


I'm basing my desired end result on a game called Runescape. Every object can be right clicked in the game and depending on what it is, and where it is (inventory, floor, bank etc.) displays a different set of options available to the player to interact with.


How would I go about achieving this? What approach should I take to first of all, decide which options SHOULD be displayed and once clicked, how to call the corresponding method.


I am using C# and Unity3D, but any examples provided do not have to be related to either of them as I'm after a pattern as opposed to actual code.


Any help is much appreciated and if I have not been clear in my question or desired results, please post a comment and I'll tend to it ASAP.


Here is what I have tried so far:



  • I've actually managed to implement a generic "Item" class that holds all of the values for different types of items (extra attack, extra defence, cost etc...). These variables get populated by data from an Xml file.

  • I have thought about placing every single possible interaction method inside of the Item class but I think this is unbelievably messy and poor form. I've probably taken the wrong approach for implementing this kind of system by only using the one class and not sub-classing to different items, but its the only way I can load the data from an Xml and store it in the class.


  • The reason I've chose to load all my items from an Xml file is due to this game having the possibility for 40,000+ items. If my math is correct, a class for each item is a lot of classes.



Answer



As with everything in software development, there is no ideal solution. Only the solution which is ideal for you and your project. Here are some you could use.


Option 1: The procedural model


The ancient obsolete old-school method.


All items are dumb plain-old-data types without any methods but lots of public attributes which represent all properties an item could have, including some boolean flags like isEdible, isEquipable etc. which determine what context menu entries are available for it (maybe you could also do without these flags when you can derive it from the values of other attributes). Have some methods like Eat, Equip etc. in your player class which takes an item and which has all the logic to process it according to the attribute values.



This is more of a OOP-by-the-book solution which is based on inheritance and polymorphism.


Have a base-class Item from which other items like EdibleItem, EquipableItem etc. inherit. The base class should have a public method GetContextMenuEntriesForBank, GetContextMenuEntriesForFloor etc. which return a list of ContextMenuEntry. Each inheriting class would override these methods to return the context menu entries which are appropriate for this item type. It could also call the same method of the base class to get some default entries which are applicable for any item type. The ContextMenuEntry would be a class with a method Perform which then calls the relevant method from the Item which created it (you could use a delegate for this).



Regarding your problems with implementing this pattern when reading data from the XML file: First examine the XML node for each item to determine the type of item, then use specialized code for each type to create an instance of the appropriate sub-class.



This pattern uses composition instead of inheritance and is closer to how the rest of Unity works. Depending on how you structure your game it might be possible/beneficial to use the Unity component system for this... or not, your mileage may vary.


Each object of class Item would have a list of components like Equipable, Edible, Sellable, Drinkable, etc. An item can have one or none of each component (for example, a helmet made of chocolate would be both Equipable and Edible, and when it is not a plot-critical quest item also Sellable). The programming logic which is specific to the component is implemented in that component. When the user right-clicks on an item, the components of the item are iterated and context-menu entries are added for each component which exists. When the user selects one of these entries, the component which added that entry processes the option.


You could represent this in your XML-file by having a sub-node for each component. Example:



   
Chocolate Helmet
helmet-chocolate.png
Protects you from enemies and from starving


sweet
2560


head
20


120



No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...