C # programming and development of game controllers-API (2)

Source: Internet
Author: User
Tags in degrees
Review passive development

In C # programming and development of game controllers-API (1) This article introduces the development of "passive mode. In this way, our program acts as only one message receiver. The system regularly tells us the current status of a game controller. After receiving the gamepad, our program can process it as needed. However, if you are a careful person, you will find that there will be a problem if you directly press the message event to process it, such as when we press a key (such as the upward direction key) and then open it, for our "people", the two actions we press and play should only indicate that we onlyClickThis button is used once. But for the system, it only mechanically and periodically notifies our program inA certain timeThe status of each button in the gameshield console.The time from press to pop-upThe system may alreadyPassed N timesNotification (N value is determined based on the uPeriod value set during capturing and the speed of your buttons), the notification handle has buttons in the pressed status, if we directly process click events based on the message package, it will lead to problems (for example, in a game, we designedRight-click the handle and move the role one step forward.. However, from the time we press the button to the time when the button is popped up, the human response speed is much slower than the processing speed of the computer, so during this very short period of time, the system may have noticed that more than 10 message packets indicate that the right-click of the game controller has been pressed, which leads to one right-click, but the role in the game may have moved more than 10 steps, this is not the result we want ). So how can we deal with this "click" event to avoid repeated notifications? This is what we will focus on at the end of this article ......

Before explaining the solution to this problem, Let's explain a development method mentioned above.

 

Active Development

Actively, we do not need to apply for registration from the system to capture a game handle.Get the status information of the gamepad on time.

In this case, we need to use the following API functions.

/// <Summary> /// obtain the joystick position and button status /// </summary> /// <param name = "uJoyID"> </param> /// <param name = "pji"> </param> // <returns> </returns> [DllImport ("winmm. dll ")] public static extern int joyGetPos (int uJoyID, ref JOYINFO pji ); /// <summary> /// obtain the joystick position and button status /// </summary> /// <param name = "uJoyID"> </param> /// <param name = "pji"> </param> // <returns> </returns> [DllImport ("winmm. dll ")] public static extern int joyGetPosEx (int uJoyID, ref JOYINFOEX pji );

 

You can select one of the preceding two API functions, but the joyGetPos function can only get the status of four buttons, 1, 2, and 4. Therefore, we recommend that you do not use it,The following describes the joyGetPosEx function.!

JOYINFO and JOYINFOEX are struct. Their definitions are as follows:
# Location and button status of the region gamepad handle /// <summary> // location and button status of the gamepad handle /// </summary> [StructLayout (LayoutKind. sequential)] public struct JOYINFO {public int wXpos; public int wYpos; public int wZpos; public int wButtons ;} /// <summary> /// the location of the gamepad and the button status /// </summary> [StructLayout (LayoutKind. sequential)] public struct JOYINFOEX {// <summary> // Size, in bytes, of this structure. /// </summary> public int dwSize; // <summary> // Flags indicating the valid information returned in this structure. members that do not contain valid information are set to zero. /// </summary> public int dwFlags; // <summary> // Current X-coordinate. /// </summary> public int dwXpos; // <summary> // Current Y-coordinate. /// </summary> public int dwYpos; // <summary> // Current Z-coordinate. /// </summary> public int dwZpos; // <summary> // Current position of the rudder or fourth joystick axis. /// </summary> public int dwRpos; // <summary> // Current th axis position. /// </summary> public int dwUpos; // <summary> // Current sixth axis position. /// </summary> public int dwVpos; // <summary> // Current state of the 32 joystick buttons. the value of this member can be set to any combination of JOY_BUTTONn flags, where n is a value in the range of 1 through 32 corresponding to the button that is pressed. /// </summary> public int dwButtons; // <summary> // Current button number that is pressed. /// </summary> public int dwButtonNumber; // <summary> // Current position of the point-of-view control. values for this member are in the range 0 through 35,900. these values represent the angle, in degrees, of each view multiplied by 100. /// </summary> public int dwPOV; /// <summary> // Reserved; do not use. /// </summary> public int dwReserved1; // <summary> // Reserved; do not use. /// </summary> public int dwReserved2;} # endregion

 

For example, when we use joyGetPosEx to obtain the status of a game device, we must first initialize the JOYINFOEX schema instance and set the value of the dwSize parameter, that is, the memory space occupied by the JOYINFOEX struct. sizeOf ). To obtain other parameters of a game device, you must set the value of the dwFlags parameter! Otherwise, you can only obtain the coordinate value (dwXPos ). For game controllers, if we need to obtain the status of other buttons, set dwFlags to JOY_RETURNBUTTONS to indicate that we need to return the status of all buttons.

