In my code, I've got two interfaces, let's say IOpenable
and IExaminable
. IOpenable
allows the user to Open
or Close
the object, and IExaminable
allows the user to Examine
the object.
Now, we have some sort of Tile
structure which contains objects which adhere to the following: Not all objects are openable, not all objects are examinable, some are both.
When the user right clicks a Tile
in-map, I want to populate some sort of list with the possible targets and their varied functionalities.
As a concrete example, let's say that a Book
is examinable and openable, whereas a Card
is just examinable. When I right click, I wanted to make it so that I can navigate through Open -> Book or Examine -> [Card | Book].
At the moment, I'm essentially copy/pasting code, where I assess each time if any object is IOpenable
and add it to a list of Open
targets. Then I do the same for Close
, then IExaminable
with Examine
. I'm tying the functionality of the button to a delegate e.g. [Open -> Book] would have the functionality
delegate
{
lockedInteractable.Open();
}
The problem with this is, I'm reusing the same code every single time, just changing which interface we're looking for (e.g. changing IOpenable
to IExaminable
) and changing the function in the delegate (e.g. .Open()
to .Examine()
or whatever).
Is there a more efficient way to do this? Is this simply a product of my bad code practice in making things implement IOpenable and IExaminable like that?
Clarification
In my setup, Opening results in a shift of sprites, much like closing (I do not want to make this a toggle functionality) and examining actually takes a string in and outputs some flavour text about the object, e.g. "[Bob] examined the [Door], and found it to be very disinteresting."
The duplication of code is essentially as follows:
I start by creating an instance of Button
for each examinable. Button
then has the on click event linked to .Examine
for that examinable object. We then make an instance of Button that opens the menu with all the previously made buttons, and has the text examine. By doing this, we setup a menu with Examine
-> Target
as described before.
I then create an instance of Button
for each openable. Button
then has the on-click event linked to .Open
for that...
etc for each possible operation and function.
I was hoping to find a way to simply pass in, say, IExaminable
or IOpenable
and what part I want made into a menu, e.g. .Open
and automatically create a menu, rather than repeatedly duplicating the code and just changing the method and interface.
Code
if(tileInteractable is ILock)
{
ILock lockedInteractable = tileInteractable as ILock;
if(lockedInteractable.Locked)
{
int lockedItemCount = 0;
List<string> lockedStrings = new List<string>();
List<Action> lockedActions = new List<Action>();
lockedItemCount++;
lockedStrings.Add (tileInteractable.ObjectName);
lockedActions.Add(new Action(
delegate
{
lockedInteractable.Unlock (GameManager.instance.player.entity);
Reset();
}
));
radComponentCount++;
buttonStrings.Add ("Unlock");
actions.Add(new Action(
delegate
{
Reset();
GenerateRadial(lockedItemCount,lockedActions,lockedStrings);
isActive = true;
}
));
}
}
To run you through the code, the following occurs:
A radial menu button is made. It's told to create one button with the entity's name as its hover text.
When pressed, it calls Unlock
with the sender as the player, and then closes the radial menu via Reset()
.
We then create another radial button labelled Unlock
that runs the other radial menu when it's pressed. This radial button is then built into a base menu with any other similar ones, so the first menu has Unlock
, Examine
, etc. if anything exists that implements that functionality, and the second refers to the potential targets.
This code is then nearly identically duplicated, with ILock
changed to IExaminable
and .Unlock
changed to .Examine
. Doing this creates the Examine functionality for the main radial menu.