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_Htemplate <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 referencePointer ptr2=ptr;//indirectionstd::string str=*ptr2;//dereferencingconst char* cptr=ptr2->data();//Array UsagePointer<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!
Keep up the motivating work!