Skip to main content
GameDev.net gamedev.net
🔒 Locked

Singleton Refinement: Global Registry?

Started by Mithrandir Mar 28, 2001 at 10:23 AM 25 replies 1.4k views
Original Post
Mithrandir
Mithrandir
Okay, i''ve just recently got my hands on the design patterns book that all the software engineers rave about, and its quite an interesting read. I''ve developed on my own, or used several of the patterns defined in the book before i even knew they were actually documented somewhere (Specifically: factory method, bridge, iterator, adapter, strategy, etc) Now i read the pattern on Singletons, and it smacked me that they are a lot closer to describing the problem i have been trying to figure out for a while than what I have thought up on my own. However, there are a few issues with singletons that bother me, specifically while using subclassing. In my problem, i require a virtual object which can be switched at run time, but remain as a global singleton object. This would be useful for hardware engines (grapics, sound, etc) which are abstract, or for math engines which use a specific optimised sub-set of the current processor (3dnow, mmx, or sse). Of these modules, it would only be desirable to have one in use at any given time. The singleton pattern solutions for subclassing (since C++ does not support virtual static''s) strike me as hacks, almost. The first one explained in the book requires the base singleton class to be aware of every sub class singleton in the program. While not a large problem to a limited range program which will only use one or two specific modules, the problem appears when the client wants to modify an existing singleton and put it into a swappable external code module (such as a DLL). This would be impossible, obviously. This method also destroys object-oriented principles, as a base class should not know about it''s subclasses, and it would become a major detriment if the client is required to modify the base singleton everytime he/she wants to subclass it. There would be version control problems, and for a black boxed environment, this would be undesireable if you don''t want the clients modifying the base class. The second solution presented in the book would be to have every sub class add itself to the global static registry, but the problem with this would require every subclass to construct itself on initialisation, and a graphics engine should not be created more than once at the same time, thus making this solution unworkable, not to mention slow, as the instance operation would be required to search a registry list every time it wants to access a virtual singleton. And then there is the problem of initialisation variables. what if the virtual singleton requires class specific constructor variables? Surely we cannot expect the singleton base class to determine how a subclass is constructed. Say we have a user launcher, which takes start variables from the user (from a file, or an OS specific window which requests variables, etc) to create a graphics engine. What if one graphics engine needs to know how to initialise the backbuffer type, but another does not? This information is obviously best put into the constructor, and the user launcher would construct the object and pass it into the framework. This is impossible with singletons, as the constructors are protected. I propose then, that there be a modification of the singleton class, a so called Global Registry or accessor. This would allow the user to create a virtual singleton and pass it into the global instance reference, as we only want to access the ''current'' module at any given time. This also solves the problem of the client managing several sub-singletons and swapping them into the global instance whenever a change is required, instead of the instance method re-checking of a change needs to be made every time the instance is accessed. I realise this is not much different than using just a global pointer, and has no construction protection, but by using the instance method, global accessors can internally manage copies, whereas global variables cannot. Does this sound like a good idea? =============================================== Hurry up madness, hurry up disease, hurry up insanity, hurry up please. Hooray! I say, for the end of the world.
This is my signature. There are many like it, but this one is mine. My signature is my best friend. It is my life. I must master it as I must master my life. My signature, without me, is useless. Without my signature, I am useless.
Altair
Altair
Hi Mithrandir,

Best thing to do, is to avoid use of Singleton pattern completely. If it''s necessary, you can throw exception from the constructor, if it''s not allowed in current implementation to have more than one instance of a class, but it''s better not to expose that feature.

For example that graphics engine you mentioned; If you had one as a singleton, you couldn''t have several graphics engines running simultaneously. Anyway, if you would want to have several for some reason (for example, if you want to gain from multiple processors / video cards in your 3d modeller), you should build that feature inside your engine and explicitly use that, while without singleton and using proper design, it would be automatic.

I think it''s short sighted to use singleton pattern and it breaks the idea of object oriented design.

Cheers, Altair


"Only two things are infinite, the universe and human stupidity, and I''m not sure about the former." - Albert Einstein
"Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein
Mithrandir
Mithrandir
Well, okay, i admit that assuming only one module (as in the case of a graphics engine) could be used at any one time is shortsighted.

However, what about static virtual libraries? I have an idea of a math library which will be swapped at initialisation time, based on the properties of the processer. Such as a 3dnow ib, a mmx lib, or a sse lib, which all optimise the math functions based on the current processor, which obviously wont change during run-time and won''t require any changes.

