Thursday, 4 January 2007

MDX Custom Action Mapping


[Warning: This article is obsolote. I´d suggest you to read the Refreshed version here.]

In the last few months I realized that I didn´t have a decent controller configuration system and I started to look at DirectInput´s Action Mapping.

After a couple of weeks working around it, my frustration growed up and I decided to make my own full ActionMapping system (supporting mapping to several devices). Why?

1.- The documentation of Microsoft about AcionMapping sucks (no offense!)

2.- ManagedDirectX version of Action Mapping seems to be incomplete, just like if they wanted to finish asap, regardless what was the final result: undocumented methods, parameters, etc.

3.- Error reports coming out from methods is something just, impossible to understand without good specs. One example: The Acquire() method always throws "Argument Exception". Why? It can be due to a dozen of things.

4.- To push me even forwarder in my willing of comitting suicide, most of the actionMapping samples have been removed from the SDK. As there´s no human able to find old samples in Microsoft´s websites, I had to dive into the pile of old CDs that, thank to the great lord, I haven´t thrown away yet. Hey you gus, why just not putting there a special website with all the DX samples published ever?

5.- Of course, after finding the samples, they are all C++, so you have to bring all your c++ knowledge to life and start studying them.

6.- Even after all this process, I honestly have to say that I couldn´t determine the behaviour of some methods. They seem to be chaotic and I dont understand what happens sometimes. I loose the action map when set the dataFormat and vice-versa.

7.- Another and last (I hope) reason. What´s all that stuff about pre-defined genres, device types and so on... ??? Who decided that? Did you really thought that it was gonna be enough with a bunch of pre-definded genres and types? To be even worse, they are all mixed up in the Managed DirectInput namespaces, with no order. If you don´t know what Im talking about, I´ll say that, in action mapping, you have to assign a Genre (like "driving", "Fighting", "SpaceSimulator", ...) to your ActionMap. Each genre has it´s own Default Actions, and no more. This default actions are what you map your game actions to, and basing on this mapping and on the genre of your Actionmap, methods of DInput may even crash. Goddamn it! And, what happens if you need more actions than the pre-defined? Yes, I know there´s something called "AnyButton", "AnyAxis" and so on... but... I just don´t like it. i.e., now, with the new Logitech G25... it comes with a clutch pedal. There´s no DX Action for the clutch in the Driving Genre. It´s quite clear that DX was designed in U.S ;)

8.- No! it was not the last reason, more coming to my mind. How standard ActionMapping saves and recovers actionMap configurations is something misterious. Actually, it saves a per-application file in ApplicationData\Microsoft\DirectInput special folder with all the settings. DirectInput loads and saves it "behind the scene", and that´s something I don´t like at all. Why not just putting there a "SaveActionMapToFile(), LoadActionMapFromFile()" methods instead ?. I want to be able to decide where the file will be saved and how! In addition to that, while development, it´s behaviour its very unconfortable, because when app´s guid changed, DirectInput generates additional files. You can easily end up with hundreds of config files in that folder if that happens. Microsoft recommends to manually delete the contents of that folder periodically while development. Arrgglll....

9.- More and more reasons... The Acion Mapping configuration dialog. What can I say? It´s almost un-customizable. It´s behaviour is absolutely undocumented. I really think that DirectInput is the ugly brother of DirectX. It does not follow the quality standard present in other parts of the libs.

Anyway... No more time wasted in ActionMapping. I decided to make my own, custom, brighty, magnificent, easy Action Mapping System. This could seem an easy task, but again, just like always I try to make something new with DirectInput, it´s not.

The main task we want to make in our ActionMapping is to be able to save to disk and recover a controller configuration, which assign a InputDevice and an Object of that device to a GameAction defined by us.

As this tutorial is gonna take long, I will divide it into parts.

PART 1: Define game actions

Will put all of our actions in an enumeration.

enum eGameActions
MoveForward = 0,
MoveBackward = 1,
TurnLeft = 2,
TurnRight = 3,
Shoot = 4,

NumberOfActions = 5 // Not an action, just to know the number

If you don´t know, there´s a very useful class in the .Net Framework called System.Enum. This class has static methods to loop through members of an enumeration and more. Things like:

Enum.GetNames ( typeof (eGameActions) ) : Will return a string[] with: "MoveForward", "MoveBackward" and so on.

Enum.IsDefined( typeof(eGameActions), 6 ): Will return false because eGameActions doesnt have that member.

more coming tomorrow ...

Cheers !

No comments: