Sign in to follow this  
Xperience

Managers, which pattern should I use

Recommended Posts

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?

Share this post


Link to post
Share on other sites

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.

Edited by Daivuk

Share this post


Link to post
Share on other sites

...

 

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.  

Share this post


Link to post
Share on other sites

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.

Share this post


Link to post
Share on other sites

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.

Edited by Khatharr

Share this post


Link to post
Share on other sites


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.

Share this post


Link to post
Share on other sites

 


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.

Share this post


Link to post
Share on other sites

If you need simplified access to a lot of subsystems and yet you do not want to place restrictions on directly accessing the subsystems, a facade pattern might work.  Create a class that allows you to assign subsystem objects, preferably as interfaces.  The facade merely holds a reference to the subsystem object but doesn't prevent you from accessing the object directly if it becomes necessary.  You can then add methods to the facade that allow you to control the complex behavior.

Share this post


Link to post
Share on other sites

Ok, if I understand it, I have to create one class which handle Input from keyboard, one from mouse, gamepad etc. and put this classes inside a facade and this facade class put inside a root class? And if some class want keyboard input I should pass it by parameter? Something like this:

class Keyboard
{
//some members variables, functions etc.
};
class Mouse
{
//some members variables, functions etc.
};
class Gamepad
{
//some members variables, functions etc.
};

//Facade class
class InputHandler
{
Gamepad m_Gamepad;
Mouse m_Mouse;
Keyboard m_Keyboard;
//other functions, variables...
};

//Root Class
class Game
{
InputHandler m_InputHandler;
};
Edited by Xperience

Share this post


Link to post
Share on other sites

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?

The problem with this is the big root class. It would be better to pass input manager and texture manager as separate objects to functions and classes that need them. Don't pass both together, unless both are needed.

Others have made good points too, particularly about how "manager" is not a good name and what frob said about how input should work.

Share this post


Link to post
Share on other sites

In my humble opinion the term "manager" should immediately ring an alarm bell when it comes to designing your application.

QFE.
Usually if you think about the design a bit more, you'll realise you're designing a cache or a factory or a pool, or some other specific structure (not a vague "manager").

Or maybe you're designing something that's all three of those (in violation of SRP), and you can actually split it out into separate reusable parts... which you can then reuse to very easily make a texture cache, a buffer cache, etc, etc.

Edited by Hodgman

Share this post


Link to post
Share on other sites
The one thing I never get about the "manager" hate is that even though people say to decompose the class into multiple classes that take care of the different bits of what the manager does, what it comes down to is that they're changing internals and usually there's always still one "manager" class thats the interface for other classes to do things.

A good example being the "resource cache" like, to me all you're doing is putting sparkly glitter on the fact that the resource cache is a resource manager, you're overbearing the point of what it does externally when in reality you're just saying to decompose it into parts.

Sure reducing coupling is good, maybe you want to add loaders to your resource cache for different resources instead of having to mess with the internals, but to me its all semantics. For the rest of your code the resource cache is going to be a resource manager still and it probably should NOT see the other classes the resource manager is using anyway.

tl;dr: I feel like people use the word "manager" like its a semantic for "bad design" when it reality it isn't. In fact I find it debatable whether the term resource cache really explains the purpose of what it does more than resource manager would to the other parts of the program looking in.

Is it a better name? Maybe, but really, it's just that, a name. Edited by Satharis

Share this post


Link to post
Share on other sites
Why?

 

That is certainly one way to do it, but far from the only way.

 

Games generally like to handle events and flags.  

 

* You care that you got a "move left" event, you don't care if it came from the keyboard or mouse or script or network or AI.

* You care that you got a "fire" event, you don't care if it came from the keyboard or mouse or script or network or AI.

* You care that you got a "zoom in" event, you don't care if it came from the keyboard or mouse or script or network or AI.

* You care that you got an "object placed" event, you don't care if it came from the keyboard or mouse or script or network or AI.

* You generally don't care if the player prefers WASD or IJKL or arrow keys for a keyboard mapping.

* You generally don't care if the player prefers to reverse the up/down axis for a controller

 

 

Large games tend to have multiple input mappings that generate a common set of events or states that are consumed or tested. 

 

The code tests against that common interface and not against a specific keyboard or controller.

 

 

It's much better and more flexible, thank you for this sample.

I'm never think about this approach, but where I should put this Input Handler? I should pass Input Handler into every Level, or create new one?

