   Using input in an OOP-friendly manner
  If you click on my profile and check my recent posts, you may notice that I've been trying to improve my ability to design OO programs (specifically in C++). Well, I've come to a problem.My problem arises not with getting input, but in using it. Currently, I have some classes like so: (pipes reprsent derivation)    Humanoid    ||    AI   PlayerThis is a simplification, but it works. Currently, my Player class is handling too many things. It takes input from the keyboard/mouse/whatever and turns that into actions for player to do. It also provides more functions (eg: using special abilities like controlling gravity, which other Humanoids cannot do).So, my problem is, is this the right place to be handling input, and if not, where should I put that? I had, in other programs, had the main() function handle events and calls the appropriate functions in classes. This, keeps all input code in the same place (main()), but lead to a bloated main() function and dirty taste in my mouth.And, of course, the Player isn't the only thing using input - so is the GUI, inventory, etc. Where should I handle that?Thanks in advanced.Edit: darn askii diagrams. And I dunno if it's supposed to do this, but the forum replaces '\\' with '\' and '\' with '' inside of the  tag. But, this is not shown in the Preview of a post.Edit again: Gah! I give up! (used good 'ol pipes instead)<!--EDIT--><span class=editedby><!--/EDIT-->[Edited by - Ezbez on July 25, 2006 3:42:02 PM]<!--EDIT--></span><!--/EDIT-->
Quote:Original post by EzbezSo, my problem is, is this the right place to be handling input, and if not, where should I put that? I had, in other programs, had the main() function handle events and calls the appropriate functions in classes. This, keeps all input code in the same place (main()), but lead to a bloated main() function and dirty taste in my mouth.The main() thing seems like a much better place. You shouldn't make any object aware of the way it's being controlled. It should know that an event has come, not where it's come from. It could be comming from a script, for example. Or it could be a replay of a recorded game (input was recorded).If it feels bloated, just move the input handling to a sub-function. Or even better, to some InputHandler object.Quote:Original post by EzbezAnd, of course, the Player isn't the only thing using input - so is the GUI, inventory, etc. Where should I handle that?In my InputController class, I keep a reference to a KeyboardHandlers and MouseHandlers classes, that are basically arrays of function pointers to handlers of specific key/mouse events. Those objects can be switched when a game is moving to another state (e.g. menu). Another thing is that you might want to assign keys to events in run time, without hardcoding anything, for example, from some config file.It's quite basic design, nothing fancy, but it works for me.   ;  Similarly to deffer, I have a class which is comprised of different handlers (albeit maps of boost::function objects or Dictionaries of delegates). I keep this with the rendering/ui code, since things like coordinate systems are common between that and mouse events.   ;  In my current project, in the main loop, the input is first processed by an input handler that first preprocesses the input and then calls the appropriate virtual function on the current state object. What happens then is dependent on the state, but usually the state first calls the analagous function on the user interface manager, and if the user interface manager reports that it didn't handle the input event, the input event is passed through an action map which translates input events into abstract action tokens, depending on the current settings. Then the appropriate action for the action token is performed.The action map is used to allow for user configurable mouse button and key bindings. So in one state the 'a' key might map to the "move left" token and then cause some entity to move left, but with a change to the configuration file that can be replaced with the left arrow key.   ;Quote:Original post by SiCraneThen the appropriate action for the action token is performed.How do you decide what the "appropriate action" is? With "action token" do you mean some sort of unique identifier declared in an enum (for example), or is an "action token" an actual object that inherently knows what it's supposed to do (ie execute "move left" on some entity)?Quote:Original post by SiCraneThe action map is used to allow for user configurable mouse button and key bindings. So in one state the 'a' key might map to the "move left" token and then cause some entity to move left, but with a change to the configuration file that can be replaced with the left arrow key.How does your input system know on which entity to act? I can see how State and UI are handled (you have direct pointers/references to those), but how does "move left" know which entity to actually move left, and how does it "get" to that entity?  Suppose you have players A and B in the world, how does "move left" know that it should perform some action on A and not on B?Thanks :)   ;  That's all state dependent. The mapping of input event to action token is state dependent. After all, the 'a' key may mean one thing when in a menu and mean something else when in combat. The very action tokens used and processed by each state are state dependent. All the game loop sees are the virtual functions exposed by the state. It doesn't know anything about user interface or the entities controlled by the state.;Original post by EzbezMy problem arises not with getting input, but in using it. Currently, I have some classes like so: (pipes reprsent derivation)    Humanoid    ||    AI   PlayerThis is a simplification, but it works. Currently, my Player class is handling too many things. It takes input from the keyboard/mouse/whatever and turns that into actions for player to do. It also provides more functions (eg: using special abilities like controlling gravity, which other Humanoids cannot do).IMHO, actually your Player class *IS* handling too many things. But your problem is not a matter of bloated classes, but a matter of proper abstraction, i.e.: separation of interface and implementation.I think your Player class should be considered as one of the game entities in your program. There are no standard rules about this, but I think game entity should mainly contain only data that describe the state of the entity itself, and not actually *DO* the actions. E.g.: your Player class could beclass Player: public Humanoid{private:// statsint iHitPoints;unsigned int uiStrength;unsigned int uiIntelligence;unsigned int uiExperiencePoints;// conditionbool bIsPoisoned;bool bIsCursed;// qualitiesvector<Skill> aSkillsLearnt;public:// contains constructor(s) and destructor// contains accessors and mutators for your data};As what SiCrane is doing, you should as cleanly as possible, separate input-collection, from handling, from the actual data that the input will change. i.e.:Layer 1: collect input (e.g.: the UI that user inputs into with mouse, keyboard)Layer 2: make sense of and handle input (e.g.: the game state machine)Layer 3: modify game state based on input (e.g.: all the game entities like your Player objects, whether your game is in menu mode or battle mode, etc)From above, Layer 2 is the part/component/module that actual *DO* the actions.As you said yourself, the other parts of your game software also takes in user input, which (surprise surprise!) is also in the form of mouse and keyboard inputs. By separating the input collection from handling from the actual data to be modified, you are able to reuse and extend your input collection/handling code much more easily.Joshua