3
\$\begingroup\$

Currently I have something like this:

public bool IsLeftMouseButtonDown()
{
    return currentMouseState.LeftButton == ButtonState.Pressed && previousMouseSate.LeftButton == ButtonState.Pressed;
}

public bool IsLeftMouseButtonPressed()
{
    return currentMouseState.LeftButton == ButtonState.Pressed && previousMouseSate.LeftButton == ButtonState.Released;
}

public bool IsLeftMouseButtonUp()
{
    return currentMouseState.LeftButton == ButtonState.Released && previousMouseSate.LeftButton == ButtonState.Released;
}

public bool IsLeftMouseButtonReleased()
{
    return currentMouseState.LeftButton == ButtonState.Released && previousMouseSate.LeftButton == ButtonState.Pressed;
}

This is fine. In fact, I kind of like it. However, I'd hate to have to repeat this same code five times (for right, middle, X1, X2). Is there any way to pass in the button I want to the function so I could have something like this?

public bool IsMouseButtonDown(MouseButton button)
{
    return currentMouseState.IsPressed(button) &&  previousMouseState.IsPressed(button);
}

public bool IsMouseButtonPressed(MouseButton button)
{
    return currentMouseState.IsPressed(button) &&  !previousMouseState.IsPressed(button);
}

public bool IsMouseButtonUp(MouseButton button)
{
    return !currentMouseState.IsPressed(button) &&  previousMouseState.IsPressed(button);
}

public bool IsMouseButtonReleased(MouseButton button)
{
    return !currentMouseState.IsPressed(button) &&  previousMouseState.IsPressed(button);
}

I suppose I could create some custom enumeration and switch through it in each function, but I'd like to first see if there is a built-in solution or a better way..

Thanks!

\$\endgroup\$

3 Answers 3

7
\$\begingroup\$

The naming of your functions is hard to determine, and looks like you've just covered the 4 boolean cases. For example, what is the purpose of IsMouseButtonsDown(MouseButton button)? The only case I can think of is where you want to keep a flag for a player holding down a key to charge something up. But you'd probably want to keep that flag stored elsewhere.

For checking inputs, I like to do something like this:

[Flags]
public enum MouseButton
{
    Left   = 0x01, // equiv 0b0001
    Middle = 0x02, // equiv 0b0010
    Right  = 0x04, // equiv 0b0100
    None   = 0x00  // equiv 0b0000
}

public class MouseInput
{
    private MouseButton mouseButtonsThisFrame;
    private MouseButton mouseButtonsLastFrame;
    private MouseState currentMouseState;

    public void update()
    {
        mouseButtonsLastFrame = mouseButtonsThisFrame;
        mouseButtonsThisFrame = MouseButton.None;

        currentMouseState = GetMouseState();
        mouseButtonsThisFrame |=  currentMouseState.LeftButton == ButtonState.Pressed ? MouseButton.Left : MouseButton.None;
        mouseButtonsThisFrame |=  currentMouseState.MiddleButton == ButtonState.Pressed ? MouseButton.Left : MouseButton.None
        mouseButtonsThisFrame |=  currentMouseState.RightButton == ButtonState.Pressed ? MouseButton.Right : MouseButton.None; 
    }

    public bool wasPressed(MouseButton button)
    {
        // Not quite clear and correct as noted by Cypher
        //return (mouseButtonsLastFrame & button) == button && (mouseButtonsThisFrame & button) == button;

        // This is a little better
        return (mouseButtonsLastFrame & button) == button && (mouseButtonsThisFrame & button) != button;
    }

    public bool isDown(MouseButton button)
    {
        return (mouseButtonsThisFrame & button) == button;
    }

    public bool isUp(MouseButon button)
    {
        return ((mouseButtonsThisFrame ^ button) & button) == button;
    }
}

That way you can check for something in your update loop like so:

