Sylvagon,
This isn't a direct response to your question. However I too wanted to make a text-based RPG in the console a while ago, and I too wanted a nice menu system.
I don't expect you to understand this right away, but it worked for me very well. I ended up programming the game in a "menu driven" paradigm.
Big thanks to
JLBorges and the rest who helped me with this when I was stuck, I don't forget.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
|
typedef std::function<void(void)> MenuHandle;
template<typename... ARGS>
inline MenuHandle MakeHandle(ARGS&&... args) { return std::bind((args)...); }
class MenuItem
{
private:
int key;
std::string name;
std::function<void(void)> handle;
public:
MenuItem() {}
MenuItem(const int& k, const std::string& n, const std::function<void(void)>& h)
: key(k), name(n), handle(h) {}
void Call() { handle(); }
const int& GetKey() { return key; }
const std::string& GetName() { return name; }
};
class Menu
{
private:
std::string menu_name;
std::vector<MenuItem> menu_container;
public:
Menu(const std::string& name, std::vector<std::string> desc, std::vector<std::function<void(void)>> handles): menu_name(name)
{
if(desc.size() != handles.size()) throw std::runtime_error("Menu: Constructor arguments not equal");
for(size_t i = 0; i < desc.size(); i++)
menu_container.push_back(MenuItem(i+1,desc[i],handles[i]));
}
void Show()
{
while(1)
{
mega::CPrint("\n-* ",menu_name," *-\n\n");
for(size_t i = 0; i < menu_container.size(); i++)
mega::CPrint(menu_container[i].GetKey(),".) ",menu_container[i].GetName(),"\n");
mega::CPrint("\n0.) Return/Exit\n\n");
size_t input = mega::CGet<size_t>("Option: ");
if(input == 0) return;
if(input > 0 && input <= menu_container.size()) // Still trying to think of a nice way to incorporate range finding in CGet
{ mega::CPrint("\n\n"); menu_container[input-1].Call(); }
else mega::CPrint("\n\nError: Invalid option.");
mega::CPrint("\n\n");
}
}
};
|
You are going to need to change the
mega::CPrint() && mega::CGet()
functions as all of this code is part of my personal namespace. To keep things simple, change those functions to how you would normally cin and cout.
How this basically works is you create 2 vectors, one of the descriptions and the second is a vector of functions you would like to call according to that description.
The class automatically fills the "Keys" you have to press to access those functions.
Here is a basic example of the code being used:
1 2 3 4
|
Player player; // Generic object
MenuHandle PrintInventory = MakeHandle(&Player::PrintInventory,&player); // Make a MenuHandle from the addresses of the function to use and the object to use
Menu player_menu("Option selection",{"Print inventory"},{PrintInventory}); // Create the menu, first argument is the menu name, second is the vector of descriptions, third argument is the vector of MenuHandles
player_menu.Show(); // Show the menu, does not return until "0" is entered, meaning exit.
|
I think it's quite nice, and found it very useful not just in text based RPG's, but other things as well.