Item Management Systems
IntroductionA lot of games allow the player to pick up, carry around, use, sell, buy, drop, drink, wear various items. For such a thing to happen without becoming an overwhelming task for the programmers, a coherent system for managing all these actions becomes necessary. In this article, I will present and discuss a simple and basic system for managing objects, that can easily be extended to cover more complex cases. System architecture : what's what?Keeping all item information along with each item is overkill: all small health potions have the same name, looks and properties. Sure, some objects might have "personal" data such as ammunition, charges, enchantments, nicknames or durability that must be stored on the item itself, but this can be added later on. The items will be represented by objects of a cItem class that will act as a black box - users of the class do not need to know how it is working on the inside. These objects will actually contain an item index which indicates what kind of item they are. To get the properties of an object, there will be a cItemDatabase that holds all the information for all the possible item indices an object can have, and which can be asked for this for information. Finally, to represent piles of various items with various amounts (whether it is a pile on the ground, a pile being traded to somebody else, or in the player's backpack) there will be a cItemPack class which acts just like any pile of items: you can count the objects, add some, or remove others. The itemsThe first and foremost step is to implement the class that will represent the items - since it's what we're going to move around and use most of the time anyway. An "item" variable should obviously have the following properties:
Because we will need to manipulate the objects, we also need the object to have the following (from a programming standpoint) :
This leads to the following class definition: class cItem { unsigned long type; public: cItem( unsigned long ); cItem & operator= ( const cItem & ); bool operator== ( const cItem & ) const; bool operator< ( const cItem & ) const; unsigned long getID( ) const; }; This is it: a constructor (from an identifier), assignment and comparison operators, and an identifier function. The private type variable is the item index that will be used later to get the item properties from the item database. Also note that the const keyword appears in a lot of places: it is quite a good programming practice to mark as const variables that should not be modified by the function they are passed to, and as const functions those member functions that can be called without altering the object. This way, when the cItem class will get bigger later on, it will become better to pass objects by reference, in which case marking certain variables as const prevents those hard-to-spot bugs where one of those references is mistakenly modified (they cause a compiler error instead). As far as the behavior of the object goes, the implementation is quite straightforward: cItem::cItem( unsigned long t ) : type( t ) { } cItem &cItem::operator =( const cItem & o) { type = copy.type; return( *this ); } The constructors and assignment operator are quite easy right now, since they simply have to set the type to whatever is required. The type of the object is used for comparisons as well: unsigned long cItem::getID( void ) const { return( type ); } bool cItem::operator ==( const cItem & i ) const { return( type == i.type ); } bool cItem::operator <( const cItem &i ) const { return( type < i.type ); } As the system grows, so will the item class and its members, but it will happen transparently: new things will be added, but the behavior of the previously implemented methods will remain the same. |
|