Skip to content
Gabor Szauer edited this page Aug 23, 2015 · 3 revisions

#Joystick Example The joystick is one of the harder inputs to use, it's probably a good idea for us to go trough creating a simple application that uses it together,

In this application where we will have a red square on screen, using the joystick will move the square around, and pressing an action button will change it's color. Here is my example of how this should work.

If you think you can figure out how to build this on your own, give it a go; If you get stuck, or just want to follow how i would do it, read on

#Globals Let's start by defining some global variables. We're going to have 3 variables, position, colors and currentColor,

private static RectangleF position = new RectangleF(100, 100, 20, 20);
private static Color[] colors = new Color[] { Color.Red, Color.Blue, Color.Green, Color.Yellow };
private static int currentColor = 0;

The position rectangle is where we are going to draw the rectangle on screen, the colors array is the colors that the rectangle can possibly be and currentColor is what color the current rectangle is going to be.

#Initialize We're going to initialize the GraphicsManager and the InputManager

public static void Initialize(object sender, EventArgs e) {
    GraphicsManager.Instance.Initialize(Window);
    InputManager.Instance.Initialize(Window);
}

#Shutdown Since we initialized the GraphicsManager and the InputManager lets make sure to shut them both down.

public static void Shutdown(object sender, EventArgs e) {
    InputManager.Instance.Shutdown();
    GraphicsManager.Instance.Shutdown();
}

#Render Let's start off by drawing the square.

public static void Render(object sender, FrameEventArgs e) {
    GraphicsManager.Instance.ClearScreen(Color.CadetBlue);
    
    GraphicsManager.Instance.DrawRect(position, colors[currentColor]);

    GraphicsManager.Instance.SwapBuffers();
}

At this point you should see a red square on screen, like so:

SCREEN1

#Button mapping We don't have joystick profiles, therefore we don't know what button does what. Let's write some code to assign the action button. We could map the buttons in the Update function, but it will be easier to understand if we map them right in the Render function.

If there is no controller connected, we're gonna print something to screen to let the user know. If a controller is connected, we will ask the user to press the "A" button. They can choose anything. Once the "A" button is mapped, we will draw the square.

We are going to check if the A button is mapped with HasAButton, then we will use the GetButton function to get the first pressed button in a non blocking manner.

public static void Render(object sender, FrameEventArgs e) {
    GraphicsManager.Instance.ClearScreen(Color.CadetBlue);

    if (!InputManager.Instance.IsConnected(0)) {
        GraphicsManager.Instance.DrawString("Please connect a controller", new PointF(10, 10), Color.Red);
    }
    else if (!InputManager.Instance.HasAButton(0)) {
        GraphicsManager.Instance.DrawString("A button not mapped, press A button", new PointF(10, 10), Color.Red);
        JoystickButton newAButton = JoystickButton.Button0; // Some default

        if (InputManager.Instance.GetButton(0, ref newAButton)) {
            InputManager.Instance.GetMapping(0).A = newAButton;
        }
    }
    else {
        GraphicsManager.Instance.DrawRect(position, colors[currentColor]);
    }

    GraphicsManager.Instance.SwapBuffers();
}

Lets use the Update function to check if the button was pressed. Don't forget, the input manager has an *Update function that needs to be called for buffered input.

public static void Update(object sender, FrameEventArgs e) {
    InputManager.Instance.Update();

    if (InputManager.Instance.APressed(0)) {
        currentColor += 1;
        if (currentColor >= colors.Length) {
            currentColor = 0;
        }
    }
}

At this point your application should look like this:

SCREEN2

After mapping the "A" button you should see the square on screen. Subsequently pressing the "A" button will change the color of the square.

#Axis debugging We're going to implement axis mapping to move the square on screen around. The way controller axis works is a bit odd, they move around randomly. By default the dead zone is 0.25 which should suffice for now. Also worth noting, the shoulder buttons on a controller are implemented as axis.

To make debugging easier, we will print out all of the axis, this should visually show you the values of each axis at all times. Notice, be default none of the axis are usually at 0 exactly, this is why we need that dead zone. Update the Render function:

public static void Render(object sender, FrameEventArgs e) {
    GraphicsManager.Instance.ClearScreen(Color.CadetBlue);

    if (!InputManager.Instance.IsConnected(0)) {
        GraphicsManager.Instance.DrawString("Please connect a controller", new PointF(10, 10), Color.Red);
    }
    else if (!InputManager.Instance.HasAButton(0)) {
        GraphicsManager.Instance.DrawString("A button not mapped, press A button", new PointF(10, 10), Color.Red);
        JoystickButton newAButton = JoystickButton.Button0; // Some default

        if (InputManager.Instance.GetButton(0, ref newAButton)) {
            InputManager.Instance.GetMapping(0).A = newAButton;
        }
    }
    else {
        GraphicsManager.Instance.DrawRect(position, colors[currentColor]);
    }

	int y = 0;
    JoystickState state = Joystick.GetState(0);
    InputManager.ControllerMapping buttons = InputManager.Instance.GetMapping(0);
    foreach (JoystickAxis enumVal in Enum.GetValues(typeof(JoystickAxis))) {
        Color clr = Color.Black;
        GraphicsManager.Instance.DrawString(enumVal.ToString() + ": " + state.GetAxis(enumVal), new PointF(10, 30 + y), clr);
        y += 20;
    }

    GraphicsManager.Instance.SwapBuffers();
}

