OO in C

M

Malcolm

I'm doing an adventure game.

Objects naturally lend themselves to C++, but I decided to implement the
thing in C.

The idea was that each object is identified by an id. These are stored in a
big array, indexed by id number.

To use an object, you convert the id to an OBJECT *.

typedef struct object
{
int id;
void * (*hasattribute)(struct object *obj, const char *name)
void *data;
} OBJECT;

Now the idea is that each object implements interfaces. So for instance a
sword would have the interfaces "ITEM" (it is a named item in the game),
"PORTABLE" (you can pick it up an carry it), and "WEAPON" (you can use it to
attack people with). You would set the hasattribute member to a function to
return these interfaces. So for instance "PORTABLE" has a member labelled
"weight", since all portable items weigh something.

One problem is that this rapidly gets ugly. For instance to get the weight
of a sword you would have to write

sword = getobject(swordid);
portable = sword->hasattribute(sword, "PORTABLE"):
if(portable)
sword->getweight(sword, portable);

Why is this necessary, since we are probably returning a single variable?
The answer is that a bag would weight the weight of a bag plus the weight of
any contents.

Another problem is that the attributes just represent interfaces, weapons,
containers, decorations, and so on. If I want a "dancing sword" then really
I want some type of inheritance to extend the "sword" code. However with the
current setup I don't have this. Instead I have to re-implement all of the
interfaces.

Has anyone any experience doing this sort of thing?
 
D

Dave Vandervies

I'm doing an adventure game.

Objects naturally lend themselves to C++, but I decided to implement the
thing in C.

The idea was that each object is identified by an id. These are stored in a
big array, indexed by id number.

To use an object, you convert the id to an OBJECT *.

Is there a good reason to not just store it as a pointer, rather than
as an index into a pointer table?

typedef struct object
{
int id;
void * (*hasattribute)(struct object *obj, const char *name)

I'm not sure why you're returning a pointer to void here. 'Tmight be
easier to do something like:

/*returns nonzero if we can get the value for this attribute*/
int (*has_attribute)(struct object *,const char *);
/*Returns the attribute value, appropriately encoded*/
MAGIC_COOKIE (*get_attribute)(struct object *,const char *);
void *data;
} OBJECT;

MAGIC_COOKIE can be anything that can represent all attribute values.
int might be a good choice if you're only doing numbers, pointer to static
string buffer ("extract the value of the appropriate type from this string
before getting another attribute") would be a good choice otherwise.

Now the idea is that each object implements interfaces. So for instance a
sword would have the interfaces "ITEM" (it is a named item in the game),
"PORTABLE" (you can pick it up an carry it), and "WEAPON" (you can use it to
attack people with). You would set the hasattribute member to a function to
return these interfaces. So for instance "PORTABLE" has a member labelled
"weight", since all portable items weigh something.

One problem is that this rapidly gets ugly. For instance to get the weight
of a sword you would have to write

sword = getobject(swordid);
portable = sword->hasattribute(sword, "PORTABLE"):
if(portable)
sword->getweight(sword, portable);

Why is this necessary, since we are probably returning a single variable?
The answer is that a bag would weight the weight of a bag plus the weight of
any contents.

'Tmight be easier to set things up so you can do:
--------
if(!(sword->has_interface(sword,"PORTABLE")))
/*Handle type error - we're trying to work with a nonportable sword?*/
if(!(sword->has_attribute(sword,"weight")))
/*Handle internal error - claims to be portable, but has no weight?*/
/*the above code is just internal consistency checking, these two lines
are all that's really needed
*/
my_cookie=sword->get_attribute(sword,"weight")
weight=unpack_weight_cookie(my_cookie);
--------

Then the sword's get_attribute function, if it's asked for weight, can
just do "return ((sword_data *)(obj->data))->weight" (optionally packing
it into an appropriate magic cookie first), and the bag's get_attribute
function can walk through the collection of stuff in the bag and return
the sum of the weights.

Another problem is that the attributes just represent interfaces, weapons,
containers, decorations, and so on. If I want a "dancing sword" then really
I want some type of inheritance to extend the "sword" code. However with the
current setup I don't have this. Instead I have to re-implement all of the
interfaces.

If you have a single pointer to get-named-attribute function, you can
write a new function that handles more attributes (optionally passing
existing attributes on to the existing function), add the appropriate
attributes to whatever your data pointer is pointing at, and just change
the get_attribute pointer you stuff into the struct when you create the
object. So your dancing sword object's {get|has}_attribute function can
check for the can_dance attribute, and if that's not the one the caller is
looking for pass the request on to the normal sword's attribute function.

If you really want to get clever, you can add attributes at runtime.
If the player learns how to control objects remotely, he can add a
remote_controllable attribute to his weapons.

Has anyone any experience doing this sort of thing?

See if you can find a Smalltalk implementor; this is beginning to look
not entirely unlike the Smalltalk dynamic dispatch system.


dave
 
R

Richard Bos

Malcolm said:
I'm doing an adventure game.

Objects naturally lend themselves to C++, but I decided to implement the
thing in C.

Do yourself a favour and use a specialised language. All the problems
you describe have already been solved. I recommend Inform.

Richard
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,146
Messages
2,570,832
Members
47,374
Latest member
EmeliaBryc

Latest Threads

Top