Managers, which pattern should I use

Started by
28 comments, last by Khatharr 10 years, 7 months ago

Hi,

I'm learning Direct3D now, but I don't know how I should write managers(Input manager, texture manager etc.).
I created some small games, but in this games I had input manager and texture manager in one big root class, and pass them to function which want to use them, but this is a bad or not? Is some pattern which should I use?

Advertisement

Singleton pattern is the most commonly used for managers.

Just careful to not put managers as singleton that don't need to be.

One day you will want to add multiplayer, or split screen, to your game. And all those singleton will haunt you.

Some things, like Texture manager, should definitely be in a singleton. It's sharing textures across all part of the engine.

But input manager, maybe not. If you add a second controller for player 2, you might want him to handle his own input separately, and you will want a second instance of input manager.

What I do in my games generally, is create a global singleton, where I put all those managers in.

Globals::getInstance()->textureManager()->getTexture("baby.png");

Globals::getInstance()->inputManagers[PlayerId]->isButtonDown('A');

Not the best practice, but accessing things easily from everywhere is nice too. Also I cant keep all my other managers singleton-free.

as usual I have to bring my pov against singletons.

It isnt really a big deal to pass needed stuff around.. when needed :)

And, if I REALLY need a singleton, I'd rather write loose functions.. it maps much better IMO.

Stefano Casillo
TWITTER: [twitter]KunosStefano[/twitter]
AssettoCorsa - netKar PRO - Kunos Simulazioni

I hate "manager" classes (in general). They often turn into a mess of SRP violations and weird state mixtures.

A texture manager probably isn't a great idea. A texture resource cache with a texture resource loader is a much better idea, though. But it really shouldn't do much managing of texture resources.

[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]

...

Globals::getInstance()->textureManager()->getTexture("baby.png");

Globals::getInstance()->inputManagers[PlayerId]->isButtonDown('A');

Not the best practice, but accessing things easily from everywhere is nice too. Also I cant keep all my other managers singleton-free.

That is just ugly. It reminds of me of the OGRE engine and how much i hated its managers. Like said before, there is nothing wrong with passing pointers or localizing functionality.

"Spending your life waiting for the messiah to come save the world is like waiting around for the straight piece to come in Tetris...even if it comes, by that time you've accumulated a mountain of shit so high that you're fucked no matter what you do. "
"Manager" classes are usually questionable. Often they are a sign of underdeveloped design, with arbitrarily conflated functionality in "god classes"; at the very least, they have a less vague purpose than "managing" and therefore they should have a less vague name. For example, depending on your architecture, you could have an InputQueue (where simulation code reads and consumes a sequence of incoming input events), an InputState (determined when it is queried or frozen in time until updated), a XxxInputController (with the same interface as other XxxController implementations, which reads inputs from the user and gives corresponding commands to a Xxx), or something fancier, or very likely a combination of several categories of input handling classes and interfaces. This doesn't include many other classes to configure the use of input peripherals (representing and persisting preferences in general, user interface, configuring input-reading classes according to preferences, etc.) What you cannot have is an InputManager that deals with all current and future input-related needs of all parts of the program on its own: wishful thinking cannot replace actual design. A "texture manager" is more obviously a combination of different concerns: listing and describing all texture assets, associating textures and the sprites, models etc. using them, loading image data from individual files or archives, assembling texture atlases or reading metadata about already made ones, loading texture image data onto the graphics card and possibly reclaiming memory from unneeded textures, setting the appropriate texture for each drawing call, etc. Some of these tasks deserve specialized objects with a single purpose, others can be encapsulated into sophisticated and easy to use Texture objects.

Omae Wa Mou Shindeiru

In my humble opinion the term "manager" should immediately ring an alarm bell when it comes to designing your application. I'm not saying that you should never write classes which completely manage some system, but they have a tendency to turn into god classes pretty quick and that's something you want to avoid at all costs.

Cornstalks made a really good point on which systems to implement to handle your texture resources. A system which handles the loading of resources shouldn't be bothered with maintaining a resource's lifecycle or vice-versa. It just bloats the system and will turn it into an unmanageable wreck.

The same thing goes for input. You can receive input from many different devices, do you really want to put all of the logic behind receiving that input into one system? Will systems which require input (eg. character controllers) all have to depend on this one bloated system? That's just not a flexible design.

I gets all your texture budgets!

I know that a lot of people reject to 'managers', but I don't immediately reject the notion, provided that the 'manager' does not violate other design principals. It should not be a god class, and it shouldn't be a singleton unless it's 'managing' a resource which would cause conflicts in the case of multiple instances. For example, a 'texture manager' could be called a 'texture cache', and there's no reason to artificially force it to have a single instance. You may want a single cache for textures that are used everywhere, and a second cache for textures that are only used in the current level, etc.

That is to say, I agree with Cornstalks. 'Manager' just isn't the right name for what you want.

As for input, Radikalizm points out that you can have all sorts of different input devices, but in this case I think a 'manager' is okay for exactly that reason: your game can only support the device types that you code support for, and it needs a system in place to 'manage' which devices are active/connected, etc. That system can function as a means of allowing easy access to your input device interfaces, but it shouldn't implement those interfaces. I have no problem with something like

spacePressed = inputMgr->keyboard.isKeyDown(KBKEY_SPACE);

if(inputMgr->getNumberOfJoypads() > 0) {

stickX = inputMgr->joypad[0].getLeftStickX();

}

mouseDX = inputMgr->mouse.getDeltaX();

The 'manager' would only do the work of enumerating the connected devices and containing the objects that allow interaction with those devices. By virtue of simplicity it avoids being restrictive. There may be a better name for it, but none comes to mind.

Anyway, that's my take on it. I'm interested in hearing feedback.

void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.


As for input, Radikalizm points out that you can have all sorts of different input devices, but in this case I think a 'manager' is okay for exactly that reason: your game can only support the device types that you code support for, and it needs a system in place to 'manage' which devices are active/connected, etc. That system can function as a means of allowing easy access to your input device interfaces, but it shouldn't implement those interfaces. I have no problem with something like

I mostly follow the mindset that there will probably be some devices which I'll want to implement later on in my game's development lifecycle without having to bloat existing systems. Some devices also require you to use an existing SDK with some of their own manager objects which need to be alive during the time you want to use the device (like the Oculus Rift for example), so that's more of a reason to maintain the code driving a certain input device separated from other devices.

Hiding all of your device info behind an input manager also hides which input devices a certain other input requiring class need, which can become a real mess when you want to change something in your input manager class.

I gets all your texture budgets!


As for input, Radikalizm points out that you can have all sorts of different input devices, but in this case I think a 'manager' is okay for exactly that reason: your game can only support the device types that you code support for, and it needs a system in place to 'manage' which devices are active/connected, etc. That system can function as a means of allowing easy access to your input device interfaces, but it shouldn't implement those interfaces. I have no problem with something like

I mostly follow the mindset that there will probably be some devices which I'll want to implement later on in my game's development lifecycle without having to bloat existing systems. Some devices also require you to use an existing SDK with some of their own manager objects which need to be alive during the time you want to use the device (like the Oculus Rift for example), so that's more of a reason to maintain the code driving a certain input device separated from other devices.

Hiding all of your device info behind an input manager also hides which input devices a certain other input requiring class need, which can become a real mess when you want to change something in your input manager class.

But you should hide all of you input devices behind an interface anyway otherwise you are going to add special code paths for certain device which lead to even worse design. Implement against and interface not an implementation, and behind that interface all kinds of nasty can go on but your game code doesn't need to know about this and that is exactly what an input system is supposed to do.

I agree with the idea that as soon as you try to create a manager object you need to rethink that part of your code to see whether this is a system or cache type situation but the example you use just doesn't work. In that case implementing against an interface will save you from a lot of trouble in the rest of the code base.

Worked on titles: CMR:DiRT2, DiRT 3, DiRT: Showdown, GRID 2, theHunter, theHunter: Primal, Mad Max, Watch Dogs: Legion

This topic is closed to new replies.

Advertisement