I prefer things be a bit more scalable...
#include <iostream>#include <string>#include <vector>#include <algorithm>struct object{ unsigned int id; virtual std::string type() const = 0; virtual std::string display_name() const = 0;};struct actor;struct item : object{ actor* owner; virtual double weight() const = 0; virtual std::size_t stack_count() const { return 1; }};struct weapon : item{ virtual unsigned short damage_low() const = 0; virtual unsigned short damage_high() const = 0;};struct actor : object{ std::vector< std::vector<item*> > inventory; std::string proper_name; virtual std::string display_name() const { return proper_name; } void display_name( std::string const& name ) { proper_name = name; } void print_inventory() { using std::cout; cout << "Inventory for actor: " << display_name() << '\n'; for( std::vector< std::vector<item*> >::iterator slot_iter = inventory.begin(); slot_iter != inventory.end(); ++slot_iter ) { cout << "Slot " << std::distance( inventory.begin(), slot_iter ) << " : "; std::vector<item*>& slot = *slot_iter; for( std::vector<item*>::iterator item_iter = slot.begin(); item_iter != slot.end(); ++item_iter ) { item* i = *item_iter; cout << '[' << i->display_name() << ']'; } cout << '\n'; } } bool add_to_inventory( item* item_to_add ) { for( std::size_t slot_index = 0; slot_index < inventory.size(); ++slot_index ) { if( add_to_inventory( slot_index, item_to_add ) ) { //was able to slip the item into this slot return true; } } //no room in inventory return false; } bool add_to_inventory( std::size_t slot_index, item* item_to_add ) { //try to insert the item at this slot //check if this slot is beyond the bounds of the inventory if( slot_index < inventory.size() ) { std::vector< item* >& slot( inventory[ slot_index ] ); //if the slot is empty, add it right in if( slot.empty() ) { slot.push_back( item_to_add ); item_to_add->owner = this; std::cout << "Adding item: " << item_to_add->type() << " to inventory slot " << slot_index << " as base item.\n"; return true; } else { //this slot is not empty - check if we can add the item here item* base_item = slot[ 0 ]; //first make sure this item matches the item type that's in the slot if( base_item->type() == item_to_add->type() ) { //now make sure that the number of items in that slot doesn't exceed the stack_count for this item type if( slot.size() < item_to_add->stack_count() ) { //all good! slot.push_back( item_to_add ); item_to_add->owner = this; std::cout << "Stacking item: " << item_to_add->type() << " to inventory slot " << slot_index << ".\n"; return true; } } } } return false; }};namespace go //specific game objects are in this namespace{ struct shield : item { virtual std::string type() const { return "shield"; } virtual std::string display_name() const { return "Shield"; } virtual double weight() const { return 5.0; } }; struct knapsack : item { virtual std::string type() const { return "knapsack"; } virtual std::string display_name() const { return "Knapsack"; } virtual double weight() const { return 3.0; } }; struct cape : item //might inherit from 'clothing' instead { virtual std::string type() const { return "cape"; } virtual std::string display_name() const { return "Cape"; } virtual double weight() const { return 1.0; } }; struct sword : weapon { virtual std::string type() const { return "sword"; } virtual std::string display_name() const { return "Sword"; } virtual unsigned short damage_low() const { return 2; } virtual unsigned short damage_high() const { return 5; } virtual double weight() const { return 6.0; } }; struct healing_potion : item { virtual std::string type() const { return "potion_healing"; } virtual std::string display_name() const { return "Healing Potion"; } virtual double weight() const { return 0.5; } virtual std::size_t stack_count() const { return 5; } }; struct human : actor { virtual std::string type() const { return "human"; } };}int main(){ actor* bob = new go::human; bob->display_name( "Bob" ); bob->inventory.resize( 10 ); //10 slots for items item* sword = new go::sword; std::vector<item*> potions( 10 ); { std::size_t count = 10; while( --count ) { if( count == 8 ) { bob->add_to_inventory( sword ); } potions[count] = new go::healing_potion; bob->add_to_inventory( potions[count] ); } } std::cout << "\n\n"; bob->print_inventory(); //clean up { std::size_t count = 10; while( --count ) { delete potions[count]; } } delete sword; delete bob;}
Of course, where there are pointers should be some kind of smart pointers or other handle idiom.
And the actual objects would be best created through a factory...
And some kind of runtime type system to get from an object* to an actor*, or item*, etc is necessary, especially since the factory would be returning object*'s or handles to object
Designing a good Game Object system requires a good deal of patience, and lots of iterations ;)
[Edited by - RDragon1 on December 18, 2005 4:49:26 AM]