Please check out Otherworld, the land of Tirn Aill !

Member Discussions

terms



[Previous] [Next] [Post] [Reply] [Topics] [Summary] [Search]


1. Back To The Basics Thu Oct 4, 2007 [1:36 AM]
Schlittzer
Email not supplied
member since:
Reply
I'm trying to come up with a nice design to start things out, using C++.

I've read in a previous post, from a while ago, which I cannot find for the life of me, that a good way to design an "is a" diagram goes something like this:


//All things with names and
//descriptions
class Thing
{};




//All things that can move or
//somehow change location
class Mobile : public Thing
{};





//All things that cannot move
//or have no concept of location
class Immobile : public Thing
{};






//Objects in the sense of weapons,
//shields, rings, etc.
class Object : public Mobile
{};




//Things that run around!
class Creature : public Mobile
{};



Anyone have any thoughts? I've written
the Thing class so far, but I'm hesitant to proceed anymore. At the risk of revealing my poor style, I'm showing my "Thing.h" file, and I invite anyone to catch me before i shoot myself in my future foot. I'm trying to do this right, and I'm very juvenile when it comes to sliding back into procedural programming styles and forgetting about OO.


#ifndef THING_H
#define THING_H

#include <string>

using std::string;

class Thing {

public:

/* Constructors */
Thing();
Thing(string title, string d_desc);

/* Attributes */
string name(); /* a rock */
string description(); /* It is dark blue. */

/* Behaviour */
void change_name(string new_name);
void change_desc(string new_desc);

private:

string things_name; /* name */
string things_desc; /* description */
};

#endif /* THING_H */


2. RE: Back To The Basics Thu Oct 4, 2007 [2:23 AM]
Kuros
kurosknight@gmail.com
member since: Feb 28, 2000
In Reply To
Reply
Hmm. Where do Zones fit in there (or areas, whatever you want to call them. A collection of rooms.)

Or rooms? I assume they would be an Immobile, but then they could potentially be the same class as...I dunno, a giant statue that can't be moved?

I am not saying your hierarchy won't work, and it could just be a personal preference thing, but I prefer to divide stuff more along the lines of their...concepts, I guess, than what they can do. Quick summary of my hiearchy:

object (contains id num, name, desc)

Then these inherit from that:
Zone, Room, Character (NPCs and PCs), Portal (an exit).

Point being, I prefer my classes to apply to only one "thing". A room, a zone, a character, etc. I would think it would be difficult to write methods that would apply to both a room and a giant statue, maybe?

Also, what about an item that can move on it's own? Say, the aforementioned giant statue coming to life. Or a wizard casting an animate item spell and causing a chair to go on a homicidal rampage? You see how, conceptually, they change classes?

Anyway, just my thoughts, and like I said, it could very well be a personal preference thing.

Good luck!

-Kuros


3. RE: Back To The Basics Thu Oct 4, 2007 [5:20 AM]
KaVir
Email not supplied
member since: Aug 19, 1999
In Reply To
Reply
I use a similar approach in God Wars II, except without the Mobile and Immobile classes. This hierarchy is years out of date (I generated it near the start of the project and never bothered to update it), but you might still find it of interest:

http://www.godwars2.com/docs/projects/GodWarsII/project-tree.html

Creature, Object, World, etc, are all derived from the Thing base class, while HumanBrain, MobileBrain, WarBrain, etc, are all derived from the Brain base class. A Thing can have a Brain, which controls what it does.

A player therefore has two parts - a Creature and a HumanBrain. If the players drops link, their HumanBrain is destroyed but their Creature remains in the game. It's also possible for them just to have a HumanBrain without a Creature (although they can't interact with the game world, only chat and such).

A mob has a Creature and a MobileBrain. Their Creature is exactly the same as that of a player, but their MobileBrain sends the commands. If an admin wants to switch into a mob, the mud simply disconnects the MobileBrain from the mob and then connects the admin's HumanBrain.

A sword has an Object but no Brain, therefore it doesn't do anything on its own. If you wanted an "animate sword" spell, you'd need to create some sort of "AnimatedBrain" which you could connect to the sword.

The game world is a World object with no Brain (although arguably the weather might have been better implemented as a WeatherBrain). Each World keeps track of its own zones/areas.
God Wars II: http://www.godwars2.org (godwars2.org 3000) Roomless world. Manual combat. Endless possibilities.
MudLab: http://www.mudlab.org


4. RE: Back To The Basics Thu Oct 4, 2007 [7:00 AM]
shasarak
Email not supplied
member since: Dec 10, 2004
In Reply To
Reply
KaVir brings up an important fundamental point which is: don't make the mistake of assuming that something which a player of the MUD would describe as "an object" must necessarily be represented by a single "object" in the programming sense of the term.

For example, consider a torch. There might reasonably be a class called Torch which inherits from a class called MUDLightSource, that has other subclasses such as Lantern. Potentially things like the brightness of the light could be dealt with in the MUDLightSource class.

So far, so good. But now, suppose you want to introduce a flaming sword: like a torch, it can also emit light on demand. Is it reasonable to have a flaming sword be a subclass of MUDLightSource? Well, perhaps; but it's also got to be a subclass of LongSword, which is a subclass of Sword, which is a subclass of Blade, which is a subclass of Weapon - and it definitely wouldn't be healthy for Weapon to be in the same part of the class hierarchy as MUDLightSource.

You could get around that by using multiple inheritance, of course; the flaming sword might inherit from both LongSword and from MUDLightSource (although emphatically not directly from Torch or Lantern!). However, what now happens if we want to introduce a light spell to the game, which you can cast on any object and cause it to emit light? Now you have a situation where, if you use inheritance, every object in the game would have to inherit from MUDLightSource, even though the vast majority do not emit light at any given moment. Clearly that's a hopeless idea.

So the solution is not to have every object inherit from MUDLightSource, but to add a class that deals with light emission. Let's call that a LightHandler. This is not at all the same thing as a MUDLightSource: a MUDLightSource represents a physical MUD object that is designed to emit light, such as a torch or a lantern. A LightHandler is a purely programmatic object that models attributes of light emission. Any given class that inherits from MUDLightSource will, when lit, create an instance of LightHandler (or a subclass) to model the light's behaviour. When the light is extinguished, the LightHandler will be destroyed. Similarly, a light spell cast on something that is not normally a light source creates a new instance of a LightHandler and associates it with the object for an appropriate period of time. The code associated with the target of the spell doesn't need to know about this; it doesn't even need to know that there are such things as light spells.

So, each "physical" MUD object should probably have a linked list called (e.g.) properties. Each entry in the list is a key pointing to a collection. Suppose some code needs to iterate over all the objects in a player's inventory and figure out which ones emit light, and work out the total brightness. It asks each object in turn "do you have a property called lightHandlers?" If the object is not currently emitting light, it won't have a lightHandlers property at all, and will return null. If it is emitting light, then the object returns a collection of all of its active LightHandlers. Each one can then be queried for (e.g.) the brightness of the light it is emitting, and all those values can be added up.

Why would the lightHandlers property be a collection? Because potentially an object could be emitting light for two different reasons at once, for example if you cast a light spell on an already lit torch.

Once you start to think about this kind of system - a combination of dynamic property obects and multiply-inherited abstract superclasses - you should be able to move towards the ideal of having one class per type of behaviour. You should never be afraid of using lots of small classes so long as the aspects of behaviour they are modelling really are discrete.

Two final examples:

1) If orc and troll are different player races, you probably shouldn't have classes OrcPlayer and TrollPlayer that both inherit from Player. Instead a player will have a body property, and the body object might perhaps be an instance of either Troll or Orc. Or perhaps Body is also a separate class, which has a property called "race", which in turn points to an instance of Orc or Troll.

2) The code that handles fire damage probably should not be in the same class as the code that represents a fireball spell. A possible model would be:

A FireBall spell, if cast successfully, creates an instance of FireEffect. This checks for things like, are we in a sanctuary room (so the attack is disallowed)? Are we underwater? Etc.

If the attack is successful, the FireEffect then creates an instance of another class called FireDamage whose function is to inflict fire-based damage on a target. The FireDamage object then interrogates the target to see if it has any properties that influence damage sustained by fire. (For example, if the target is wearing fire-resistant armour then the action of wearing the armour will have a created a FireResistance object that was added to the wearer's list of properties). Eventually the FireDamage figures out how many hitpoints the target has lost, and informs it of this. The target object then figures out how to deal with the hitpoint loss (e.g. should it die?)
Please do not feed the troll.


5. RE: Back To The Basics Thu Oct 4, 2007 [10:33 AM]
Schlittzer
Email not supplied
member since:
In Reply To
Reply

A player therefore has two parts - a Creature and a HumanBrain. If the players drops link, their HumanBrain is destroyed but their Creature remains in the game. It's also possible for them just to have a HumanBrain without a Creature (although they can't interact with the game world, only chat and such).

A mob has a Creature and a MobileBrain. Their Creature is exactly the same as that of a player, but their MobileBrain sends the commands. If an admin wants to switch into a mob, the mud simply disconnects the MobileBrain from the mob and then connects the admin's HumanBrain.


Nice. I like it.


6. RE: Back To The Basics Thu Oct 4, 2007 [10:37 AM]
Schlittzer
Email not supplied
member since:
In Reply To
Reply
Whew! I need to give this further thought clearly.

And as for your initial statement:


KaVir brings up an important fundamental point which is: don't make the mistake of assuming that something which a player of the MUD would describe as "an object" must necessarily be represented by a single "object" in the programming sense of the term.


Don't worry, I made that mistake before. The code turned into spaghetti very rapidly. :(


7. RE: Back To The Basics Thu Oct 4, 2007 [11:02 AM]
shasarak
Email not supplied
member since: Dec 10, 2004
In Reply To
Reply
Schlittzer:
> Whew! I need to give this further thought clearly.


I'll give you a one-line summary. :-)

"Don't ask what a class should be, ask what it should do."
Please do not feed the troll.


8. RE: Back To The Basics Thu Oct 4, 2007 [1:52 PM]
Schlittzer
Email not supplied
member since:
In Reply To
Reply

Hmm. Where do Zones fit in there (or areas, whatever you want to call them. A collection of rooms.)


They don't fit into this tree currently.

Assuming that I, somewhere down the road, have defined something like:


class Room : public Immobile 
{};


I'm guessing I will eventually have something like:


class Zone
{
   std::list<Room> room_list;
};



Point being, I prefer my classes to apply to only one "thing". A room, a zone, a character, etc. I would think it would be difficult to write methods that would apply to both a room and a giant statue, maybe?


I agree. I think that I should re-word my description of what I mean by the Mobile class.

I think it would be better described as the subclass of 'Thing's that have some concept of 'location'.

So whether or not they CAN BE moved, doesn't solely determine whether or not they are Mobiles or Immobiles.

Examples:

