Suggestions for my Input Manager.

Started by
5 comments, last by hudovisk 10 years, 1 month ago

Hi everybody,

I am thinking in how to implement my game engine and started with the input system. I read http://www.gamedev.net/blog/355/entry-2250186-designing-a-robust-input-handling-system-for-games/ and came up with this. What i have is an InputManager that handles SDL way of input and send them to a list of InputContexts. Each InputContext has a pointer to IInputListenner, that is the one who handles the input, but the InputContext has the role of translate the InputEvent object into a game message. And is here that i dont know how to really do it. I thought put the information needed by InputContext inside a XML file, but i dont know how to parse a XML into a generic type of data, which may have one, two or three values inside it and pass it to game logic.

My problem isn't how to load a XML file, it is how do i create a generic MessageObject that my game can handle.

InputManager.h:


class InputManager
{
public:
        static InputManager* getInstance();

        void dispatchEvents();

        void registerContext(InputContext* c);
        void deregisterContext(InputContext* c);
private:
        InputManager();
        static InputManager* instance;
        std::list<InputContext*> contexts;
}

The only interesting function is the dispatchEvent(). which is called every frame:


void InputManager::dispatchEvents()
{
	SDL_Event event;
	while(SDL_PollEvent(&event) != 0)
	{
		InputEvent inputEvent;
		std::map<unsigned int, InputEventType>::iterator it = inputEventMap.find(event.type);
		if(it == inputEventMap.end())
		{
                        std::cout<<"Unknown Event"<<std::endl;
            		continue;
		}
		inputEvent.type = it->second;
		inputEvent.timestamp = event.common.timestamp;
		if(inputEvent.type == KEYBOARD)
		{
			inputEvent.key = mapKeyInput(event);
		}
		else if(inputEvent.type == MOUSE)
		{
			inputEvent.mouse = mapMouseInput(event);
		}
		for(std::list<InputContext*>::iterator it = contexts.begin(); it != contexts.end(); it++)
		{
			if((*it)->dispatch(inputEvent))
			{
				break;
			}
		}
	}
}

Here is a possible syntax for the XML :


<?xml version="1.0" encoding="ISO-8859-1"?>
<context>
   <key value="W" pressed="true" message="MOVE_FORWARD"/>
   <key value="SHIFT + W" pressed="true" message="RUN_FORWARD"/>
...
   <mouse value="MOTION" message="CAMERA_MOTION">
      <param value="X" inverted="false"/>
      <param value="Y" inverted="false"/>
   </mouse>
</context>

i dont like the idea of passing the messages as string because string comparison isnt efficient. I am open to suggestions.

Thanks in advance.

Advertisement

You are just a bit too fast; within the next 2 weeks I plan to release an article on handling input from an implementation standpoint. It’s much more complex than you think.

That article is good for an overall idea of what features need to be part of the overall input system, but I believe its step #2 is or at least could be construed as being akin to an event system. Inputs are not events. While it is true they are to be collected and remapped, they are not to be processed immediately as they are received (as an event system would have you do).

Input is to be accumulated on the input thread, timestamped, and fed to the game logic at a specific time during the overall logic processing.

So I am going to suggest you stop here on 2 points:

#1: If you are using singletons, you are doing it wrong.

#2: Inputs are not events. You don’t need an answer to your posted question because you don’t need events and handlers. Read my posts for (many) details on why this is and try to get inspiration for another approach to this problem.

I will answer questions related to the input system I described already and very soon I will post the promised article on an input system that addresses the biggest issues: Input lag and timely processing.

L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Thanks for your reply.

Ok, let me see if i got it. I dont need handlers, because the inputs goes direct to my buffer and the buffer is directed accessed from logic update right?

But i still need a way to parse the input data into game data, and this must be relative to the context that i'm using. The way i see, a player would have a context, a menu would have a context and so on. Then whenever i would read the input, i would pass something like message = currentContext.parse(input); and check whatever i need to execute the message. So i still need a way to parse my XML into a generic message or there is a more elegant way of doing it?

Also, could you explain me why singleton is wrong? its not the first time i see it, but no one pointed me an article or explained why.

In either case, first-off you would not be parsing anything at run-time. Any mappings should be parsed from a configuration file once at start-up and never again unless the user changes them in the options menu.
And there is no reason to use XML. JSON is generally preferred for its smaller size and easier manual editing, but there is also no reason you can’t just make your own format, which is what I would do personally. It’s a few lines of X=BLAH; easier thing in the world to parse.
I’ve never used XML or JSON so I would not know what options are available if you go that route.

http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons
http://www.gamedev.net/blog/42/entry-1831201-another-example-of-why-singletons-are-bad/


L. Spiro

I restore Nintendo 64 video-game OST’s into HD! https://www.youtube.com/channel/UCCtX_wedtZ5BoyQBXEhnVZw/playlists?view=1&sort=lad&flow=grid

Also, could you explain me why singleton is wrong? its not the first time i see it, but no one pointed me an article or explained why.

Generally because they're just a sign of a poor engine architecture and layout, they also make silly assumptions like that you will only ever have one instance of something. Want to make a second input handler to accept networked input? Sorry, only one. Want to make a second render controller for another opengl context? Sorry only one here.

They also are basically globals in OOP sheep's wool and have nearly all the same problems as them. It is usually considered rather bad design choice to allow any section of a program to reach a claw out and stick itself in different sections of the engine without any sort of control or reduction of visibility. I believe L. Spiro mentions it in a few blog posts too as to why you would ever possibly want more than one copy of a subsystem like rendering for multiple contexts.

But really if you search the forum I'd be shocked if you don't find a thousand debate topics on the subject. My opinion stands at, they are a valid design idea but with the exception of a few closet cases in languages like C#, you should prefer to not use them, they'll just promote lazy design that will bite you hard later, especially if you start threading.

This is an article I like about the topic of Singletons: http://www.ibm.com/developerworks/webservices/library/co-single/index.html

I like it because it doesn't just say "Why Singletons Are Evil". It explains it and it also explains when it is OK to use them.

Also, I would add to what Satharis said that one reason to have multiple instances of something that have come to me in the past more often than not is multi-threading. If you build your application relying on singletons and then you need to multithread... well, you are in for a world of pain. If you just use mutex in the singleton you end up with a parallel program that is not so parallel (most threads are always waiting for some other which is accessing a singleton). You could just create singletons that can actually return one instance per thread but then you are constraining yourself to having a fixed amount of threads and manually manage them...

“We should forget about small efficiencies, say about 97% of the time; premature optimization is the root of all evil” - Donald E. Knuth, Structured Programming with go to Statements

"First you learn the value of abstraction, then you learn the cost of abstraction, then you're ready to engineer" - Ken Beck, Twitter

Thanks for the articles, now i see the way i was using ( and taught ) was wrong. About the input, i changed to an event manager that i saw in Game Code Complete 4, using fast delegates http://www.codeproject.com/Articles/11015/The-Impossibly-Fast-C-Delegates. Now i am going to learn how to do it multithread so i can properly handle SDL.

So much to learn..

Thanks for the help smile.png .

This topic is closed to new replies.

Advertisement