The ideal would be to encapsulate this all into one swappable package, since i do not want to be distributing more than one executable (pain in the butt).

Since the math module is purely static, as it contains only functions and constants (Pi, E) but not modifiable data, the singleton seems to be closer to a solution than anything else, but i want to avoid the singleton problems as i''ve stated above.

===============================================
Hurry up madness, hurry up disease,
hurry up insanity, hurry up please.
Hooray! I say, for the end of the world.
This is my signature. There are many like it, but this one is mine. My signature is my best friend. It is my life. I must master it as I must master my life. My signature, without me, is useless. Without my signature, I am useless.
Altair
Altair
It''s not good idea to check platform in installation time, because people tend to upgrade their hardware and would be forced to reinstall your software.

What you should do, is to design abstract factory which exposes factory methods for specific mathematical components. For every platform which you like to support you implement this interface and pass the interface as argument to your main application. For example the interface might look something like this

class MathFactoryBase
{
public:
virtual MatrixBase *createMatrix(unsigned rows_, unsigned columns_)=0;
virtual PixelConverter *createPixelConverter(PixelFormat &source_, PixelFormat ⌖_)=0;
virtual FourierTransform *createFourierTransform(unsigned size_)=0;
};

Next you implement generic portable implementation of that interface so that you''ll always have fallback solution available. It''s also good reference implementation, which you can use to compare, that platform specific implementations also work properly.

class MathFactory: public MathFactoryBase
{
public:
MatrixBase *createMatrix(...);
... etc.
};

class MathFactoryMMX: public MathFactoryBase
{
public:
MatrixBase *createMatrix(...); ... etc...
};

In the beginning of your application you check the platform the application is running on and instantiate factory which fits to that environment.

switch (platform)
{
case Platform_MMX: m_mathFactory=new MathFactoryMMX(); break;
case Platform_SSE: m_mathFactory=new MathFactorySSE(); break;
case Platform_3DNOW: m_mathFactory=new MathFactory3DNOW(); break;
default: m_mathFactory=new MathFactory();
};

When the selection has been made, in the main application you just build appropriate math components by using the factory.

void playGame()
{
MatrixBase *matrix=m_mathFactory->createMatrix(4, 4);
matrix.read(array);
...etc
};

The playGame() is completely portable and doesn''t know anything about the platform it''s running on. It just uses those base classes created by factory methods.

Cheers, Altair


"Only two things are infinite, the universe and human stupidity, and I''m not sure about the former." - Albert Einstein
"Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein
Mithrandir
Mithrandir
So, instead of assuming only one library in use at any given time, i should instead use a factory to create the needed modules and pass them into the game engine?


interesting. I''d need to work on a method of easily finding out which math engine to use in the sub-modules, since i really don''t want to pass in a math engine for every function call which may use math.

===============================================
Hurry up madness, hurry up disease,
hurry up insanity, hurry up please.
Hooray! I say, for the end of the world.
This is my signature. There are many like it, but this one is mine. My signature is my best friend. It is my life. I must master it as I must master my life. My signature, without me, is useless. Without my signature, I am useless.
Altair
Altair
You should pass the abstract factory to the game engine, not modules created by it, because then you would end up to development nightmare (every time you need new object, you should create it in non-portable part of code). That''s why the factory is abstract after all.

And of course you instantiate factories only once when your application starts (nothing of course prevents you from instantiating more), with that kind of switch-case piece of code I gave. Then you pass those abstract interfaces to your game engine (in a struct of pointers to abstract factories if you like).

For classes, which need factories to create objects, you can pass abstract factory interface(s) as construction argument to the class, save it as member variable, and only access it from methods which need it. Another way is to have that collection of abstract factories globally available in a namespace, but that''s less flexible approach.

