But, I want to use Function Pointers!

Published May 08, 2007
Advertisement
I've come to the conclusion that I'll need the Boost Filesystem to do the loading dialog, so I'll need to work on getting that working. Even the pre-built libraries are giving me linker errors, concerning the filesystem .lib file.

While I'm doing that, I decided to get other bits of programming done. First, I want to get Gamepad configuration working. Basically, the player should be able to configure their gamepad controls for the game, no matter what gamepad they are using. This configuration will be saved in a text file after setup, and recalled whenever the player uses that gamepad.

This is difficult to program, as I need to find a way to make gamepad input the same, no matter how the player configured it. My first idea was to have a class with function pointers representing commands such as Up, Down, Jump, Start, etc. This way, no matter what the player set as the Jump button, I would just call the Jump boolean function pointer to see if it was input. This sounded great, but when I sat down to code it, I realized that I would have to write a different function for each possible number of gamepad sticks, hats, and buttons, so that the function pointers could have something to point to. So I had to come up with a different method, and sadly, I did not fulfill my lifelong dream of actually using a function pointer in my game code[sad]

The other, and much simpler method, is to have each of the commands represented as an abstract class PadCommand, with derived classes JoystickCommand, HatCommand, and ButtonCommand. This way I can cover any amount of sticks, hats, and buttons a gamepad could have.

One reason I wrote this is that I'm going to code this tomorrow, and I don't want to forget what I was going to do[grin]
Previous Entry Maybe not
0 likes 3 comments

Comments

Drilian
What I had was, I had a structure defining an input assignment:

it was something like:


struct InputDefinition
{
  InputType inputType; // can be InputType_Joystick or InputType_Keyboard
  DWORD inputDeviceIndex; // always 0 for keyboard, can be 0-N for joysticks.
  InputValue inputValueType; // Either InputValue_Button or InputValue_Axis
  DWORD inputValueIndex; // Which button, key, or axis.
};


So, if you assigned a keyboard key, it would look like

id.inputType = InputType_Keyboard; // Keyboard
id.inputValueIndex = VK_RETURN;  // Only the value index needed for this, virtual key code


A joystick axis would be like:

id.inputType = InputType_Joystick;
id.inputDeviceIndex = 0; // first joystick in the system
id.inputValueType = InputValue_Axis;
id.inputValueIndex = 1 | Flag_AxisNegative; //assume that the x axis == index 0, y axis == index 1.


Note that, for the value index on that, I have a flag for negative (which is the high bit, 0x80000000). If that bit is not set, then it's the positive axis. Thus, RIGHT is generally assigned to axis 0, positive and LEFT is axis 0, negative.

A joystick button would be:

id.inputType = InputType_Joystick;
id.inputDeviceIndex = 0; // first joystick in the system
id.inputValueType = InputValue_Button;
id.inputValueIndex = 4; // 4th Joystick Button


So, I have an array of these (one for each control key, like Jump, Left, Right, Crouch, Attack, etc). I also had a for each, like InputDefinition::JoystickButton(0, 4); (Joystick 0, button 4).

Given that array, you could scan through to see which devices are assigned (i.e. if you have no joysticks on any controls, you don't have to poll any joysticks), to only poll the relevant devices.

Finally, to assign, it would essentially poll in a loop (for joysticks - for keyboard it'd check for windows messages), and whatever the first input was, it would build the corresponding structure and assign it.

This data was pretty easy to output to a text-based format.

You can probably make something a little cleaner than that, but that's how I did it, so that I only had to check the values of assigned buttons, and not loop through all buttons.

The downside is that it only allows one key per action, but you could theoretically make an array of up to N values for each action, so you could have 3 attack keys if you wanted (and add a third InputType_None for unassigned controls).

Hope that helps a bit, that system has worked really well for me :)
May 08, 2007 11:18 PM
Trapper Zoid
I'm soon going to be coding the input routines for my system. I'm planning on using the signal system I've been working on the last week, but in essence they're just managed function pointers. Input is one area where I think they work well.

The way I've planned to do mine is to have an interpreter module that acts like a translator between the raw input from the keyboard, joystick and mice and the rest of the system. Basically it's got raw input data going in, and it calls the right functions using function pointers (or signals in my case) going out.

If nothing is being pressed, it just sits there doing nothing. If something is pressed (say the 'K' key) it gets message saying so. The interpreter has some lookup for what keys map where. I'm leaning towards a map table that maps every key to something, even if most are just to a function that does nothing. It can then call the right function pointer for that key, so if the 'K' key was mapped to jump then pressing 'K' would cause the Jump function to be called. Mouse buttons and joystick buttons can also be mapped to functions this way, although mouse movement may need something special to send the amount of distance it has moved.
May 08, 2007 11:57 PM
Stompy9999
My basic plan is to have:

class PadCommand
{
    public:
       virtual bool active() = 0;
};

class ButtonCommand : public PadCommand
{
    private:
       int button_num;
    public:
       ButtonCommand(int n)
       {
           button_num = n;
       }

       bool active()
       {
           // Check Input system for a button press
       }
};

PadCommand *start;
start = new ButtonCommand(0);

if(start->active())
   // pause game




I'll see if this works when I get home and code it.
May 09, 2007 07:06 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement