design for a text adventure

Started by
10 comments, last by Zahlman 18 years, 4 months ago
Hey guys, I want to preface this post by saying I have -purposefully- not read any tutorials on text-adventure game creation. I wanted to spitball a few design ideas around by myself before I looked at what others do. Here's what i've come up with as far as program design for the game's "world." Let me know what you think. Is it any good? And if yes/no, what needs work or what is good about it? The world, in my head, would be made up completely of CRoom objects, a class that looks something like the following:
class CRoom
{
private:
     int roomID;
     int north;
     int south;
     int east;
     int west;

     CItem* itemsInRoom;
     int numItems;
     char* roomDescription;

public:
     //insert miscellaneous functions
     //for accessing data
}

In practice, roomID would be, obviously, the ID# of the room. These numbers would be used to keep track of each room. The ints north, south, east, and west, would be the ID numbers of the rooms connected to each respective direction. If a particular room had nothing connected to a specific side, then that int would simply be zero (for example if a room was in the northeast corner of a building then north and east would both equal 0). The CItem pointer would hold an array of "items" that would exist in the room for the character to interact with, and the roomDescription pointer would hold, fittingly, a string that would print to the screen, describing the room. I feel this provides an organized approach to the naviagation of rooms in a text adventure. I havn't put much though into how to program puzzles and the like just yet... moreso the navigation aspects. The game's driver could load a text file and dynamically load/parse a linked list of "CRoom"s to create the game's world, making it pretty easy to modify the world without having to recompile everything. Other things I was considering: -instead of room ID#s, have north south east and west be pointers to CRoom objects -Still not sure what to do from here; I'll probably buckle in the end and look at the tutorials to see how people script these addicting games. Does anyone have hints as to what types of problems/dillemas I should consider when designing a text adventure game? What types of things should I be anticipating? I'm really new to game programming -- and large-scale software design in general -- but I feel I have a very solid understanding of the C++ core language, and a good head start to attaining the much-sought-after object-oriented mindset. Thanks for helping a n00b, guys.
Deep Blue Wave - Brian's Dev Blog.
Advertisement
I've never actually done a text adventure game, but one approach you might explore is using a search tree to control the flow of the game. That way you can use recursion to control movement through the world. You can load the whole tree from a text file which would allow you to write the whole script in a more or less readable way. Again, I'm not speaking from experience, it's just my first thought on the subject. Good luck.
dear BTownTKD,

if this is one of your first game project i suggest
to progress and tackle things as they come.
since this is a relative simple app(text adventure)
self taught would help your design techniques.

cheers.
Quote:Original post by BTownTKD
Other things I was considering:
-instead of room ID#s, have north south east and west be pointers to CRoom objects

I would try to refactor toward this end. If you know for sure you're only going to have 4 possible exits from a room, then some pseudo code might look like

