Introduction and Input Manager

Introduction

Hello, my name is Linus Bjernhagen and I’m going my first year of Game Design and Programming at Uppsala University – Campus Gotland. The course I have now, Game Programming I, gives 5 points towards the project we have to do for this course if we make a blog about it with at least 5 posts.

We’re supposed to make a clone of a game from a list of 12 games. The game is to be programmed in C++ and SDL. It has to have a proper game engine with things such as eg. entity hierarchy, input manager and audio manager. I’m thinking of making a Zelda I clone, but it’s still not too late to change my mind. It will ‘officially’ start on the fifth week, but I asked the teacher if it was possible to start earlier. This course is aimed at people with no previous programming experience, so I thought I would begin earlier as I wouldn’t have much to do otherwise. He said it was okay, but if I waited we would get code we could use in the game engine, eg. code for the input manager.

I began working on the project on tuesday, the second day of the course, and it’s now sunday. I think the input manager is completly done now. I finished it on thursday, so it took two and a half day to make. I’ve since then been working on the entity component system. The entities are called game objects as I feel that makes more sense. I’ve barely worked on it during the weekend though, but I feel as it’s almost done. It could have been finished much earlier if I made it differently, though I think I’ll talk more about that in my next post. Today I’m going to talk about my input manager.

Input Manager

A function called frameInputUpdate() is called each frame. Inside that function the input is polled with SDL_PollEvent(&event) and stored in a vector of events called std::vector<SDL_Event> eventList. Inside the frameInputUpdate function SDL_KEYUP, SDL_KEYDOWN, SDL_MOUSEBUTTONUP, and SDL_MOUSEBUTTONDOWN is checked. If SDL_KEYDOWN or SDL_MOUSEBUTTONDOWN is found within eventList, then that event is added to another vector of events called eventPressedList, and if SDL_KEYUP or SDL_MOUSEBUTTONUP is found within eventList, then the event in eventPressedList with the same key or mouse button is removed.

There is another way that is built-in in SDL of checking for keys pressed, but I think this way is better. You do it by checking the variable key.repeat in SDL_Event. The inteval between each time a repeat event is sent is pretty low, and there is a slight delay after you press the key until repeat begin sending. That interval and delay could apparently be set in previous versions of SDL with a function called SDL_EnableKeyRepeat. But even if I had that function I don’t think I would use key repeat, as much more events would constantly have to be handled, which could make it a bit slower. There also isn’t a way of checking for the mouse buttons being pressed built-in in SDL.

In the functions bool getKeyDown(SDL_Keycode keyCode), bool getKeyUp(SDL_Keycode keyCode) the the specified key is searched for in the varable event.key.keysum.sym in each event in eventList. It is also important to check that the event type is correct. The same thing is done in bool getKeyPressed(SDL_Keycode keyCode), but with eventPressedList instead of eventList. bool getMouseDown(Uint8 button), bool getMouseUp(Uint8 button), and bool getMousePressed(Uint8 button), but instead of checking key.keysum.sym, button.button is checked instead.

Instead of checking for keys you can also check for ‘buttons’. Button is a class I’ve made that contains a string called id and a SDL_Event* called eventP. It enables keymapping by binding keys to id’s. There is a vector called ButtonList which contains all the bindings. bool getButtonDown(std::string id), bool getButtonUp(std::string id), and bool getButtonPressed(std::string id) looks through the ButtonList after matching id’s. When a match is found the key.keysum.sym in the button’s event is checked if it is not equal to SDLK_UNKNOWN. If that’s the case then it calls getKeyDown, getKeyUp, or getKeyPressed, otherwise it checkes button.button != 0, and if that’s true it calls getMouseDown, getMouseUp, or getMousePressed. To bind a key or mouse button to an id you call the function void registerButton(std::string id, SDL_Keycode keyCode = SDLK_UNKNOWN, Uint8 mouseButton = 0). If you want to bind a key you pass a SDL_Keycode but no Uint8, and the other way around if you want to bind a mouse button. It is possible to bind several keys and mouse buttons to the same id, and it’s also possible to bind several id’s to the same key or mouse button.

You get the mouse position with Vector2* getMousePosition(). This is nothing but a simple wrapper around SDL_GetMouseState, but I thought it would be good to have my own functions for all the different input. Vector2 is a class I’ve made that has two varables; x and y. With the function Vector2* getMouseDelta() you get how much the mouse has moved since the last frame. In frameInputUpdate, getMousePosition is called and the position is stored in the variable Vector2* lastMousePosition. getMouseDelta returns lastMousePosition minus the current mouse position.

I also have a function called bool getQuit() that checks eventList for SDL_QUIT. SDL_QUIT happens when you close the window.

void destroyInputManager() clears and deletes eventList, eventPressedList, and buttonList.

That was all of my input manager. It wasn’t very hard to make, I think it was easy to figure out how to do things. In my next post I’ll most likely talk about my entity component system. I had a bit more problem with that one as I wanted to make it a certain way, but had a bit of difficulty with implementing it the way I wanted; but it seems as if I’ve got a solution to it now.

Just now while writing this I realized that I haven’t considered mouse lock and hiding the mouse, though it might be enough to just use SDL_SetRelativeMouseMode(SDL_bool enabled) for that. getMouseDelta() seems unnecessary now though as SDL_SetRelativeMouseMode does the same thing when enabled.