0

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.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 1
    Use smart pointers, e.g. std::shared_pointer or std:unique_pointer. Raw pointers are best left to the pros (who will tend to avoid them). This is a rather advanced assignment for a tyro. The requirement that you "use pointers" makes me a little suspect of the course material. – Jive Dadson Jan 12 '18 at 08:52
  • Thank you for telling me this. Do you have any idea how to let each Room know they have Objects placed within them? I don't really care about the method used, but the first block of code (which is what I tried) won't compile. – probeginner Jan 12 '18 at 09:00
  • what's the compiler error? – corsel Jan 12 '18 at 10:37
  • Please see the edits I made on my original post. – probeginner Jan 12 '18 at 10:50

2 Answers2

0

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.

corsel
  • 315
  • 2
  • 12
  • What would you write inside the `pushObject` function? I created a vector of pointer of Objects called `vectorallObjects`, and inside the `pushObject` function wrote: `allObjects.push_back(argObject)`. I also include the `r->push_Object(this)` within my Object constructor, but it's not compiling. If I'm getting nowhere with the pointers, I'll try the linked list. The Room class was already provided for me, so would I be able to still use a linked list for the Object class and integrate that into my Room class? – probeginner Jan 12 '18 at 09:23
  • Made some edits... If you have get compile-time errors, maybe it would be easier if you post your full code and error output. – corsel Jan 12 '18 at 10:28
  • Yeah, I think my overriding problem is compile-time errors. I tried pasting my full code but it exceeds the maximum number of words. Is there any way to get around that? – probeginner Jan 12 '18 at 10:36
  • The link is in my original post. I just solved my problem. Thank you so much for your help! – probeginner Jan 12 '18 at 11:27
0

You've got a Many-to-May relationship in this case. A room doesn't own the an object, an object is in a room. You can model Many-to-May relationship with a sparse map. Say, std::unordered_multimap<Room*, Object*>. With this approach you can easily query all objects in a particular room or move object to another room by associating in with different key. You will need a reverse map std::unordered_multimap<Object*, Room*> if you want to know which room contains your object. Also, smart pointers won't help you because you won't create and destroy objects often. It's better to bind objects' lifetime with lifetime of a level they're associated with.

Minor Threat
  • 2,025
  • 1
  • 18
  • 32