• entries
    503
  • comments
    1888
  • views
    333755

Forward =)

Sign in to follow this  

101 views

I find it funny that I thought there would be a time (notably after the finish of Morning's Wrath) that I would stop working on games, I have found that this simply won't be the case.

Not more than a week of being done with the development of MW, and already my mind is ticking once again =D

Of course there are things to be done with MW and that will come first, but I have had a little more time lately, AND I dont have that voice saying (finnish this game first!), so at the moment my thoughts are dwelling upon the next iteration of our game engine.

On sunday I did a bit of work on a prototype, it was for an 'object' class, and I implemented a system that I designed, I would have liked to use it in MW, but we know what happens to programmers that rip the engine apart at 3/4 development completion =)

The outcome of the protoype is an Object class and two MACROS,

DeclareObject(classname,superclass)
ImplementObject(classname)

these are used for subclassing object (which will be done a lot).

So what does 'Object' do you ask?

1. Robust type information

Object::getInstanceType() - returns a Type object of the objects true instance type.

Type t = obj->getInstanceType();

Object::getClassType - (static) returns a Type object of the class type.

Type t = SomeType::getClassType();

Object::instanceOf - hierarchy aware inheritence test

bool b = obj->instanceOf(obj2->getInstanceType());

Type::getName() - returns the string name of a type

std::string str = t->getName();

Type::getID() - returns the numerical ID of a type

unsigned long id = t->getID();

Type::forName(std::string name) - returns a type for a given string name.

Type t=Type::forName("SomeType");

Type::newInstance() - creates a new instance of the type

Object* obj= t->newInstance();



These features were priceless in the creation of Morning's Wrath, and unfortunetly had to be fullfilled in rather non-elegant ways. But now, I have a well developed solution!




2. Smart Pointers

To reduce the amount of pointer errors and to promote efficant use of memory I have constructed a Pointer object, which can be used as a real pointer, and supports reference counting.

It can be used a lot like a C# or Java pointer(object), in that it handles instantiation and copying and destruction properly, it will make programming in C++ somewhat easier I imagine.

The Source:

Pointer.h

#if !defined(POINTER_H)
#define POINTER_H

template <class T> class Pointer
{
public:
Pointer() {counter=0;}
Pointer(T* ptr) {counter=0; acquire(new Counter(ptr));}
Pointer(const Pointer& p) {counter=0; acquire(p.counter);}
T& operator*() {return *counter->ptr;}
T* operator->(void) {return counter->ptr;}
T& operator[](unsigned i) {return counter->ptr;}
~Pointer(void) {release();}
Pointer& operator=(T* ptr)
{
if(this->counter&&this->counter->ptr==ptr)
{
return *this;
}
acquire(new Counter(ptr));
return *this;
}
Pointer& operator=(const Pointer& p)
{
if(this != &p)
{
acquire(p.counter);
}
return *this;
}
private:
struct Counter{
Counter(T* p = 0){ptr=p;count=0;}
T* ptr;
unsigned long count;
}* counter;

void acquire(Counter* c)
{
release();
counter = c;
if(c)++c->count;
}

void release()
{
if(counter)
{
if(--counter->count==0)
{
delete counter->ptr;
delete counter;
}
counter = 0;
}
}
};

#endif




Examples of usage:

Pointer ptr;
//assignment from raw pointer(will release existing if applicable)
ptr=new std::string("omg cool!");
//increased reference
Pointer ptr2=ptr;
//indirection
std::string str=*ptr2;
//dereferencing
const char* cptr=ptr2->data();

//Array Usage
Pointer<int> intArray(new int[100]);

int i=intArray[20];




In short, it's fricken awesome =D


3. WTF? Why must you roll your own?

a. To learn and become a better programmer
b. It was not all that hard to build
c. Self written components cater directly and only to your needs
d. Rolling my own components hasn't caused me much harm yet (points to completed game) ;)

yay!
Sign in to follow this  


3 Comments


Recommended Comments

It is always a pleasure to view code written by well extablished individuals, to see their ideas and methodologies for adapting to the environment at hand.

Keep up the motivating work!

Share this comment


Link to comment
You and your darned reinvent the wheel syndrome! =P Use your time for NEW features instead! *rants* hehe

What's up with with the RTTI? What do you use it for? *curious*

hehe ;)

Share this comment


Link to comment
RTTI is a key part of serialization, and complex programming as a whole.

Serialization:

lets say i want to save an object and load it again later.

it is very important to save a description of exactly what type of instance the object was.

when you reload it, you need to look at the kind of instance it was and then be able to recreate it, without RTTI this is somtimes nearly impossible, or at least very hard.


example:

//Character extends Object
//Save
Character* ch=new Character();

ch->saveType();
ch->saveData();

//Load
Type t=loadType();
ch=(Character*)t->newInstance();
ch->loadData();


this way, an object can be remade perfectly without needing compile time knowledge of what type it was.


Other Stuff:

while most programing problems can be solved without RTTI, somtimes they are easier solved with it:


example:

for instance, say you had three types of item Potion,Spell and Weapon, and all inherited from Item.

when a character takes an item it is dumped into an array, which only assures type knowledge from Item and up.

if you need to know how many potions you have, you can itterate the list and use RTTI to determine if an Item is in fact a Poition, using instanceOf.

"But Raymond!" you say, "why not store potions,weapons and spells in thier own arrays!?", doing so would solve that problem, _however_ it can complicate other such things;

for instance, if you ever need to see if you are carrying a certain item you will have to itterate over three lists.

it also means that you cannot simply extend Item at will and allow Character to use it, a new array and a new set of accessors would need to be added, AND, this new array would have to be factored into all of the existing 'multi-array-checking' code, clearly a pain =)

There are of course even more solutions that can solve what i just proposed, but IMHO, the best solutions are the ones that dont cause the need for more solutions =) As long as RTTI isn't blatently abused it is perfectly fine, and useful.

and just so you know, the functionality of my RTTI was modeled after the JAVA functionality, since I found it to be a dream to work with =)



Share this comment


Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now