• FEATURED

View more

View more

View more

Image of the Day Submit

IOTD | Top Screenshots

The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.

The 5millionth post on OO design principles..

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

52 replies to this topic

#41The_Minister  Members

Posted 01 January 2001 - 05:56 AM

Kylotan, modules are the way to go. Develop each part of your game separately and individualy, and join them together with the final game code when you finish them. While developing them, test them completely.

That way, no module ever gets too big, and if one module is starting to become truly massive, break it down into smaller modules.

This is, as I''m sure you know but for those who don''t, known as the test harness or ''testbed'' developing method.

The_Minister
1C3-D3M0N Interactive

#42Kylotan  Moderators

Posted 01 January 2001 - 07:51 AM

quote:
Original post by The_Minister

Kylotan, modules are the way to go. Develop each part of your game separately and individualy, and join them together with the final game code when you finish them. While developing them, test them completely.

That way, no module ever gets too big, and if one module is starting to become truly massive, break it down into smaller modules.

I wish it were that easy. My game is split into
142 source files (including 66 header files). Generally, it is 1 class = 1 source file + 1 header file, but some smaller classes are grouped together. Nearly all of my game data structures are STL containers of pointers to objects. Now, the main problem here, is that in order to use a container of pointers to type XYZ, that file needs the entire class definition of XYZ. It shouldn''t , but this is a template implementation limitation / STL bug. So, a lot of source files include headers that they shouldn''t need to, just so it will compile without errors.

Secondly, about 3 or 4 of these classes are so integral to the system, that nearly everything needs to include the header file. And these classes get added to on a fairly regular basis: it''s not bad design - it''s just iterative design If I wish to add a feature, generally one of the main 3 or 4 classes needs to get altered, which will result in having to recompile 60-80% of the code.

It isn''t a ''normal'' game where you could separate out a SoundFX module, a Music module, a GameWorld module, and so on. This is a text-based multiuser game which doesn''t lend itself too well to modularisation. It''s kind of hard to explain any better than that, since obviously any design can be well encapsulated, it''s just that this kind of program revolves around several important classes which change as the design progresses. (The game will never be ''finished'', it''s always in a state of evolution).

#43Wilka  Members

Posted 01 January 2001 - 09:17 AM

Kylotan:
quote:

Now, the main problem here, is that in order to use a container of pointers to type XYZ, that file needs the entire class definition of XYZ. It shouldn''t , but this is a template implementation limitation / STL bug. So, a lot of source files include headers that they shouldn''t need to, just so it will compile without errors.

What version of STL & compiler are you using? I always used forward declarations when I''m storing pointers in a container, and I''ve never had any problems. I normally use STLport, but I''ve just tried it with the default VC6 STL at it works fine. Borland''s compiler & STL also have no problems with it.

#44Facehat  Members

Posted 02 January 2001 - 06:09 AM

quote:

My whole project is now about 150.000 lines of code, about 1000 files and it re genereates an exe from scratch (compile,link with resouces add) in about 1 (ONE) second on a P2/400 computer

That''s great, but with incremental linking I only generally need to recompile one file when I''m going to run it, which means that I can compile and run my stuff in about 1 second, as well.

Besides, I actually like the wait between compiles. It gives me time to think about what I''m going to do next and what I should perhaps change.

quote:

dont forget its all about SPEED in games....(think at AI, GFX)

Speed is actually one of the lesser things on the list of importance. Obviously, you don''t want to write bloated software, but you should always put robustness, maintainability, and functionality first.

quote:

today most "optimized" compilers only make about 100% up to 300% slower programs then ASM

Can you actually back that up with some proof? I''ve never seen anything near the stats you''re mentioning.

quote:

If the OOP ONLY disadvantages are (you say):
=============================================
1.slow
2.ineficient

=================
3. complicated

It''s only more complicated if you can''t design properly. OOP code is almost always simpler if it''s designed right, and generally much more robust (stable) as well.

quote:

Yes there are advantages to OOP but those are more likely to be used in database visual programming rather then fast games.

Are you kidding? Games are almost the perfect domain for object oriented programming. You''re creating worlds which contain, you guessed it, a lot of objects.

quote:

I just wanted to kindly say: take care OOP can ruin your game speed...and generated a flame...ooops...not my intention...but if u want i can give you more arguments....just dont think i have to...

Once again, can you actually back up that statement?

quote:

Yes ASM is much simpler than OOP
and OOP is very complex compared to ASM...

Assembly is simpler in that there is less to learn, but programming wise, it isn''t "easier". OOP is very simple in most respects. Which parts of OOP do you find to be "complex"?

quote:

I am not against OOP...just against too much OOP in games in every position...

You should always be consistent in your design. If you''re using different programming methodologies all over your source, it''s a sign of poor design.