I have been using this approach in my 3d engine, and it has been working great. One important thing you should consider is heavy use of smart pointers, because otherwise you may have resource leaks if you don''t release objects created by factories. Also the exit points in your apps would have great piles of deletes without smart pointers, not to mention what kind of code the exception handling would force you to write (:

Cheers, Altair


"Only two things are infinite, the universe and human stupidity, and I''m not sure about the former." - Albert Einstein
"Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein
Mithrandir
Mithrandir
I suppose my real problem is accessing the dynamic strategy library, because each module in the game is independent of the actual game (mediator+composite pattern, i think), and thus won''t have access to the game.


should i just make each module contain a pointer to the strategy, and pass in each strategy to each module upon creation?

===============================================
Hurry up madness, hurry up disease,
hurry up insanity, hurry up please.
Hooray! I say, for the end of the world.
This is my signature. There are many like it, but this one is mine. My signature is my best friend. It is my life. I must master it as I must master my life. My signature, without me, is useless. Without my signature, I am useless.
Altair
Altair
Sorry, I''m really lousy with these pattern names. I should probably read Design Patterns through again (:

Anyway, as I said, you could have global instance of structure (not in game, but in general library) with group of pointers to abstract factories, which you setup in your game. However, this is not very flexible solution.

I think it''s better to pass reference of a abstract factory to modules, which need it. In practice, you don''t need to pass those factories to many modules. You can also combine functionality of modules and factories in some cases; For instance in my gfx engine, I can create platform dependent 3d object instance from platform dependent primary surface, so primary surface works as abstract object factory, but also provides primary surface specific functionality (such as page flipping).

Cheers, Altair


"Only two things are infinite, the universe and human stupidity, and I''m not sure about the former." - Albert Einstein
"Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein
Houdini
Houdini
quote:
Original post by Altair

Best thing to do, is to avoid use of Singleton pattern completely. If it''s necessary, you can throw exception from the constructor, if it''s not allowed in current implementation to have more than one instance of a class, but it''s better not to expose that feature.

For example that graphics engine you mentioned; If you had one as a singleton, you couldn''t have several graphics engines running simultaneously. Anyway, if you would want to have several for some reason (for example, if you want to gain from multiple processors / video cards in your 3d modeller), you should build that feature inside your engine and explicitly use that, while without singleton and using proper design, it would be automatic.

I think it''s short sighted to use singleton pattern and it breaks the idea of object oriented design.




Altair, I can''t say I agree with you, although you have an interesting argument.

I can see your point with the graphics engine, but that seems to be overkill. Why take all of that extra time and effort design your code to work with such an obscure feature that you''ll probably never use? I mean, if I decided to design my engine to use every possible remote feature I could think of I''d never finish it.

For some things I definately agree with designing for the future. For example, for most of my games I attempt to follow a client/server architecture even if it isn''t a multiplayer game. However, making it multiplayer is a feature I could see me wanting to implement in the future, so I design my game with that in mind. But multiple simultaneous video card support...?

Singletons make sense because you can force a variable amount of instances (or just 1) of the class, yet you can very easily (just a few lines of code) converted that class back to a normal one.

Using Singletons also means you don''t have to create global variables, thus polluting the name space.


- Houdini
Houdini
MetalicFog
MetalicFog
There is a C++ idiom called "enevelope-letter" or something like that (Coplien). Using this you can use both the factory method and the singleton class to generate effects that you are talking about. Basically you define a singlton class which has as its member a pointer to the base class of your strategy object. Then you can use the factory method to dynamically change the behavior of the strategy object during run-time.
Altair
Altair
Houdini,

It''s in no way overkill, since you don''t need to do any special design for having multiple engines running simultaneously. Instead, if you use singleton pattern, you explicitly expose that you are using that specific pattern. See my point?

It''s alot harder to try to later remove some specific feature (such as use of singleton pattern) from the engine, than add it. If you create your gfx engine with getInstance() or similar STATIC function, what if you call that from several places? You expect first, that all the calls return the same instance, but when you change the behaviour so, that it can return multiple instances, you are in deep shit.

So, how do you expect to instantiate proper engine in getInstance()? Because that function needs to be abstract, e.g. it may not be specified in any specific gfx engine, you need to have some selection code globally available. Maybe it''s in the base class? That''s probably the worst place for selection code to be placed, because selection of gfx engine is definately application specific feature (for instance some application may be dx8 only, or in some other app user can select the engine). Also base class shouldn''t know anything about derived classes. It''s also possible that you want to gain from some gfx engine specific feature, which can''t be exposed in abstract interface (such as pixel shaders), and make your application dx8 specific.

Nature of object oriented programming is, that you have a class and you can make several instances of that class. Singleton pattern efficiently break that and fixes a point in your application making it inflexible.

I don''t see your point about polluting the global namespace. I suggested, that required abstract factories should be passed as arguments, because it makes things more flexible.

It''s always good to have your design open ended for later extensions, _because_ you can''t possibly know what kind of extensions you''ll later need. Having your code flexible is very good aim to have in your design, because it makes you prepared for such changes you don''t know beforehand. And I''ll say it again: Singletons efficiently fix your code and makes it inflexible.

Every static declaration is like one new nail to your chest

Cheers, Altair


"Only two things are infinite, the universe and human stupidity, and I''m not sure about the former." - Albert Einstein
"Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein
Houdini
Houdini
Altair,

I see your point with the GetInstance() function needing to be replaced. You''d either need to replace it with a global variable (easy, but a nasty hack) or pass a pointer of an instance to that class to save for later use. Obviously this creates a lot of extra work to fix, which is your main reason for not using the Singleton, right?

Well, this also works the other way. What happens when you realize you need to access to class G (that will only ever have one instance) from class F? Well, you need to pass a pointer to an instance of class G to class F. Sounds easy enough.

But what class F class is a member of a parent class E? Now you have to pass the pointer class E, which would pass it to the child F. What if class E is a child of D, which is a child of C, which is a child of B, and so on? Then you have to keep passing this variable through all these classes that care nothing about this instance, until the child class finally gets a hold of it. Not only is this a lot of code change, but every single one of those parent classes are now dependant on that class you need the instance of. This create a lot more code just to type, extra code to keep compile times down, and it hurts reusability in your classes (the more classes one class is dependant on, the less reusable it is). Had you used a Singleton you could have done this in one line of code.

There is also the issue of when you want to create a library where the user shouldn''t need to be aware of the innards of the library to use it. Although this isn''t the best example, let me show you the problem I ran into not too long ago:

My GameEngine project contains an Entity (world object) class. For entities to be able to receive events, they need to register themselves with the EventServer class.

Because there will only be one instance of EventServer running inside the engine, I could make it a Singleton, and in the constructor of the Entity register itself to the EventServer automatically. All the game programmer has to do in the game source to create an Entity and have it automatically added into the world is create the instance of both the engine and the entity:

  
GameEngine *pGameEngine = new GameEngine;
Entity *pEntity = new Entity;


The programmer using my library wouldn''t need to know about the EventServer class to create an object in the world. Nor should he know about it, since he wont be using it directly.

But, if my EventServer is not a Singleton, I have a bunch of steps to do. I have to retrieve a pointer to the EventServer that my game engine created behind the scenes (once again more dependancies). I need to keep this pointer in my game class for use whenever I create entities. Then, when I create one I need to pass a pointer to that EventServer so the entity can register itself.

  
GameEngine *pGameEngine = new GameEngine;
EventServer *pEventServer = pGameEngine->GetEventServer();
Entity *pEntity = new Entity(pEventServer);


To me this just doesn''t make sense to do.

I don''t know, maybe I hadn''t thought of something and you can help me figure out a way passed this problem. I''m off work now, so I''ll check back tomorrow.


- Houdini
Houdini
Altair
Altair
Houdini,

GetInstance() is similar nasty hack as global variable. It just happens to be in classes namespace, just like a global variable can be in any namespace. Both are static, while GetInstance() just happens to be function, which can''t be overridden, hence it can''t provide regular runtime polymorphic properties as normal class methods.

The example you gave about dependency chain might happen if there is no sense how you design your object hierarchies. It''s not fool proof solution, but that''s the price you have to pay for flexibility. Otherwise you could just stick to global variable in namespace, which extensively is the same thing as singleton (except that you could atleast change the variable temporarly). However, it''s really worth to have this flexibility.

For instance, someone who uses your engine would probably want to implement abstract interface of your EventServer to trap events sent by entities. When EventServer is instantiated as singleton and entities directly access GetInstance(), there is no way to do that, unless you build some hooking code there, which is one more kludge to your bag.

As the initial thought in my gfx engine I thought that I would have abstract classes providing specific functionality to draw 3D gfx. Then I would have several implementations of that for different gfx APIs, such as DX & OGL. Well, I believe most programmers who have thought about writing portable gfx engine have think exactly alike.

However, what I DIDN''T think, was, that I might actually have portable visibility engine implementation of that interface as completely separate module (just like DX & OGL implementation), which would trap all object construction and updating calls and pass them in any form to the a gfx engine instance (naturally same engine could be utilized to any gfx API specific implementation due to abstraction). If I had used singleton, this wouldn''t be possible, because several objects had bypassed the actual visibility engine by directly accessing GetInstance().

I DIDN''T think either, that I might want to implement cache efficient triangle stripper implementation for abstract interface of geometry streaming as extension to streaming sequence, NOR did I think that I might want to have object hierarchy optimizer for more efficient state changing.

Because all information flow goes through well defined routes and no secret passages exists (read: direct accesses to globals, such as singleton functions), it gives you alot room to make extensions later.

Cheers, Altair


"Only two things are infinite, the universe and human stupidity, and I''m not sure about the former." - Albert Einstein
"Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein
Houdini
Houdini
quote:
Original post by Altair

GetInstance() is similar nasty hack as global variable. It just happens to be in classes namespace, just like a global variable can be in any namespace. Both are static, while GetInstance() just happens to be function, which can''t be overridden, hence it can''t provide regular runtime polymorphic properties as normal class methods.




I wouldn''t call GetInstance() necessarily a ''nasty hack'' like a global variable. GetInstance() hides the implementation just like a class function should, and it resides in the class namespace, just like a class function should (as you stated). It also performs lazy evaluation, meaning it only instantiates the class the first time it is being used.

The only comparison to a global variable I can see is that any class can get access to the pointer, if they so choose. However, this can also be a good thing as now someone doesn''t have to derive 3 classes just to pass the parameter to the class you want to use it in.

The only real obstacle you run into, as you said, is when you want to subclass the original class. Unfortunately there is no clean solution to this problem, although there are some hacks.

quote:
Original post by Altair

For instance, someone who uses your engine would probably want to implement abstract interface of your EventServer to trap events sent by entities. When EventServer is instantiated as singleton and entities directly access GetInstance(), there is no way to do that, unless you build some hooking code there, which is one more kludge to your bag.




Ok, lets say that they did want to subclass EventServer for this purpose. They would not be doing this on the game level, as they would have no access to the EventServer. This is done on purpose to hide as much detail from the game programmer as possible. If he wanted to edit EventServer, he''d have to do this in the Game engine project itself. Since he''d be making game specific changes to a general game engine, the best thing to do is create a shadow copy of the project in source control, branch the EventServer file he wants and make the change to, and directly edit the class. No reason to subclass since this engine is now a game specific engine anyways. So the subclassing a Singleton in this instance is a mute point.


As for the examples you gave me, I can understand what you are saying. However, I have another one for you, that has been plauging me to this day:

My engine is an OS independant and API independant engine. This has been my goal from day one. Now, to the meat of my problem: I have a WinWindow class which is a wrapper class for the Win32 window manipulation functions (much like CWnd in MFC). My WinApplication class contains an instance of WinWinow, which will be the main application window. My LinuxApplication class contains no xWindow class as it doesn''t need one, obviously.

Now, everything was going great, until I implemented the D3D graphics. Direct 3D needs my HWND pointer to instantiate itself. If I do my parameter passing, I''d have to pass Application* to my game engine, which would in turn pass that to the graphics portion which would then typecast it into a WinApplication and get the HWND. Not only does it not sound right to pass the Application class to the graphics class just so it can get the HWND, but if I do this for the Win32 implementation, I need to do it for ALL platform implementations. The Linux OpenGL has no reason at all to need the Application instance to be passed to it, yet it''s going to be. To me this is just a sloppy hack.

What would happen if I only had the Linux version implemented and someone wanted to add the Win32 implementation? They''d have to subclass or edit the Engine, Graphics, and Input (which need the HINSTANCE) abstract classes, AND all the OS implementations of those classes! If you support 4 OS''s, then that''s 11 classes you''d be subclassing or editing just allow Win32 support.

Yes, I''ve also ran into problems using the Singleton to get passed this approach, but at least it''s a behind the scenes hack and not a up front and in your face hack.

Actually, too tell you the honest truth, I was dead set on using the parameter passing for everything, until this HWND/HISNTANCE problem, among a few others.

If you can show me a clean way to get around this, I''ll use it. If you can show me a better design so I don''t have to pass the application class to classes that may not need it (other OS verions) then I''ll use it.

Problem is, I don''t see how there could be a better design. The HWND belongs to the WinWinow, which belongs to the Application class, pure and simple. The Application instance does NOT belong to the graphics engine, and it is needed by both the DInput AND D3D classes anyways.


- Houdini
Houdini
Altair
Altair
Houdini,

Having static getInstance() in classes namespace doesn''t make it any better than having getInstance() in some separate namespace. It''s procedural programming to have global variables and functions floating around, not OOP, and there is several reasons, why you should have functionality and data coupled, but I don''t want to run into debate about that now.

To make your terminology straight, lazy evaluation isn''t what you descriped. Lazy evaluation means that something is evaluated only when it''s gueried, not before. You should check Scott Mayers "More Effective C++" about the topic.

You don''t need to derive classes to pass a parameter. Just declare it in the argument list of a method. But I hope you knew this already

I didn''t mean that EventServer messages would be catched only for debugging purposes or such. As you have probably noticed yourself, you are assuming quite much, what everyone would want or wouldn''t want to do. If you design things properly, you don''t need to make such assumptions. The example I gave about my engine was ment to illustrate that even when some specific functionality weren''t designed to be implemented by client (like visibility engine), he/she still could do that, without any assistance from the author.

You are very much right about that no platform specific stuff should be presented in abstract interface, which is supposed to be portable. If you explicitly instantiate a specific gfx engine (like D3D engine), you can pass any implementation specific arguments to it, like WinWindow or WindowBase if you want it to run it in a specific window. I don''t really see what''s your problem there. Note that D3D engine can also create its own window if that''s applicable.

Cheers, Altair


"Only two things are infinite, the universe and human stupidity, and I''m not sure about the former." - Albert Einstein
"Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein
Houdini
Houdini
quote:
Original post by Altair

Having static getInstance() in classes namespace doesn''t make it any better than having getInstance() in some separate namespace.




Using it in the same namespace as the class means we aren''t depleting the namespaces available by adding one more, thus less chance of namespace collision. Yes, I know this is a very petty point, but damnit I win! Erm, uh, ok maybe not .

quote:
Original post by Altair

It''s procedural programming to have global variables and functions floating around, not OOP, and there is several reasons, why you should have functionality and data coupled, but I don''t want to run into debate about that now.




Interesting. You sound as if you are of the mind that code isn''t truely OOP if you have any global variables or functions. What about using memcpy? Isn''t that a global function? If you use that does it mean your code isn''t OOP? Note, I''m not trying to sound sarcastic at all, I''m trying to see where you stand.

quote:
Original post by Altair

To make your terminology straight, lazy evaluation isn''t what you descriped. Lazy evaluation means that something is evaluated only when it''s gueried, not before. You should check Scott Mayers "More Effective C++" about the topic.




Yes, you are probably right. I couldn''t think of a better word than ''evaluation'', but since it''s a wide known term I just stuck with it. Either way it''s still lazy.

  
MySingleton *MySingleton::GetInstance()
{
if (!m_pInstance)
m_pInstance = new MySingleton;

return m_pInstance;
}


quote:
Original post by Altair

You don''t need to derive classes to pass a parameter. Just declare it in the argument list of a method. But I hope you knew this already




Yes, but that requires a change to original code. If it was a game specific change needed to the engine, you could just subclass that class in your game project, and instantiate that class, thus never touching the game engine code. If it was a generic enhancement of bug fix you could just do it directly to the engine and recompile. I believe I mentioned something about deriving a new class or editing the old one as a means to add the parameter, whichever was preferred.

quote:
Original post by Altair

I didn''t mean that EventServer messages would be catched only for debugging purposes or such.




Erm, neither did I. I guess we are both missing each others points .

quote:
Original post by Altair

As you have probably noticed yourself, you are assuming quite much, what everyone would want or wouldn''t want to do. If you design things properly, you don''t need to make such assumptions. The example I gave about my engine was ment to illustrate that even when some specific functionality weren''t designed to be implemented by client (like visibility engine), he/she still could do that, without any assistance from the author.




Yes, I am making assumptions. For instance, my engine is designed specifically as an engine and framework for creating 3D isometric tile games easily. I''m trading some low level functionality which I consider insignificant for ease of use. Note, I''ve have taken pains to ensure the user can add plugins without touching a bit of the original code (plugins work for graphics/input/sound, and I''m debating doing the same with graphic/model formats).

If you don''t want to make any assumptions, then you cannot make a higher level engine, as I am. You must make that trade, functionality or ease of use.

quote:
Original post by Altair

You are very much right about that no platform specific stuff should be presented in abstract interface, which is supposed to be portable. If you explicitly instantiate a specific gfx engine (like D3D engine), you can pass any implementation specific arguments to it, like WinWindow or WindowBase if you want it to run it in a specific window. I don''t really see what''s your problem there. Note that D3D engine can also create its own window if that''s applicable.




Unfortunately, that wouldn''t work. The engine is designed specifically so the actual game code won''t change for Linux,Windows,Mac, etc, so I can''t explicitily instantiate any specific gfx engines in my game code (since most are platform dependant).

Also, the gfx/input/sound engines are plugins, which my game engine doesn''t know about. The user tell the engine which dlls to use by passing the name of the dll through the command line. The engine will then load them up using the abstract interfaces.

Also, although creating the window in the D3D engine would work (even tho I consider it ugly) I would still have the same problem with my input engine. DInput requires the HINSTANCE to be passed.


- Houdini
Houdini
Altair
Altair
Houdini,

I mean exposing global functions and variables in your interfaces, not about utilizing C standard library, such as memcpy, in the implementation. After all, C is procedural programming language, while C++ is hybrid of both procedural and object-oriented language, which allows you to use such global function as memcpy. Have you ever tried Java? There is no global functions, but which still can be implemented by using static methods. And believe me, alot of people do that, because they aren''t that comfortable with OOP, sad but true.

GetInstance() isn''t lazy. It would be lazy if it would return smart pointer instance, which wouldn''t instantiate the actual class until you would access it with -> operator or such. Anyway, I doubt there would be any reason to make it so, because all queried instancies are efficiently used. I actually call my coding lazy, because I only write code that I really need I don''t i.e. write full matrix class just because I might need one in the future, but only implement required functionality I need at the present moment. It gives better perspective on things and saves alot of time.

Yes, you need to make few assumption, such as client understands C++ and uses decent C++ compiler Anyway, you should build your engine with several layers and components, which help client to implement some specific type of game. If the lowest level layer in your engine is designed so, that all games implemented by using it are supposed to be 3D isometric game, it may be very hard or even impossible in practice to implement 3D shooter with it.

I know from experience that it''s time consuming to design a generic gfx API, but once it''s properly designed, you don''t need to do it ever again, just make some updates now and then. 3D isometric game engine then should utilize this API hence being portable and isolated module. Anyway, it''s quite hard to give you any partical thoughts, which you might utilize, without diving deeply into your current design.

Cheers, Altair


"Only two things are infinite, the universe and human stupidity, and I''m not sure about the former." - Albert Einstein
"Only two things are infinite, the universe and human stupidity, and I'm not sure about the former." - Albert Einstein
Houdini
Houdini
I still consider GetInstance(), or at least my implementation of it, lazy because the class is never instantiated until you try to use it. For instance, my EventServer class is never instantiated until a class tries to register itself with it. If no class ever registers, then it never gets instantiated.

I do know what you mean about how time consuming it is to properly design a gaming engine. I''ve spent months (on and off) thinking, rethinking, and tweaking my design. The biggest pitfalls I''ve ran into is trying to keep the engine API and OS independant without resorting to nasty hacks. And unfortunately, there are very few OS and API independant C++ gaming engines on the net, and the few I''ve seen use nasty hacks, so they don''t help me at all.

Oh well, just means I spend more time thinking how I can make my engine better. Besides, it''s almost more fun designing an engine than actually one.

BTW, thanks for your thoughts on the subject. It gives me something to consider on how I can improve my design.


- Houdini

Houdini
Mithrandir
Mithrandir
Okay, i think i figured out a solution to my math module problem:


combination facade and abstract factory.


What i do is use a math facade which accesses certain abstract sub modules (trig, primes, random generation, etc) to do its work, and pass in the math module to each game module that uses it.

sounds cool?

===============================================
Hurry up madness, hurry up disease,
hurry up insanity, hurry up please.
Hooray! I say, for the end of the world.
This is my signature. There are many like it, but this one is mine. My signature is my best friend. It is my life. I must master it as I must master my life. My signature, without me, is useless. Without my signature, I am useless.
Shannon Barber
Shannon Barber
If you try it let me know how bad the overhead is - I worried about making all my math functions virtual... which means you can''t make them static... which means a double derefernce for each one... not sure if it matters.

Magmai Kai Holmlor
- The disgruntled & disillusioned
The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.