Sign in to follow this  
Shamino45

Text Engine and Menu System, a few design questions.

Recommended Posts

So, heres the situation. I have a couple classes that handle my menu's and input commands in my little text game. Well pseudo-game as it is nowhere near playable yet, but I digress. I have an Interpreter class, a Menu class, a resource manager, and thats what I got so far. These are just pieces of the puzzle, but a design issue is keeping me from coding more stuff. Anyways, heres how it works. The interpreter gets an input command from the user (a string). It takes the string and compares it with a list of valid commands at any given time. If a menu command is selected, i.e inventory, the interpreter asks the resource manager to return a pointer to that specific menu object. The interpreter uses this pointer to find out what submenus are available in that menu, thus updating our list of valid commands. Now we are in the inventory menu, and see other options such as armor, weapons, items, quest items, etc, whatever you want really. Okay, that is pretty much the process of events as of now. I'll show some code now. I've written every single bit of this myself :) The Interpreter, it doesn't have full functionality yet but I'll explain that later.
class Interpreter
{
public:

	typedef std::map< std::string, std::string > Command_List;

	virtual void Navigate_Menu(std::string Command)
	{	
		Command_List::iterator it = Commands.find(Command);

		if(it == Commands.end())
		{
			std::cout << "Fail" << std::endl;
		}
			

		//if it is a recognized command, we delete
		//the current list of valid commands

		//then

		//We make a new list of valid coimmands by
		//inserting command strings into valid commands
		//by looping through the selected menu's
		//children and getting their Selection string
		
	}

private:
	
	Command_List Commands;
};

Here is the resource manager
template< typename T_ >
class Resource_Manager
{  

public:

	typedef T_ value_type; // std library convention 

	typedef boost::shared_ptr<T_> Resource_Ptr;
	typedef boost::weak_ptr<T_> Resource_Observer;
	typedef std::map< std::string, Resource_Ptr > Resource_Map;

	Resource_Manager<T_>() {};
	~Resource_Manager<T_>() {};

	void Add_Resource(const std::string & name, T_)
	{
		Resource_Ptr Raw_Resource(T_);
		mResources.insert(std::make_pair(name, Raw_Resource));
	}

	Resource_Observer Request_Resource(const std::string & name)
	{
		Resource_Map::iterator  it = mResources.find(name);

		if (it == mResources.end())
		{
			std::cout << "Internal program error, " << name << " does not exist!" << std::endl;
		}
		else
		{
			return Resource_Observer(it->second);
		}
	}

	void Request_Resource_Removal(const std::string & name)
	{
		Resource_Map::iterator it = mResources.find(name);

		if (it != mResources.end())
		{
			mResources.erase(it);
		}
	}

private:
	Resource_Map  mResources;
};

#endif

And here is the menu object
class Menu
{
public:
	
	Menu(std::string mSelection)
	{
		mSelection = Selection;
	}

	virtual ~Menu() { Destroy(); }

	// deletes self
	void Release() { delete this; }

	// call update on all children
	virtual void Update()
	{
		for( std::list<Menu*>::iterator i = MenuChoices.begin();
			i != MenuChoices.end(); i++ )
		{
			(*i)->Update();
		}
	}

	// recursively destroy all children and self
	void Destroy()
	{
		for( std::list<Menu*>::iterator i = MenuChoices.begin();
			i != MenuChoices.end(); i++ )
		(*i)->Release();
  
		MenuChoices.clear();
	}

	// add a child
	void MenuSelection( Menu* MenuSelection )
	{
		MenuSelection->SetRootMenu(this);
	    MenuChoices.push_back(MenuSelection);
	}

	//Get the menu name
	std::string Return_Selection()
	{
		return Selection;
	}

private:

	// Set the parent of the child
	void SetRootMenu(Menu* Root)
	{
		RootMenu = Root;
	}

	//menu name
	std::string Selection;

protected:
	// list of children
	std::list<Menu*> MenuChoices;
	// pointer to parent
	Menu * RootMenu;

};

#endif

Now I'll reiterate my problem is just a question of design really. My interpreter has to access the resource manager to get a hold of menu objects. So I ask myself, will the resource_managers be declared globally? Will I have a database wrapper object that houses all of my game resources? Two options, there is simplicity in one, and good design in the other. So I ask the public, how would I set up a Database wrapper class for the resource managers? Should it be a template class so I can have multiple types of databases? Or should it be a strictly database class which holds multiple types of resource managers? To further explain my ideas of a "database" class, let me tell you what I'd also like it to do. I'd like perhaps maybe that it would have functions that run at game startup which loads and builds my menu trees, which will be created via text file I hope in the future. So, feedback? [Edited by - Shamino45 on May 24, 2007 11:28:13 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Shamino45
The interpreter gets an input command from the user (a string). It takes the string and compares it with a list of valid commands at any given time. If a menu command is selected, i.e inventory, the interpreter asks the resource manager to return a pointer to that specific menu object. The interpreter uses this pointer to find out what submenus are available in that menu, thus updating our list of valid commands. Now we are in the inventory menu, and see other options such as armor, weapons, items, quest items, etc, whatever you want really.


This could be done with the "State Pattern" (google it). At the moment, your Menu class is a concrete class that just holds a bunch of choices. I'd replace it with an abstract class containing at least two abstract methods which could, for example, look like this:

class Menu {
// returns a list of available commands and their descriptions
virtual vector<pair<string, string> > getChoices() const = 0;

// executes a command and returns the name of the next menu.
virtual string choose(string choice) = 0;
};


Then the Interpreter would always hold a single Menu pointer.
(Of course for this to work, you need to have some map that maps strings to menus.)
Using an abstract class has the advantage that you can have subclasses that dynamically generate choices. For example, you could have a subclass WeaponEquipMenu of Menu that would return all weapons of the player as choices, and equip the corresponding weapon when calling the choose method. You could have another subclass similar to your current Menu class that reads it choices from a config file.

Quote:

Now I'll reiterate my problem is just a question of design really. My interpreter has to access the resource manager to get a hold of menu objects. So I ask myself, will the resource_managers be declared globally? Will I have a database wrapper object that houses all of my game resources? Two options, there is simplicity in one, and good design in the other.


I'm not sure if you really *need* a resource manager here. A bunch of text menus won't consume horrible amounts of memory. I'd just initialize a map with all the states at the start of the game and then pass a pointer to that map into the Interpreter constructor.

[Edited by - Barius on May 24, 2007 3:26:21 PM]

Share this post


Link to post
Share on other sites
Well, the resource manager is really just a map with a wrapper class. It adds items and pairs them up with a string.. If you look at the source code you'll see :).

I have some questions about the state machine thing, but I have to go to work now...

I think the nifty part about having menu objects is that I can save them to a file and have them initialized and put together automatically, without any hard coding.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this