quote:

I will just like to use my P3 like a P3 and not like a 286 because of slow OOP and people''s urge to finish a project faster with less work...

First off, that''s a giant exageration. OOP doesn''t kill that much speed (and if you want to argue that point, at least give some numbers from real projects to prove that, not just "well in my experience"). Second, what''s wrong with wanting to finish a project faster with less work? The quicker you can get something out, the better. If you want to spend fiveyears on a project in ASM only to have it dated by the time you release it, fine, but I''d much rather keep up with everyone else.

#45Anonymous Poster_Anonymous Poster_*  Guests

Posted 03 January 2001 - 01:40 AM

quote:
Original post by Wilka

What version of STL & compiler are you using?

MSVC5, with supplied Dinkumware STL, all publicly available STL patches applied. No service pack applied to MSVC5, since it doesn''t work on the ''cheap'' version.

quote:
I always used forward declarations when I''m storing pointers in a container, and I''ve never had any problems.

It gags on the destructors, because there is no explicit destructor defined for user-defined pointer types (ie. there is no MyType*::~MyType*() {} ). Errors in the destroy function in <xmemory> if my memory serves me correctly.

There are supposedly some workarounds available, including doing your own specialisation of the destroy function, etc etc, but I never found enough info on how to do that.

quote:
I normally use STLport, but I''ve just tried it with the default VC6 STL at it works fine. Borland''s compiler & STL also have no problems with it.

I can''t use STLPort, since my compiler chokes with a "Too many nested #IFDEFs" error. Probably because it''s the ''standard'' edition rather than one of the Big Money editions.

Borland C++ Builder 4 has exactly the same problem with the pointers in containers, as I tried it there with the same results. I don''t remember if I tried it with v5 or not.

Apparently it''s a common problem, since 1 or 2 STL sites have described it, and either suggested the explicit instantiation workaround, or the more fascist answer "don''t use pointers in containers: they''re not designed for it".

#46Kylotan  Moderators

Posted 03 January 2001 - 02:00 AM

The above post was me (Kylotan, in case it ignores my password again...)

#47furby100  Members

Posted 03 January 2001 - 02:38 AM

quote:
Original post by SiCrane

Well, when you come to the cloaked ship issue, there are a couple of ways to approach it. The first is to say that a cloaked ship is a special kind of ship. Another is to say a cloaked ship is a ship that has a cloaking device. So the choice becomes encapsulate or inherit.

A good combination of inheritance and encapsulation would be the following:
Every ship has an array of CModification, and there are a maximum amount of modifications. The CModification class would look somewhat like this:
class CModification{private:    char* name = NULL; // the name of the modification (for engineering    // displays and menus and suchpublic:    // constructor takes the name of the modification    CModification(const char* newname)    {        name=new char[strlen(newname)];        Initialise();    }    ~CModification()    {        delete name;        Destroy(owner);    }    virtual void Initialise();    virtual void Destroy();    virtual void AllocatePower(int amount);    virtual void Activate(bool activation = true);}

You would then have in the CShip class an array like this:
*CModification modifications[MAX_MODS];
and you could assign elements of this array to classes which inherit from CModification, and implement the pure virtual methods.

PS. What is this design pattern called? I see it often in Java games and the like.

''Smile, things could get worse.''
So I smiled, and they did.

#48Wilka  Members

Posted 03 January 2001 - 07:23 AM

You''ve a got a virtual function call in the constructor for CModification, it works in Java but it''s a no-no in C++. I realise it''s not real code cos there''s a few other things that won''t work, but virtual functions in ctor/dtor can lead to nasty bugs so I thought I''d mention it.

#49Succinct  Members

Posted 03 January 2001 - 09:30 AM

what about calling a super class''s virtual destructor from a subclass?

like

  class foo{protected: virtual ~foo() {};};class subfoo: public foo{public: ~subfoo(){ foo::~foo(); }};

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I have no name that you may call me. I am merely Succinct.
~Succinct Demos Online~

"Hey, where''d that display list rotate off to now?"
-(Drop me a line here)-

#50Wilka  Members

Posted 03 January 2001 - 12:37 PM

quote:

what about calling a super class''s virtual destructor from a subclass?

In that bit of code you posted, you''re not calling the function virtually so the function call is safe. But the fact that you''re calling the function isn''t safe. The destructor of base class is automatically at the end of the derived class dtor, so you''re calling it twice here which could make very bad things happen.

#51Succinct  Members

Posted 04 January 2001 - 02:32 AM

so when, say, the 5th subclass in an inheritance graph would call it''s own destructor when it went out of scope and then each of it''s superclasses would call theirs?

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I have no name that you may call me. I am merely Succinct.
~Succinct Demos Online~

"Hey, where''d that display list rotate off to now?"
-(Drop me a line here)-

#52Wilka  Members

Posted 04 January 2001 - 06:32 AM

quote:

so when, say, the 5th subclass in an inheritance graph would call it''s own destructor when it went out of scope and then each of it''s superclasses would call theirs?

Yep, classes a destructed it the opposite order of construction - including base classes. Try this program to see:

class Base{public:	~Base()	{		cout << "Base::~Base()" << endl;	}};class Sub : public Base{public:	~Sub()	{		cout << "Sub::~Sub()" << endl;	}};int main(){	Sub sub;		return 0;}

#53Shannon Barber  Moderators

Posted 09 January 2001 - 03:52 PM

furby100
quote:

A good combination of inheritance and encapsulation would be the following:
Every ship has an array of CModification, and there are a maximum amount of modifications
like a vistor, not exactly though

First I'd whack the stereotypicall array, and at least use a re-dimensionable one. In this case a linked list makes the most sense to me, becuae you'll have a fairly small indeterminet number of mods. Could be 4, could be 100. Array's would waste alot of space in over allocation. Also, you'll never need to access them by index, it's nearly uselss and provide no speed benefit. Most the time, you'll being doing complete iterations which is about the same speed for arrays as LL.
The pattern you describe is like a vistor, but not quite, you would eventually arrive at the visitor if you continued brainstorming. Pass a struct pointer (or an object) along for the MakeMod ride, to accumulate the result.

...
This thread fell off the OOD track

bogdanontanu even sounds like a troll name j/k
Abused OOD can have a catastrophic performance hit, and well tuned asm can run 400% faster on the machine its designed for.
But no one would ever OOD to the pixel level. You would never call a virtual function per pixel on the screen. That's a perfect example of misconstrued OOD. You could make the same mistake with asm, and call a bios routine to blit each pixel. My very first blitter worked this way
The difference would be a handfll of virtual function calls to one function call and a handful of array indexes. The array indexes are much faster than a virtual call, but not compared to the amount of work that needs to be done to render the scene.
On a modern machine a performance conscientious OOD will be 1-3% slower than a strictly procedural program.

If you can strip 400% more speed with asm when compared to C compiler, please go into the compiler business and help all the C programmers on earth as well as make a mint for yourself. A single properly coded asm routine might be 400% faster than a strictly C one, but the C coder could use your routine (as well as the C++ coder, or delphi coder).
So once that field has been leveled, your program is faster than most programs by deisgn implementation, not the constructs of the language you use. So you gain a significant level of speed in non-speed sensitive code, and a marginal level of speed in speed sensitive code.

An amateur with OOD is not much different than an amateur with asm. The problem is, if you're taking up OOD, you're no long an amateur coder. So you have a new learning curve to surf, and this is the serious problem many people have with OOD.
Why should I learn a new way to program? I can write programs now, that do exactly what I want them to!
And if that works for you then, no one's gonna change your mind, and they probably shouldn't!

I get pissed if I have to do the same thing twice. Special cases make for redundant code. OOD lets you handle all cases in a uniform manor.

The biggest problem with an all asm project, is that it won't run well on new processors. Go read about the pentium 4, and start crying, because you're hand crafted PIII optiized code is going to run slower on a higher clocked P4!!!

If you had written the speed critical section in asm, you would need only to add a method to determine the processor, and load the appropreiate routine. Then you only need to rewrite a small bit of code to acheive the greatest performance. I suppose you could leave the unoptimized sections of code alone, and just rewrite the speed critical sections, but now your asm project is slightly slower than a C one!
Now compare the 30minute rebuild to the daunting task of re-optimizing 150,000 lines. Of course I'd have to wait for a C compiler that supports the new processor... M\$ seems to lag behind a couole of years, Intel comes out with new ones faster.
I suppose its a moot point, because today's code on tomorrow's computer is gonna be waiting an eternity for the vsync anyway.
I have a funny feeling, you didn't use any threads. (Afterall, why would you use a thread, you can do everything with one!)

...
I almost forgot:
quote:

OOP also moves you away from the CORE of programming ...slowly moveing you to the USER side...

This could not be farther from the truth. If we were trying to use Director or power point to make a game I might agree. You can teach bateria how to add, but most people aren't capible of abstactly solving a problem in a procedural fashion - never mind an OO fashion.
The implementation can always be made more efficent.
An OOD *can* be implemented in C or even asm - as you have proven since you did use directX. C++, Ada, & smalltalk were made with OOD in mind, so they help automate the process and are more logical choices if you decide on an OOD.

Magmai Kai Holmlor
- The disgruntled & disillusioned

Edited by - Magmai Kai Holmlor on January 9, 2001 12:03:26 AM

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.