Edited by Xperience

Share this post


Link to post
Share on other sites

It's much better and more flexible, thank you for this sample.
I'm never think about this approach, but where I should put this Input Handler? I should pass Input Handler into every Level, or create new one?

What he's talking about is not a specific architecture but more the idea of translating the idea of making something happen into an abstract event. Some games use something like an event message system where objects register with each other and "listen" for messages, you could also have something like an input manager that you pass around and basically "translates" things like keypresses or network messages into states like that you should be moving left or up or whatever.

For instance as was pointed out, it is a common event in games where something will happen to an object on the map and multiple systems will take notice of it. You may destroy an enemy, that may raise your score, decrement a counter on an enemy spawner, play a sound, run an animation. All these results can be controlled from different points in code, you may have the object manually call each of these things its self, or indirectly tell another system to, you could also make a messaging system where objects "broadcast" when something happens to them and other objects respond to it.

There's different ways of doing it really.. though, I would keep in mind that making such systems is more involved, if you're making a simple game there is nothing wrong with hardcoding the keys you want to use, or making a very simple keyboard class that tracks the state of each key or the mouse. There's no golden bullet to the question, it depends on your needs and complexity.

An important thing is what I would term "delegation of responsibility" figuring out which part of your game should be in charge of making something happen. Probably the most basic design is to have something like an enemy ship in a 2d scroller tell the other systems it exploded, tell them what to do directly. Simple but not very flexible. Edited by Satharis

Share this post


Link to post
Share on other sites


A good example being the "resource cache" like, to me all you're doing is putting sparkly glitter on the fact that the resource cache is a resource manager, you're overbearing the point of what it does externally when in reality you're just saying to decompose it into parts.

 

You have that a little backwards, methinks. Part of the argument is, as you say, that the manager class is too monolithic and should be refactored into several, more tightly focused classes. But a manager means different things to different people and in different contexts. Like Hodgman said, it could be a cache, a factory, or a pool, or maybe even something else, or some combination of them, depending on what it's managing. Those are all well-defined computer science terms. Cache is the typically used suggested alternative because texture manager tends to be such a popular how-do-I- topic.

 

I agree that once it's broken down into a system of classes, there is typically one class, or sometimes a small subset of the classes, that act as the interface to the rest of the program. But that interface is more tightly focused, and if designed well, rarely needs to be global. Often the class acting as the public interface may not even be the cache or factory or pool that served as the core of the old manager class.

 

Ultimately, the manager phenomenon is a manifestation of inexperience and ignorance. It's relatively easy to learn to code self-guided from books and we sites. It's more difficult to learn good design and to think like a programmer without guidance. And so newbies create managers  because they haven't gained enough theory to better define what they intend the class to do, and they make them singletons because it looks like an answer to their design problems. And they get away with it for a time, because the new problems are much more subtle. And then they start looking for better ways to do things when they finally stumble. And they get told that managers are bad and global are bad and singletons are bad. And if they're fortunate they're given advice on better design. And if they're really fortunate it's comprehensive and easily followable. That's just how it is in the Internet we live in.

 

So, some caches may be part of some managers or management systems (or modules or whatever), but I disagree that it's all semantics.

Share this post


Link to post
Share on other sites

You have that a little backwards, methinks. Part of the argument is, as you say, that the manager class is too monolithic and should be refactored into several, more tightly focused classes. But a manager means different things to different people and in different contexts. Like Hodgman said, it could be a cache, a factory, or a pool,

Which to me is why resource cache is just a pointlessly specific name as manager, it's supposed to be an abstraction. You know, you ask for a resource, you get it back, that behavior is the same in all three things you listed. Why does the name have to reflect the behavior of how it works under the hood? Sure if you want to go in detail I guess in your file list having cache is more specific, but to the rest of the program looking in it is just specifics that don't imply anything about design. I could just as easily call it a resource pool and put -all- the loading code into that one class.

Which is why it sort of boggles my mind how many replies in this thread are like, "If I see the word manager, oh man, red flag!" You don't even know what manager means yet and you're already assuming it doesn't follow some mythical golden rule of design, silly stuff.
 

or maybe even something else, or some combination of them, depending on what it's managing. Those are all well-defined computer science terms. Cache is the typically used suggested alternative because texture manager tends to be such a popular how-do-I- topic.