a statue - Mobile (Since it has a location.)
a room - Immobile (Since it could be thought of AS a 'location'. I better be careful here since I haven't precisely defined what a 'location' is.)

squirrel - Mobile
sword - Mobile

Any additional thoughts?


9. RE: Back To The Basics Thu Oct 4, 2007 [2:45 PM]
sandog
Email not supplied
member since: Jan 20, 2002
In Reply To
Reply


Point being, I prefer my classes to apply to only one "thing". A room, a zone, a character, etc. I would think it would be difficult to write methods that would apply to both a room and a giant statue, maybe


That's the whole point of OOP as well. When you evaluate your design looking for a potential object you ask the two important questions, what is it and what should it do - "Is A and Has A". The same applies here, what does a room and statue do and if they share commonality that should be refactored into a base class.

To accomplish "writing a method that applies to both a room and a giant statue" would be just a matter of making a common method in the base class and marking it virtual. To use a simplified example, all animals speak, but each one speaks a different way: dogs bark, cats meow, birds chirp, etc... So an animal base class would have a virtual Speak method which could be overriden by derived classes to provide functionality specific to that particular animal. In this example the object "Is A" animal and it "Has A" speak behavior.
I know what your thinking, "Why didn't I take the blue pill?". - Cypher, The Matrix


10. RE: Back To The Basics Thu Oct 4, 2007 [3:40 PM]
Kuros
kurosknight@gmail.com
member since: Feb 28, 2000
In Reply To
Reply
To Sandog:

I wasn't referring to the technical difficulty of writing a method that both could use. I meant more along the lines that they shouldn't both be in the same class (and thus have the same methods).

For example, my room class has an addCharacter() method, which adds a player reference to the room. Using the OP's original hierarchy, the statue would also have that method, which would be pointless. And it isn't logical to have statue be a subclass of room, or vice versa.

Upon reviewing my post, I am afraid I didn't explain that very clearly, heh. Apologies.

To Schlittzer:

That looks better. However, a room also has a concept of location, since it exists at a specific point within the zone. It just seems to me that using the concept of location as the distinction between your classes doesn't work very well.

You can't just define an object by what it "does". That's like trying to describe a bicycle by saying "you push something with your feet and it moves".

You have to take into account passive attributes about a thing. A bicycle has two wheels, it has pedals, it has handlebars, etc.

To me, to get subclasses of Thing, it makes more sense to ask questions like...

Can the item be worn? (WearableItem class?)
-Contains armor value and/or effects, whatever
Can the item be wielded as a weapon? (Weapon class)
-Has a damage value, etc
Is it a scenery item? (Like the giant statue example)

I'm not saying that is the correct method of designing a class hierarchy, but doing it like that (asking questions more relevant to their function than "does it have a sense of location"?) seems more logical.

-Kuros


11. RE: Back To The Basics Thu Oct 4, 2007 [5:14 PM]
Schlittzer
Email not supplied
member since:
In Reply To
Reply

For example, my room class has an addCharacter() method, which adds a player reference to the room. Using the OP's original hierarchy, the statue would also have that method, which would be pointless. And it isn't logical to have statue be a subclass of room, or vice versa.


I disagree. I hadn't defined exactly what a room or a statue would be yet. I had only conjectured that they would both be in some subclass (not necessarily the same one!) of Mobile.


You can't just define an object by what it "does". That's like trying to describe a bicycle by saying "you push something with your feet and it moves".


I'm not sure I get your simile.


a room also has a concept of location, since it exists at a specific point within the zone
<blockquote>

I think of a room's location within a zone as more of an 'index' than a physical manifestation of space, the latter of which is how I think of location in terms of an object within a room, or a creature within a room.

I see what you're saying though, and this is exactly why I'm pretty tentative about using the word 'location' at all.

To me, to get subclasses of Thing, it makes more sense to ask questions like...

Can the item be worn? (WearableItem class?)
-Contains armor value and/or effects, whatever
Can the item be wielded as a weapon? (Weapon class)
-Has a damage value, etc
Is it a scenery item? (Like the giant statue example)


Yes. You're right. And that's the fun part. But I'm just simply not there yet. Many of the concepts you listed above share functionality. A WearableItem class would have some common functionality with a Weapon class. Likewise with a scenery item. They all have a concept of location, and can occupy space and two out of three of them can be carried, whereas the third one cannot. This suggests to me that there is some more 'in-between' subclasses that have yet to be pinned down.

Anyways, I thank you for the thought-provoking feedback as it is forcing me to think about these things even more. I welcome further suggestions, and hopefully I can get a revised hierachy soon.


12. RE: Back To The Basics Thu Oct 4, 2007 [9:37 PM]
Kuros
kurosknight@gmail.com
member since: Feb 28, 2000
In Reply To
Reply
Schlittzer said:


I disagree. I hadn't defined exactly what a room or a statue would be yet. I had only conjectured that they would both be in some subclass (not necessarily the same one!) of Mobile.


I stand corrected then. =) I thought you meant they would both be in the same class.

Schlittzer said:


I'm not sure I get your simile.


That was in response to Shasarak's statement that when designing classes, you should think about what they do, not what they are, a philosophy I disagree with.

It is difficult to describe things by what they do. Take anything you could represent as a programming object, and try to define it just using methods (how we programmers model what things can do).