class Room {public:   Room(): north(0), east(0), south(0), west(0) {}   void connectRoomToNorth( Room * room ) { north = room; }         // connect rooms   void connectRoomToEast( Room * room ) { east = room; }   void connectRoomToSouth( Room * room ) { south = room; }   void connectRoomToWest( Room * room ) { west = room; }   Room * roomToTheNorth() const { return north; }                  // and find rooms   Room * roomToTheEast() const { return east; }   Room * roomToTheSouth() const { return south; }   Room * roomToTheWest() const { return west; }      ...private:   std::string name;                                                // use std::strings instead of char arrays   Room * north, * east, * south, * west;   std::list< Item * > itemsInRoom;                                 // use a std::list                                                                    // instead of a plain array      ...      };

You're coding in C++, so you should probably prefer std::strings over char arrays. They're a hell of alot easier to work with and are much safer than raw arrays.

I suggested a std::list because you can easily add and remove Items (compared to say, a std::vector).

Of course, you'll have to check for NULL to see if there's an adjacent room. A better approach might be to define Door and Wall objects, and have Room contain (smart) pointers to these objects. Doors would then connect two Rooms together. This eliminates the NULL check, and also makes it easier for you to prohibit certains Rooms at certain times (by having a locked/unlocked Door state).

Walls could also connect Rooms together. This would give you the ability to have BreakableWalls that the player can enter Rooms through.

EDIT: typo
:stylin: "Make games, not war.""...if you're doing this to learn then just study a modern C++ compiler's implementation." -snk_kid
You may want to look into std::vector's for storing your CItem structures in the rooms.

You may want to look into having a std::vector<string> of descriptions, so that you can have multiple descriptions for any one room ("it is dark in here" => [use candle] => "The candle now casts a dim light into the drab room")

One of the biggest pitfalls is to hard-code the game. Think of the minimal rules for your game, and implement those.
If you think you want to later add "up" "down" "SW" "SE"... to your directions, maybe you should change the door implementation
to be more like:

struct Door
{
int roomID_doorfrom;
int roo_IDdoorto;
string direction;
string state;
};

and do string comparisons with what the user inputs for the direction.
(string state) refering to something I did in my text adventure: have a game-state.
Giving doors and items a set of game-states where you can use/see them can be usefull. If picking up "book of ruin" adds gamestate "has_book_of_ruin",
you can have [door to hidden mage's quarters] only visible when "has_book_of_ruin" is in the game-state.

PM me if you would like to see my code.

[Edited by - KulSeran on December 1, 2005 11:13:32 PM]
I'd recommend not hardcoding in your directions like that. It doesn't give you any advantages and will likely end up adding a bunch of unnecessary switches and such hardcoded throughout your code.

From the text adventures I've implemented (which were in QuickBasic, about 10 years ago), I had something like this (translated to C++):

const int NUM_ROOMS = 20;const int NUM_ITEMS = 5;const int NUM_DIRECTIONS = 6;enum DIRECTIONS{    DIR_NORTH = 0,    DIR_SOUTH = 1,    DIR_EAST = 2,    DIR_WEST = 3,    DIR_UP = 4,    DIR_DOWN = 5};int roomMap[NUM_ROOMS][NUM_DIRECTIONS];std::string roomDescriptions[NUM_ROOMS];std::string itemDescriptions[NUM_ITEMS];int itemLocations[NUM_ITEMS];int currentRoom = 0;


Your map works like this:

int newRoom = roomMap[currentRoom][desiredDirection];


Then you use special identifiers like -1 to indicate that you can't go that direction. Basically the same setup/implementation of a table-based FSM.

I have a great book I got way back then that shows how to make text adventure games in BASIC. It was impossibly thin, pink and very simplistic. But, it explained all of the concepts very well and went from beginning to end with a complete game. In fact, it's probably had more of an impact on my game programming than any book since (hard to believe, huh?). When I get home I'll see if I can find it and I'll post a link...
A better design might include a linked list of pointers within your room structure to a structure with a pointer to another room and a label (such as north, south, east, west)

Then you just read out the list and output those as your possible room exits. This way you can have special names for certain rooms, or even entirely different directional exits (such as up, down, door, tunnel etc)

-M2tM
http://www.mutedvision.net
Hey, I just signed up for an account. Long time lurker, I'm a coop at EA right now.

That AP above was me. I actually meant a linked list of something like this:
struct RoomExit{  Room *exitTo;  string exitName;  //optionally some structure of exit abbreviations such as this:  list<string> exitAbbreviations;}

And then within your room class:
class Room{ public:    bool AddRoomExit(Room *exitTo, string &exitName, list<string> &exitAbbreviations);    bool AddRoomExit(RoomExit &exitToAdd);    ... private:    list<RoomExit> Exits;    ...}

AddRoomExit could check to make sure the room is valid and such. I offer the exitAbbreviations suggestion incase you have North West or something and want the user to be able to type nw instead. Of course you should have something which takes what they type and searches for a "closest match" but nw probably wouldn't be found by something like this unless you have a smart checker that looks for the first letters of all the words as well. I don't know how you want to handle this, so the exitAbbreviations should be up to you.

if you wanted to go based on room id instead of pointers to rooms, you could always have a search for room function that returns a pointer to a room with a specific id. A nice thing about this method is that you also have an easy and quick way to move your player through rooms based on pointers as opposed to having to search through a list every time you want to move to a new room just jump to the pointer instead of grabbing the id, searching for the index (unless you have them all in some giant array I suppose) and then setting your current room pointer to that.

Now, this depends on how you store your rooms. It really depends on how you want to do this. You could also do a database stored game with something like sqlite keeping tabs on your world info.

Good luck, I hope my first post here has been helpful.


*edit: Looks like KulSeran proposed a similar method. Sorry, I should have read all the responses first. In any case, I agree with him, that's your best choice.

[Edited by - M2tM on December 1, 2005 7:41:50 PM]
_______________________"You're using a screwdriver to nail some glue to a ming vase. " -ToohrVyk
Thanks guys! Nothing like a big slice of humble pie to kick-start my foray into serious program design ;)

Looks like I've got a lot to learn about good, effective design.
Deep Blue Wave - Brian's Dev Blog.
No problems. If you have any questions feel free to ask.

What are you thinking of in terms of your world object structure? How will your rooms be held? That's your next big question I think.
_______________________"You're using a screwdriver to nail some glue to a ming vase. " -ToohrVyk

This topic is closed to new replies.

Advertisement