I'm a firm believer in something most books, tutorials and teachers try to push about programming, and that is the idea of abstracting away how something works internally from how other parts of a program use it. That happens no matter the language, you can do the same thing with subroutines in assembly. What it comes down to is that if you need to ask a major system for something it should for all intents and purposes, work automagically for you. Compartmentalizing code like that makes it much easier to manage, if anything the topic we are specifically covering is when you should decompose the internals of a manager into smaller classes and benefits of doing so.
 

I agree that once it's broken down into a system of classes, there is typically one class, or sometimes a small subset of the classes, that act as the interface to the rest of the program. But that interface is more tightly focused, and if designed well, rarely needs to be global. Often the class acting as the public interface may not even be the cache or factory or pool that served as the core of the old manager class.

I use the word "manager" in my code for such systems all the time and I don't make it global, I don't make it a singleton and if it is in my BENEFIT I decompose it into more classes internally, that doesn't have anything to do with the fact it is named "manager." I name it manager because to the rest of the program it is just that, a manager, it is presented as a monolithic class to the rest of the game because that is its job, it is to appear to be the interface to get ahold of resources and the rest of the game could care less how it works under the hood.

I'm sorry if I'm repeating myself ad nauseum but as I go through your reply it just strikes me that you seem to associate the word manager with "bad design" and although that may be true sometimes, especially in the case of novice developers, it really doesn't say anything about the architecture. Personally I've seen "manager" done a hundred different ways and a lot of them are very awful so it's not like we're talking about one medicine prescription here.
 

Ultimately, the manager phenomenon is a manifestation of inexperience and ignorance. It's relatively easy to learn to code self-guided from books and we sites. It's more difficult to learn good design and to think like a programmer without guidance. And so newbies create managers  because they haven't gained enough theory to better define what they intend the class to do, and they make them singletons because it looks like an answer to their design problems. And they get away with it for a time, because the new problems are much more subtle. And then they start looking for better ways to do things when they finally stumble. And they get told that managers are bad and global are bad and singletons are bad. And if they're fortunate they're given advice on better design. And if they're really fortunate it's comprehensive and easily followable. That's just how it is in the Internet we live in.

Yet more talk about managers being globals or singletons or bad design or what have you, a massive generalization. I would also like to point out that even though you have such a mystical view of perfect code(as do a lot of other people here) in reality a lot of AAA engines and games out there massively abuse things like globals, singletons, static objects all over and messy cross includes and bad design, these things are bad design because we come up with negatives associated with them. But the thing is, people still use them and probably always will, and honestly I'm one of those people that has learned very heavily that not everyone's advice is to be taken blindly and that you have to look at things with perspective.

The biggest fact with programming is that it is situational. I often see people pushing this massively overcomplicated component based design that they tote around like religious talk for many different subsystems of a game and the fact is: it is often overcomplicated, massively personalized, doesn't necessarily do something -better- and finally, it takes a hundred times longer to implement, and is ONLY good in a situation where how generic it is can be utilized. There's no silver bullets here, saying the word "manager" means bad is like saying "all bit shifting is bad" well of course thats silly, you can do a billion terrible things with bit shifting and also a billion good things depending on the situation.
 

So, some caches may be part of some managers or management systems (or modules or whatever), but I disagree that it's all semantics.

Well of course, how could it be semantics if all your assumptions so far are that any "manager" must be one big brand of bad design, I never once suggested that a manager had to be a singleton or global or all the code shoved together or anything like that. The OP asked for how these systems tend to work not why his name "manager" implies he is a terrible coder.

Share this post


Link to post
Share on other sites

I realize it would be asking for a lot of work, but would an example be appropriate?  We would then have something specific to talk about rather than just throwing around generic terms.  I am genuinely interested in seeing an example that starts with "manager" based code and provides a step-by-step refactor.

Share this post


Link to post
Share on other sites

I realize it would be asking for a lot of work, but would an example be appropriate?  We would then have something specific to talk about rather than just throwing around generic terms.  I am genuinely interested in seeing an example that starts with "manager" based code and provides a step-by-step refactor.

Well judging by the OP's post, at least how I read it. He isn't exactly concerned with a "manager" class but more how a "management system" of the appropriate type works, like rendering or resources.

At its heart though it basically differs a lot by the manager. In my experience they all share a common bond in that they tend to share an "outward interface" to the rest of the program and are basically subsystems for the game or simulation or whatever. Most of the complaints come from people talking about simplistic "manager" classes that are basically like, oh lets make class ResourceManager and have it just take a filename and return a loaded file to whoever asks for it. The caveat here being that all the code for the -process- of getting that resource is right in the rendermanager, so it could be a big convuluted mess.

