-
Notifications
You must be signed in to change notification settings - Fork 2
Joystick
#Joystick Most input API's make a clear distinction between a joystick and a gamepad.
- a joystick is a loose collection of buttons and axis. You can get how many buttons the joystick has (N), and the state of each button (usually button 1 to N). Same thing with the axis, a gamepad with two thumbsticks has 4 axis: left X, left Y, right X and right Y.
- a gamepad is a joystick, however it has strictly defined button mapping. The mapping consists of: one d-pad (4 buttons), two thumb sticks with four axis each of which is a button as well, four main buttons (A, B, X, Y) and up to seven auxilary buttons (start, back, guide, l-shoulder, r-shoulder, left stick, right stick)
Our framework takes the gamepad approach, we have an easy to use API for re-mapping buttons. We don't use the built in definition of a gamepad, instead our definition is:
- Four Main Butons: A, B, X, Y
- Four Directional Buttons: Left, Right, Start, Select
- Four Shoulders: L1, L2, R1, R2
- Three Auxilary Buttons: Start, Select, Home
- Four Axis: LeftX, LeftY, RightX, RightY
The API supports up to 4 controllers. Almost all functions take a controller id, this is a number from 0 to 3.
All joystick buttons are represented using the OpenTK.Input.JoystickButton enum, axis are represented with the OpenTK.Input.JoystickAxis enum. The Input manager class has a public inner class called InputManager.ControllerMapping which has a hard definition for each button, i suggest taking a peek at the source code to see it's capabilities.
#Controller Info There are a few utility methods to gather information about the currently connected controllers:
public Dictionary<int, string> Gamepad
public int NumGamepads
bool IsConnected(int padNum)
The Gamepad getter attempts to get a kvp where the value is a string that is the human readable name for each gamepad and the key is the gamepad index (0 to 3). Unfortunitaley this function is not guaranteed to work on every machine and it is unreliable. For instance, on a macbook every controller has a string id of "HID" for Human Interface Device. Don't rely on this method, it's included as a novelty
GetNumGamepads does exactly what it said it would, it returns how many gamepads are connected
Given a gamepad index IsConnected will return true of false appropriateley.
#Controller capabilities Once you know that a controller is connected it may be useful to query if it has the buttons you are looking for. We provide one function for each button:
bool HasAButton(int padNum) {
bool HasBButton(int padNum) {
bool HasXButton(int padNum) {
bool HasYButton(int padNum) {
bool HasSelectButton(int padNum) {
bool HasStartButton(int padNum) {
bool HasHomeButton(int padNum) {
bool HasDPad(int padNum) {
bool HasL1(int padNum) {
bool HasL2(int padNum) {
bool HasR1(int padNum) {
bool HasR2(int padNum) {
bool HasLeftStick(int padNum) {
bool HasRightStick(int padNum) {
Why do we keep a discreet function for each button? Why not just a HasButton(JoystickButton button) function? Because JoystickButton only has JoystickButton.Button1, not JoystickButton.ButtonA. These functions check if a given button is mapped, not what it is mapped to or if it even exists. You can map all buttons to the same physical button, and all of these functions will return true.
#Checking button states There is a discreet function to check the state of each mappable button. These functions are IsDown, IsUp, IsPressed and IsReleased
public bool ADown(int padNum) {
public bool AUp(int padNum) {
public bool APressed(int padNum) {
public bool AReleased(int padNum) {
public bool BDown(int padNum) {
public bool BUp(int padNum) {
public bool BPressed(int padNum) {
public bool BReleased(int padNum) {
public bool XDown(int padNum) {
public bool XUp(int padNum) {
public bool XPressed(int padNum) {
public bool XReleased(int padNum) {
public bool YDown(int padNum) {
public bool YUp(int padNum) {
public bool YPressed(int padNum) {
public bool YReleased(int padNum) {
public bool SelectDown(int padNum) {
public bool SelectUp(int padNum) {
public bool SelectPressed(int padNum) {
public bool SelectReleased(int padNum) {
public bool StartDown(int padNum) {
public bool StartUp(int padNum) {
public bool StartPressed(int padNum) {
public bool StartReleased(int padNum) {
public bool L1Down(int padNum) {
public bool L1Up(int padNum) {
public bool L1Pressed(int padNum) {
public bool L1Released(int padNum) {
public bool L2Down(int padNum) {
public bool L2Up(int padNum) {
public bool L2Pressed(int padNum) {
public bool L2Released(int padNum) {
public bool R1Down(int padNum) {
public bool R1Up(int padNum) {
public bool R1Pressed(int padNum) {
public bool R1Released(int padNum) {
public bool UpDown(int padNum) {
public bool UpUp(int padNum) {
public bool UpPressed(int padNum) {
public bool UpReleased(int padNum) {
public bool DownDown(int padNum) {
public bool DownUp(int padNum) {
public bool DownPressed(int padNum) {
public bool DownReleased(int padNum) {
public bool LeftDown(int padNum) {
public bool LeftUp(int padNum) {
public bool LeftPressed(int padNum) {
public bool LeftReleased(int padNum) {
public bool RightDown(int padNum) {
public bool RightUp(int padNum) {
public bool RightPressed(int padNum) {
public bool RightReleased(int padNum) {
#Checking joystick states You can check the values of the left and right stick with the following methods
public float LeftStickX(int padNum) {
public float LeftStickY(int padNum) {
public PointF LeftStick(int padNum) {
public float RightStickX(int padNum) {
public float RightStickY(int padNum) {
public PointF RightStick(int padNum) {
The center point of an axis is 0.0, all the way to the left or up is -1.0 and al the way to the right or down is 1.0.
All joysticks have what we call a dead zone. Very close to the 0.0 mark, maybe even up to 0.1 the value returned is inaccurate, this is due to hardware accuracy. To make up for this we introduce a "Dead Zone", this allows us to ignore values below a certain threshold.
You can get and set a specific controllers deadzone with these functions:
public float GetDeadzone(int controllerNum) {
public void SetDeadzone(int controller, float value) {
#Mapping
You can configure manual mapping for a joystick with the InputManager.ControllerMapping class. To get an instance of this class use the following method
public ControllerMapping GetMapping(int joyNum) {
Like so
ControllerMapping control1Map = GetMapping(1);
This has a getter and setter for each defined button, use like so:
ControllerMapping control1Map = GetMapping(1);
control1Map.A = JoystickButton.Button1;
Now the question becomes, which button is button1? How do we actually get the key for a button that was pressed? Well, there is a nifty helper function for this:
public bool GetButton(int joystick, ref JoystickButton button, params JoystickButton[] excludeButtons) {
public bool GetAxis(int joystick, JoystickAxis axis, params JoystickAxis[] excludeAxis) {
GetButton will return true if a button on the specified joystick was pressed, if so, it will fill the button out into the reference that was passed in. GetAxis works the same way.
The excludeButtons and excludeAxis arguments make these function have optional arguments at the end. Any value passed in as an optional argument will not return true of pressed, they are essentially a list of buttons and axis to ignore when it comes to mapping. We will see an example of these being used later.
Here is an example of how mapping could be used
// Just pseudo code
public void Update(float dt) {
InputManager i = InputManager.Instance;
GraphicsManager g = GraphicsManager.Instance;
// Don't update game if no controller is present
if (!i.IsConnected(0)) {
g.DrawString("Please connect game pad", new Point(), Color.Red);
}
// If A hasn't been mapped yet, map it
else if (!i.HasAButton(i)) {
g.DrawString("Controller format unknown, press button you want to use for jumping (A button)", new Point(), Color.Red);
JoystickButton newAButton = JoystickButton.Button1; // Some default
// Waiting for button to be pressed, with no loop. This if will
// not block the update method
if (i.GetButton(newAButton, ref newAButton)) {
// If we made it in here, some button was pressed
GetMapping(0).A = newAButton;
}
}
// We have a controller, and A is mapped
else {
if (i.APressed(0)) {
gameCharacter.DoJump(dt); // Do aomw work
}
}
}