Sample Code:

JoystickAPI.JOYINFOEX infoEx = new JoystickAPI.JOYINFOEX();            infoEx.dwSize = Marshal.SizeOf(typeof(JoystickAPI.JOYINFOEX));            infoEx.dwFlags = (int)JoystickAPI.JOY_RETURNBUTTONS;            int result = JoystickAPI.joyGetPosEx(this.Id, ref infoEx);

If the joyGetPosEx function successfully obtains the handle status data, JOYERR_NOERROR (value: 0) is returned. Otherwise, if other values are returned, the acquisition fails.

After the data is obtained, the status data of the corresponding game controller is stored in the JOYINFOEX structure instance. To determine whether the direction keys are pressed, you can judge the values of dwXPos and dwYPos. To determine whether other buttons are pressed, you can determine the value of dwButtons. The judgment method is described in the previous chapter. I will not elaborate on it here, or you can refer to the source code provided later.

 

Because the "Active Mode" has only one "timeliness", in order to be able to monitor the key events of the game handle at any time, you must perform a "Round Robin" acquisition, an event notification (notify? Is it like "passive mode "? Well, when we applied to capture a game handle from the system, the system finally helped us perform "Round Robin" operations !). There are multiple methods to achieve "Round Robin", such as using an independent thread for an endless loop or using Timer for scheduled execution.

 

However, when our operations go into "Round Robin", if it is handled directly by joyGetPostEx, it will also encounter the bad problem mentioned in the article! BecauseBoth "Active Mode" and "passive mode" can only get the current status of the gamepad button.(Press or not press ). How can this problem be solved?

 

Solved the duplicate button status problem.

To solve this problem, if you have clarified your ideas, it is actually a very simple method.

What we get through the API is the current status of the gamepad button (pressed or not pressed ). Therefore, we can record the number of buttons that are being pressed at a certain time every time we monitor the game controller in the "Round Robin, in this way, if a button is also monitored for the current "Round Robin" operation, the button is compared with the previous one. If the button is the same, it indicates that this button is still in the last press state, so you no longer need to send a message notification to the program. If they are different, a new button notification is issued and the button number that is pressed this time is recorded.

The pseudocode is as follows:

Previusbuttons = none;
// An endless loop.
While (true ){
If (joyGetPosEx (handle number, ref joyInfo) = successful ){
JoyButtons buttons = get the currently pressed Button (joyInfo );
If (buttons! = None ){
If (buttons! = Previusbuttons ){
// This button is different from the last button.
OnClick (buttons );
// Record the button pressed this time
Previusbuttons = buttons;
}
}
}
Pause uPeriod in milliseconds;
}

After such processing, every time we press the button on the handle, our program only receives a button notification. It seems that our goal has been achieved. But in normal games, we press not only one key at the same time. For example, if we cut down the enemy while walking, we may press the right arrow key and press A or B, so what will happen again? In this way, the following situations may occur in our "Round Robin" ("->" indicates the order ):

Obtain the right direction key currently pressed (1)-> obtain the right direction key currently pressed (2) -> obtain the "right arrow key" and "A" currently pressed (3)-> obtain the "right arrow key" currently pressed (4) -> obtain the "right arrow key" and "B key (5)" currently pressed.-> obtain the "right arrow key" (6 )......

In the above, (1) and (2) can be merged into one by means of the preceding solution, but in step 3rd, because there are two keys currently pressed, the previous button only has one, so because (2) the button is different, another button notification is issued. And so on, from step (1) To step (6), the program considers that the "right direction key" has been pressed five times in total! But for our "people", this is not the result we want, because we just keep holding down the "right arrow key", so we should only press it once. The above solution is not perfect.

Let's take A closer look at the difference between (2) and (3) in the above process. You can see that there is only one A key between them. If the "right direction key" has sent A button message at the first step, in step 3, if we only send A "A key" button message, that is to say, if the difference between the current set of keys and the previous set of keys is only sent, then in the above process, only the following notifications are sent: in step 1, A "right direction key" button notification is issued, (3) A key notification is issued, and (5) B key notification is issued. In this way, the problems in the beginning can be solved perfectly !!

(For sample code, refer to the OnTimerCallback function in the source code)

 

At this point, the article "C # programming and development of game controllers" is complete, in the next article, we will explain how to implement the software "simulate the keyboard or mouse with the game handle" described in the first article. In short, if you are interested, you may want to reply to the post to support me.

 

Download source code:/Files/kingthy/JoyKeys.Voluntary.rar

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.