Of course I disagree with people like hodge even in the case that it is a "novice" design always, to me it is a "simple" design. The fact is that such a class can work fine if the game is simplistic, if it has minimal resources to return and there wouldn't be worthy effort in taking the time to create a deeper system that say, manages the lifetime of resources and sorts them, uses seperate loader classes to deal with acquiring the data in memory, so on.

The problem most people have with the idea is not that the manager itself is bad but more that they "fear" I guess that the novice will take that manager as being a scalable solution and ONLY use that in the future, using a simple idea like that in a big game would just be masochistic.

The thing here isn't that the idea is "bad" the thing here is that the idea is "simple" so in essence you're asking for a preview of taking a simple one class "manager" and giving it more advanced functionality. Technically it wouldn't be too big a deal to write some code in here about it if anyone wants to take a crack at it, but I don't have any snippets I can throw up in a hurry to demonstrate the process very easily. The point is that it being more advanced means its going to have a lot more crossing and deep code to give it more intelligent behavior, so you'll just end up with a bunch of "some class doing something complicated for the resource cache." Edited by Satharis

Share this post


Link to post
Share on other sites

My concern is the balance between abstraction and restriction. I could hide all the graphics code behind some monolithic interface, but what if the person using that interface later wants to do something that I didn't anticipate? The important thing here is open/closed principal. The 'Input Manager' I was talking about earlier is a very simple thing. It can list which devices are connected, and it holds the device interfacing objects. It never needs to do anything other than that, so it's closed for modification. On the other hand, a new device type may come along, and I can easily slide that right in there with minimal fuss, so it's open for extension.

 

A lot of graphics libraries I've seen have done a less than stellar job with this. They always try to do too much for you and end up losing flexibility for the sake of automation. The interface becomes too restricting and I no longer care about whether or not the 'manger' is a single unit, or an interface to a collection of units: it's not open enough, and it's preventing me from getting shit done.

Share this post


Link to post
Share on other sites

My concern is the balance between abstraction and restriction. I could hide all the graphics code behind some monolithic interface, but what if the person using that interface later wants to do something that I didn't anticipate? The important thing here is open/closed principal. The 'Input Manager' I was talking about earlier is a very simple thing. It can list which devices are connected, and it holds the device interfacing objects. It never needs to do anything other than that, so it's closed for modification. On the other hand, a new device type may come along, and I can easily slide that right in there with minimal fuss, so it's open for extension.

Honestly there's no real way to anticipate what you'll need and doing so often just leads to cluttered interfaces and wasted development time, it's much easier to revise and edit. I mean.. if you need to do something you can't, then analyze why, how, and figure out a way to expose that behavior in a sensible way.

On top of that it's actually pretty uncommon to not use a monolithic interface at least for major subsystems, allowing access to a bunch of underlying classes without at least going through that top interface somehow usually leads to hidden dependencies or exposing code just for the sake of exposing it. In the case of say there being too many methods to call with your "resource manager" you coudl always decompose some of that code into a lower interface class that you access through the top one I suppose, that makes it rather clear what each section is allowing you access to.

But really.. I mean.. its the same principle regardless, using a different thing than a "manager" shouldn't mean much more than a name change otherwise that code probably could be refactored already anyway if it is beneficial to you to do so. If you don't want to expose access through that top interface then make another class and treat that as a top level interface like the resource manager.
 

A lot of graphics libraries I've seen have done a less than stellar job with this. They always try to do too much for you and end up losing flexibility for the sake of automation. The interface becomes too restricting and I no longer care about whether or not the 'manger' is a single unit, or an interface to a collection of units: it's not open enough, and it's preventing me from getting shit done.

Sadly that's just going to tend to happen, especially with third party stuff. When you're talking your own code you obviously can add things when you need to, but when you're packaging and distributing a third party library you kinda have to put in features to appease a wide audience, and sometimes it still may not have that particular thing you need, that's why rolling your own code is sometimes much more helpful, or extending the other library somehow.

Heck nobody would make engine level code from scratch if one library could do it all. Also you probably already know most of this stuff but it's just me iterating my viewpoint on the purpose of such designs. Edited by Satharis

Share this post


Link to post
Share on other sites

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

Sign in to follow this