A bike might have pedal(). Or turn(). But it tells you nothing about what color it is, if it has training wheels, what size it is, etc.

Try to define a warrior like that. attack(), retreat(), etc. But what about his HP, his race, etc? None of those are what he can do, but are things that he is. Much like what Sandog said earlier.

Opinions will vary, of course, but x IS A y and HAS A z is a much better way of looking at it, is all I meant.

Schlittzer said:


Yes. You're right. And that's the fun part. But I'm just simply not there yet. Many of the concepts you listed above share functionality. A WearableItem class would have some common functionality with a Weapon class. Likewise with a scenery item. They all have a concept of location, and can occupy space and two out of three of them can be carried, whereas the third one cannot. This suggests to me that there is some more 'in-between' subclasses that have yet to be pinned down.


Yes, there will probably be quite a few subclasses, as no class can define everything in a MUD and still be useful. That depends on your design, of course. I only have Object, Zone, Room, Item, and Character classes. I know some people who have 100+ classes. Both work fine.

Anyway, best of luck to you on figuring all that out!

-Kuros


13. RE: Back To The Basics Fri Oct 5, 2007 [3:56 AM]
shasarak
Email not supplied
member since: Dec 10, 2004
In Reply To
Reply
Kuros:
> That was in response to Shasarak's statement that when
> designing classes, you should think about what they do,
> not what they are, a philosophy I disagree with.


Hmm. This is a classic "Shasarak misunderstanding scenario" caused by me overestimating other people's perception of what is a normal level of intelligence. ;-)

The suggestion that a class is not allowed to have properties or data, only methods, is so mind-bendingly stupid that it would never occur to me that anybody could possibly ever say that; consequently it would never occur to me that anybody could possibly interpret anything anybody ever said as meaning that, because it should be obvious that no one would ever say anything that dumb; so I didn't feel it necessary to clarify that this wasn't what I meant. I guess if you're used to people saying incredibly stupid things that's a reasonable interpretation. :-)

Anyway, my focus was more on not trying to do too much with one class. If you start thinking in terms of classes directly representing individual physical MUD objects, you're likely to run into this problem. For example, the MUD might have dogs, cats, lizards and kangaroos. If you think purely in terms of what "what is a lizard?", "what is a kangaroo?" you will end up having a single Kangaroo class that inherits from Marsupial, which inherits from Mammal, etc.

That's probably not the best way to do it. Instead, a kangaroo in the game is likely to be made of several aggregated and several inherited classes. In KaVir's approach, for example, KangarooBody and KangarooBrain are two separate classes. In my light source example, a Torch inherits from MUDLightSource but the handling of the light is delegated to a LightHandler.

When deciding what should be one class and what should be several (or parts of one class rather than several distinct ones), you should ask "What is the function of this class? What task, in programming terms, is this class intended to perform?" Generally it should be one task per class; and the class is given the data and methods that are necessary to perform that task.
Please do not feed the troll.


14. RE: Back To The Basics Fri Oct 5, 2007 [5:22 AM]
Kuros
kurosknight@gmail.com
member since: Feb 28, 2000
In Reply To
Reply
-apologizes to the OP for the brief thread hijack-

To Shasarak:

If this happens often enough for you to name it and/or consider it classic, perhaps that should be a hint as to something. =)

You would be amazed at some of the stupid things I hear day in and day out. My only contact with other programmers are primarily through these forums, and one or two others. In general, though, I prefer to take people literally unless I know them. I get in more trouble assuming people know more than they do, than just taking what they say to be what they mean. I just adjust my opinion of their intelligence based on their clarification.

In any case, I certainly agree with yer clarified statement!

-Kuros


15. RE: Back To The Basics Fri Oct 5, 2007 [6:21 AM]
shasarak
Email not supplied
member since: Dec 10, 2004
In Reply To
Reply
Kuros:
> If this happens often enough for you to name it and/or
> consider it classic, perhaps that should be a hint as to
> something. =)


Well, I know, it's because I consistently underestimate just how much more intelligent I am than everybody else. ;-)

(giggles inanely)

Okay, enough. :-)


