Jump to content
  • Advertisement
Sign in to follow this  
sakky

action mapping you own action mapping.

This topic is 4736 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Does this sound right to you? I'm trying to create an input or action mapping system. Each device, a keyboard, mouse or joystick is handled semi differently. It's set up like this. Each action has a name, ID, type, source and function pointer. The name is used for representing to the user and the ID is used whensaving to an external configuration file. The type or source type is an integer the specifies weather the action responds to key press, axis, POV, slider, etc.. The source is an index into the array of available source types on the device. Sample action object: Action { "Shoot", // Name SHOOT_ID, // ID KEY_PRESS, // Source Type L_CONTROL, // Source ShootFunc // Function to perform } Now be fore I we get carried away, only one device can be configured at a time. So that means separate dialogs for keyboard, mouse and joystick. For now any ways. Well, there's a lot of input to worry about. You have joystick axes, POVs, buttons and sliders. Let alone the keyboard and mouse stuff. I didn't want to make special objects for each type of input, I just wanted a single structure that held the information on what to do with what. So I figured, why not use a DWORD. This is how I have it planed: //mouse HIWORD = mouse y offset LOWORD = mouse x offset HIWORD = old mouse wheel pos LOWORD = new mouse wheel pos // joystick HIWORD = axis or POV direction LOWORD = offset DWORD = current joystick slider pos Note that mouse clicks or any other buttons don't need any special parameters. This is because their source is directly related to their purpose. I don't need a bunch of switch statements for key presses or buttons, I'm trying to keep away from that. So like, you initialize a set of action maps by suppling a bunch of these structures to my little input engine. You make one call to UpdateInput, the devices are scanned and each device's action map set is ran through. If something happens the action function is called. Simple right? No, it's actually driving me crazy! God, every time I look at this design I'm thinking I screwed up some where, did I? I was trying to avoid making a bunch of function pointers or doing a union thing. I figured if I made the functions a little robust I could use one type for all. I hope I'm not wrong, it looks okay.... Any ways, I left all the configuration dialog stuff out because its boring. The actual action maps are more fun. But just to say, the dialogs can change the source type and source BUT the action is still the same....cool eh?

Share this post


Link to post
Share on other sites
Advertisement
Personally (and don't take this too hard), I think the way you've set up the DWORD packing is cryptic, hard to maintain, and generally ugly. It's certainly a clever solution, but I'd hate to have to update your code after you [wink]


I've recently co-designed and implemented an input mapping system for a very large and complex game (over-240-mappable-actions complex). It is made rather complicated by the fact that some actions are only valid in certain circumstances, but the basic underlying concept is fairly straightforward. This is how it's layed out:

- All "actions" are assigned action codes internally. Things like jump, run left, run right, shoot, that sort of thing. Actions are things you do by tapping a button, or do repeatedly by holding a button.

- "Direction controls" or "steering" is handled similarly. All the different things you can "steer" are given an ID internally. This might be things like your car in a racing game, your head and feet in an FPS (see Halo for a recognizable example of this), or gun turrets on a ship.

- All forms of input are either given IDs or IDs are used from DirectX (things like keys all have IDs; mouse buttons, joystick buttons, the POV hat, etc. are given internal ID codes).

- A set of "converter" functions can convert digital input to analog actions and vice versa. For instance, holding down an arrow key is converted to X units of movement per second; or perhaps moving the mouse 28 pixels to the left is converted to a "cast spell" action.

- A set of mapping tables is built, one for digital input and one for analog input. The mapping table takes an input ID (key, mouse button, joystick axis, etc.) and maps it to an action or steering ID. These can all be configured using a specially designed menu system.

- When the engine gets input from the player, it gets the ID of that input format and then looks up the ID in the mapping tables. If a digital input source is mapped to an analog action (steering), the appropriate conversion functions are used, and vice versa. The final result is that all input is converted, per frame, to the correct internal input IDs. For analog input, each ID is also given a value that corresponds to the amount to steer, etc.

- Each axis of an analog input device is a separate ID and therefore has a separate internal value. This way all analog input forms have one ID and one value, so storage is very simple and consistent. After mapping, the total values for each steering action are gathered and then applied, so it is possible to steer with both the keyboard and joystick at the same time, for example.


Again our system requires that some actions only be available at certain times (when special menus are opened, for instance) so it is actually quite a bit more intricate than that. However for most cases such complexity isn't needed and the method I described will work fine.

Share this post


Link to post
Share on other sites
I don't under stand! You pretty much described what I just described but in better words. My system is almost the same except that I don't differentiate digit and analog-it's all just input. For example, the directions are given and the offset from 0 is also given. You get this each frame, so I don't see what you're problem here is...

Next, I used the DWORD crunching because I didn't want to make a bunch a special states for each type of function you can get from an input device. If did do it that way, I would have separate actions defined for all types of controls. That seams pointless to me because I can just use MAKEDWORD(), HIWORD() and LOHWORD with a single DWORD and get all the information with only use one type of function. Much like the way a message procedure handles these things.

You said that actions only worked with menus??? I never said that, what I said was that you have to configure the actions in a menu, but all actions work regardless. This is the same thing as you described "specially designed menu system".

I think mine is a little better because I don't have so many IDs for things. Each device attached to the system is enumerated. Next, mapping is enabled for those devices if the user chooses to use them. If they do want to use those devices, then they just configure them and save the configuration so they don't have to keep configuring it all the time.

Any ways, each device has it's own set of action maps. Not every control is mapped an list of only the maps the user specified, the device has. Each time the input is updated, each VALID does...

1. ) Scan for input
2. ) Start with first action map list element
3. ) Read control data specified by action map
4. ) Call the action function if needed.
5. ) Move onto the next action in the list
6. ) Done!

I'm thinking that I don't even need the DWORD thing really. I can just use an int or something and have separate functions for moving left, right and what not and just use the int parameter as an offset. What I'm trying to do is not have a bunch of function types for things and use just one time. Most of the input is pretty much the same. Like, mouse coordinates are given by offset from the center screen position. Like wise, axis or POV coordinates are given in offsets from 0.

I was thinking about using a special class that is half abstract. Half abstract because some accessory functions are implemented but a process input method would be pure virtual. This way I could derive state classes that contain their own data and special implementation that handles things and the input gets sent to it each frame.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!