Search code examples
c++debuggingvectortext-based

How do you place an Object inside a Room in a text-based game?


I'm a coding newbie (and despite what my user name may imply I am far from a pro), and I'm trying to write my own text-based adventure game. I have two questions.

First, I want to implement an Object class. These Objects have names and descriptions and can be placed in rooms, as well as picked up and carried around by the player. What's messing me up is that these Objects are supposed to know what room they were originally in, their "homeroom" so to speak.

I'm not sure how to let each Room know that they have Objects placed within them. Everything that I've tried to do has failed to compile.

I've tried to include Room r as a private variable in Object.cpp and include Room to the Object constructor.

Object::Object(string name, string description, Room *r)
{
    name_ = name; 
    description_ = description; 
    r_ = r; //assume r_ is a private variable

}

Secondly, regarding pointers... This assignment specifies that I must have a vector of pointers of Objects. Would it look like this?

vector<Object*>objectsInRoom; 

In main.cpp, I also need a vector of Objects. Is the vector inside the Room class keeping track of Objects in each Room? And is the vector in main.cpp keeping track of all the objects the player carries. Why must the room class have a vector of pointer of Objects? Would not having a vector of Objects suffice?

(I apologize if this sounds vague; this game is based off of an assignment that can be found here. If you scroll down to the "Extra Credit" portion and go to the first paragraph block marked 10 points, you'll find a much more extensive explanation that I tried to condense above.)

room.cpp

// Room.cpp: implementation of the Room class.
//
//////////////////////////////////////////////////////////////////////

#include "Room.h"


//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Room::Room()
{
    name_ = "The void";
    description_ = "There is nothing but blackness in every direction.";
    int i;
    for(i = 0; i < 4; i++) // set all exits to "closed"
        exits_.push_back(NULL);


}

Room::Room(string name, string desc)
{
    name_ = name;
    description_ = desc;
    int i;
    for(i = 0; i < 4; i++) // set all exits to "closed"
        exits_.push_back(NULL);


}

Room::~Room()
{
    cout << "Destroying: " << name_ << endl; 
    // make sure all exits to this room are
    // destroyed so that no one can try to enter
    // this room from another location
    if(exits_[NORTH] != NULL)
        disconnect(NORTH);
    if(exits_[EAST] != NULL)
        disconnect(EAST);
    if(exits_[SOUTH] != NULL)
        disconnect(SOUTH);
    if(exits_[WEST] != NULL)
        disconnect(WEST);
}

// --- inspectors ---
Room * Room::north() const
{
    return exits_[NORTH];
}

Room * Room::south() const
{
    return exits_[SOUTH];
}

Room * Room::east() const
{
    return exits_[EAST];
}

Room * Room::west() const
{
    return exits_[WEST];
}


string Room::name() const
{
    return name_;
}

string Room::description() const
{
    return description_;
}

/*
vector<Object> Room::object() const
{
    return roomObjects; 
}
*/

// --- mutators ---
void Room::set_name(string n)
{
    name_ = n;
}

void Room::set_description(string d)
{
    description_ = d;
}

/*
void Room::set_object(Object o)
{
    allObjects.push_back(o); 
}
*/
// --- facilitators ---
bool Room::connect(Direction exit, Room *r, Direction to)
{
    // check that both exits are free
    if (exits_[exit] != NULL or r->exits_[to] != NULL)
        return false;
    // make connection
    exits_[exit] = r;
    r->exits_[to] = this;
    return true;
}

// --- private methods ---

void Room::disconnect(Direction d)
{
    // disconnects ALL exits from another
    // room to this one.  It's sloppy, but
    // that's OK.
    Room * other_room;
    other_room = exits_[d];
    int i;
    for(i = 0; i < 4; i++)  {
        if (other_room->exits_[i] == this)
            other_room->exits_[i] = NULL;
    }
}

// --- operators ---

ostream & operator<<(ostream & out, const Room & r) {
    out << r.name() << endl;
    out << r.description() << endl;
    return out;
}

Object.cpp

#include "Object.h"; 

Object::Object()
{
    name_ = "Object"; 
    description_ = "The object lies in the room"; 

}

Object::Object(string name, string description)
{
    name_ = name; 
    description_ = description; 


}

EDIT: So, If I simply add vector<Object*> allObjects under private attributes in Room.h, I get these enter image description here. Sorry, I'm not allowed to embed images yet.


Solution

  • I'd recommend (trying to adhere to your proposed architecture as much as possible) to define a method void Room::pushObject(Object* argObject). Inside your constructor Object::Object, you could add a call r->pushObject(this). Then you could iterate through your vector once you're inside a room.

    Also, a linked list std::deque would be a better solution for your needs, as it is designed for faster insertion and deletion. Then you could room1.insert(room0.erase(yourObjPtr)) to move your objects around.

    Note that the answer is theoretical, I did not check whether these compile or not.

    Edit 1:

    Why must the room class have a vector of pointer of Objects?

    You might as well have a vector to the object instance itself, but when you wish to move the object to another room, program would have to copy all the content, instead of passing a single pointer. Also, it would prohibit the use of inheritance (you probably will get to use it in the near future :))

    Edit 2: I also see now that I misinterpreted your design. You intend to use a single global vector. I thought you wanted to use a more "object-oriented" approach, so to speak. I'd put a std::deque for each and every room, but if you wish to keep it this way, regarding your main question

    I'm not sure how to let each Room know that they have Objects placed within them.

    you might do something (thought inefficiently) like this:

    void Room::processMyObjects(void)
    {
        for (int i = 0; i < globalObjectVector.size(); i++)
        {
            if (globalObjectVector[i]->r_ == myRoomId)
            {
                // do whatever you want here.
            }
        }
    }
    

    Also you'd either have to declare r_ public, write a public getter function, or declare friend class Room inside Object declarations this way, otherwise Room cannot see a private variable of Object.