At this point, your application should look like this:

SCREEN3

#Axis mapping Let's map the left X and Y axis, and make them responsible for moving the square around on screen. This is going to be very similar to the button mapping code, in that we're going to put the mapping in the Render function, and the game related logic in the Update function.

In Render, we're going to use the HasLeftStick function to see if the left stick is mapped. The left stick is only considered mapped if both the X and Y axis of the left stick are mapped. We can check the indevidual X and Y axis mapping by getting a reference to the controllers InputManager.ControllerMapping object, trough the GetMapping function.

Finally, we're going to update the debug render code to draw the X axis in purple and Y axis in blue. This will let us see in the debugger window what axis are controlling movement:

public static void Render(object sender, FrameEventArgs e) {
    GraphicsManager.Instance.ClearScreen(Color.CadetBlue);

    if (!InputManager.Instance.IsConnected(0)) {
        GraphicsManager.Instance.DrawString("Please connect a controller", new PointF(10, 10), Color.Red);
    }
    else if (!InputManager.Instance.HasAButton(0)) {
        GraphicsManager.Instance.DrawString("A button not mapped, press A button", new PointF(10, 10), Color.Red);
        JoystickButton newAButton = JoystickButton.Button0; // Some default

        if (InputManager.Instance.GetButton(0, ref newAButton)) {
            InputManager.Instance.GetMapping(0).A = newAButton;
        }
    }
    else if (!InputManager.Instance.HasLeftStick(0)) {
        InputManager.ControllerMapping map = InputManager.Instance.GetMapping(0);

        if (!map.HasLeftAxisX) {
            GraphicsManager.Instance.DrawString("X axis not found, move left stick horizontally (sizeways)", new PointF(10, 10), Color.Red);
        }
        else if (!map.HasLeftAxisY) {
            GraphicsManager.Instance.DrawString("Y axis not found, move left stick vertically (up or down)", new PointF(10, 10), Color.Red);
        }

        JoystickAxis newAxis = JoystickAxis.Axis0; // Some default
        if (map.HasLeftAxisX) { // We have X, need Y
			// Last argument, a variable number of Axis to ignore
            if (InputManager.Instance.GetAxis(0, ref newAxis, map.LeftAxisX)) {
                map.LeftAxisY = newAxis;
            }
        }
        else {
            if (InputManager.Instance.GetAxis(0, ref newAxis)) {
                map.LeftAxisX = newAxis;
            }
        }
    }
    else {
        GraphicsManager.Instance.DrawRect(position, colors[currentColor]);
    }

    int y = 0;
    JoystickState state = Joystick.GetState(0);
    InputManager.ControllerMapping buttons = InputManager.Instance.GetMapping(0);
    foreach (JoystickAxis enumVal in Enum.GetValues(typeof(JoystickAxis))) {
        Color clr = Color.Black;
        if (enumVal == buttons.LeftAxisX) {
            clr = Color.Purple;
        }
        if (enumVal == buttons.LeftAxisY) {
            clr = Color.Blue;
        }
        GraphicsManager.Instance.DrawString(enumVal.ToString() + ": " + state.GetAxis(enumVal), new PointF(10, 30 + y), clr);
        y += 20;
    }

    GraphicsManager.Instance.SwapBuffers();
}

Running the application now, it will ask you first to assign an action button, then to assign an X axis and finally to assign a Y axis. While the debug window will show the mapped axis in different colors, moving the joystick does nothing, let's fix that in the Update function:

public static void Update(object sender, FrameEventArgs e) {
    InputManager.Instance.Update();

    if (InputManager.Instance.APressed(0)) {
        currentColor += 1;
        if (currentColor >= colors.Length) {
            currentColor = 0;
        }
    }

    if (InputManager.Instance.LeftStickX(0) < 0) { // < 0 = left
        position.X -= 80.0f * Math.Abs(InputManager.Instance.LeftStickX(0)) * (float)e.Time;
    }
    else if (InputManager.Instance.LeftStickX(0) > 0) { // < 0 = right
        position.X += 80.0f * Math.Abs(InputManager.Instance.LeftStickX(0)) * (float)e.Time;
    }

    if (InputManager.Instance.LeftStickY(0) < 0) { // y < 0 = down
        position.Y += 80.0f * Math.Abs(InputManager.Instance.LeftStickY(0)) * (float)e.Time;
    }
    else if (InputManager.Instance.LeftStickY(0) > 0) { // y > 0 = up
        position.Y -= 80.0f * Math.Abs(InputManager.Instance.LeftStickY(0)) * (float)e.Time;
    }
}

Thats it, once all the buttons and axis of a controller are mapped, you should be able to move the square on screen. If you are having any issues with the code, here is my full implementaiton of Program.cs

#On your own Now that you got your feet wet with the joystick, see if you can implement these features into the demo application

  • Add D-Pad support. So that we can move the character around the screen with both the joystick and some D-Buttons.
  • Add support for the B button, where the A button cycles colors forward, the B buttons should cycle colors in reverse

Clone this wiki locally