Original Poster, one class you might consider having fairly high up the hierarchy is Container - that is, an object that can contain other objects inside it. Subclasses would include not just small objects like sacks and baskets, but also things like rooms (which contain all of the objects in the room) and potentially even zones (which contain rooms) and the world (which contains zones).

If you think of the world as a container of zones and a zone as a container of rooms then it follows that your mobile/immobile distinction (in the sense that you are now using it to mean "something that has a location" or "something that doesn't have a location") is no longer really valid for anything except the world, because even rooms now have a location: inside their parent zone.

Rooms probably also have a location in a Cartesian sense too. Suppose you have a remote tracking spell which tells you in what direction a remote object is.

Player types:

cast 'remote location' fire sword

and the game responds:

You sense there is a fire sword to the north east of here.

Now, it may or may not be possible to find out which nearby room contains a fire sword; but how do you know whether that room is to the north or to the south if it's more than a couple of rooms away? Easiest thing is to give each room some coordinates in Cartesian space so that you know whether any given location is "north", "south" or whatever.

This, of course, all presupposes that an object's location is primarily defined by its room. Not all MUDs work like that; some give every object its own position in world space. This can work quite well for outdoor areas; when checking for objects to include in the local description you ask not "what objects are in the room?" but "what objects are within (say) 50 feet of the player?"

Or alternatively you could have a system where each enclosed region is regarded as its own separate cartesian space. Each object then has a reference to which space it is in, and also to its position within that space. You can then set up explicit portals between spaces (e.g. doors and windows) which allow movement from one space to another and also line-of-sight calculations.

So, within a room, the player can see not just the contents of the room, but also what is outside the window. This includes an authentic calculation as to how much of the outside world is visible through the window, which will depend on where in the room the player is standing. So, if he opts to go over to the chest in the corner to search it, this will change whether or not he can see the roses in the garden outside.

Player:

look

Game:

You are standing in the middle of a dusty room with bare wooden flooboards. Through the window on the south wall you can see bright green grass. In the northwest corner of the room is an ancient, ornate chest.

Player:

examine chest

Game:

You walk over to the chest and examine it. The chest is locked with a black iron padlock.

Player:

look

Game:

You are standing in the northwest corner of a dusty room with bare wooden flooboards. Next to you is an ancient, ornate chest. Through the window on the south wall you can see bright green grass and pink roses growing up a trellis to the side of the window.

And so on.

Deciding how your position-system is going to work is probably something you should do fairly early on, because it has a lot of knock-on effects. For example, are you going to have a combat system? If so, do you plan to have ranged attacks (e.g. the use of bows and arrows, or firearms) as well as hand-to-hand fighting? This can be tricky in a room-based system. Are you going to allow players to shoot targets in adjoining rooms? If so, how can they see that the target is there if they can only see things in the current room? If you can only shoot things in the same room as you, how do you distinguish between something that's within sword-reach and something that's over the other side of the room?
Please do not feed the troll.


16. RE: Back To The Basics Fri Oct 5, 2007 [12:24 PM]
sandog
Email not supplied
member since: Jan 20, 2002
In Reply To
Reply


I wasn't referring to the technical difficulty of writing a method that both could use. I meant more along the lines that they shouldn't both be in the same class (and thus have the same methods).

For example, my room class has an addCharacter() method, which adds a player reference to the room. Using the OP's original hierarchy, the statue would also have that method, which would be pointless. And it isn't logical to have statue be a subclass of room, or vice versa.


Yes, I agree. In the point you make we can ask the two questions, IS A, and HAS A. Is the Statue a room? No. Does a statue have a room? No. Does a room have a statue? potentially, yes. So there we go, now we know that a statue should not inherit from a room but a room may contain a collection of statues. I think someone before pointed it out (it was probably you Kuros and I'm to lazy to read back through the thread) that if you determine x IS A y and HAS A z you will see the pattern revealed. This is a small example. It's really easy if you just follow those rules.
I know what your thinking, "Why didn't I take the blue pill?". - Cypher, The Matrix




[Previous] [Next] [Post] [Reply] [Topics] [Summary] [Search]