public void update()
{
    if (mouseInput.wasPressed(MouseButton.Left | MouseButton.Right) {
        ExecuteDoubleMouseButtonComboAttack();
    } else if (mouseInput.wasPressed(MouseButton.Left)) {
        ExecutePitifulSingleMouseButtonAttack();
    }
}

Of course you'd want to introduce some timing compensation for the double button stuff, but this style of managing input has proven to be nice and flexible for me. Like ClassicThunder says, you're kind of stuck in a polling model with XNA. The system event work around works but only if you don't want to deploy to Xbox.

\$\endgroup\$
6
  • 2
    \$\begingroup\$ Decorate the enumeration with a [Flags] attribute. \$\endgroup\$ Feb 20, 2012 at 6:00
  • 1
    \$\begingroup\$ +1 I actually have the MouseButtons enumeration set up as flags on my projects too. :) It allows me to write methods such as MouseButtons GetPressedMouseButtons() for when I want to check for any mouse button being pressed without having to specify one of them - the method returns that information for me. \$\endgroup\$ Feb 20, 2012 at 6:10
  • \$\begingroup\$ @AndrewPrice I changed the enum flag values to look like David's answer. The 0x001, 0x010, etc. make the concept more clear, but these values make bit twiddling easier (currently struggling with Flixel's direction consts). \$\endgroup\$ Feb 20, 2012 at 8:45
  • \$\begingroup\$ I believe wasPressed() should read: return (mouseButtonsLastFrame & button) == button && (mouseButtonsThisFrame ^ button) == button; \$\endgroup\$
    – Cypher
    Jun 10, 2012 at 18:32
  • \$\begingroup\$ @Cypher That wouldn't work since the ^ could return false positives. The idea is to mask against the button parameter. Admittedly the exact meaning of wasPressed() in the example isn't clear. In this case it was just meant to be pressed_Last_Frame_And_Hasnt_Been_Released(). Which is not useful, but illustrates the point. Looking at it now, a more correct implementation would have been return (mouseButtonsLastFrame & button) == button && (mouseButtonsThisFrame & button) != button;, but then if you want to use this for multiple-button actions, you'd want a time window for human error. \$\endgroup\$ Jun 10, 2012 at 23:19
2
\$\begingroup\$

In the example that you wanted to achieve, you used a MouseButton enumeration, but unfortunately there's no such type in XNA.

Nonetheless, I would actually recommend you to go ahead with your idea, create that enumeration yourself and branch on it. It's what I do on my projects and it's also useful when I want to store which mouse buttons were pressed inside an event. And if you mark it as Flags you can even store and check for multiple buttons at once:

[Flags]
public enum MouseButtons
{
    None = 0x0,
    Left = 0x1,
    Middle = 0x2,
    Right = 0x4,
    X1 = 0x8,
    X2 = 0x10
}

But since you asked if it was possible to write something like currentMouseState.IsPressed(button) here's an extra trick. If instead of passing it an enumeration you don't mind passing it the name of the button, then it is possible using a little bit of reflection and an extension method. Just add this class to your project and you're good to go:

public static class MouseStateExtension
{
    public static bool IsPressed(this MouseState state, string buttonName)
    {
        return (ButtonState)(typeof(MouseState).GetProperty(buttonName).GetValue(state, null)) == ButtonState.Pressed;
    }   
}

The result would be that you could then call it by writing currentMouseState.IsPressed("LeftButton") or any other valid button name.

Not that I would really recommend going this route, but it's good to be aware of the alternatives. And of course it only works if you pass it a valid property name of type ButtonState, otherwise it will crash.

\$\endgroup\$
0
\$\begingroup\$

Is there any way to pass in the button I want to the function so I could have something like this?

Nope. Such functionality is built in for the keyboard but not the mouse.

Personally I hate how XNA handles mouse input. If you want an alternative take a look at this. It has a delegate that translates messages sent to the window your game is embedded in then fires events specific to the type of input.

Most useful of these for you are the below.

/// <summary>Event raised when a mouse button is pressed.</summary>
public static event MouseEventHandler MouseDown;

/// <summary>Event raised when a mouse button is released.</summary>    
public static event MouseEventHandler MouseUp;

Which allow for event driven input.

InputSystem.Initialize(Game.Window);

InputSystem.MouseUp += delegate(Object o, MouseEventArgs e) {

    switch (e.Button) {
        case MouseButton.Left:
        case MouseButton.Middle:
        case MouseButton.Right:
        case MouseButton.X1:
        case MouseButton.X2:
        break;
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ -1 Misleading information. You can do it just fine, you just need a mouse handler (as seen in bearcdp's answer). \$\endgroup\$ Feb 20, 2012 at 10:23
  • \$\begingroup\$ Didn't realize that a user created enum was a button, my bad :/ \$\endgroup\$ Feb 20, 2012 at 13:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .