Game Development Community

Is anyone able to track mouse movement?

by John Kanalakis · in Torque X 2D · 12/26/2007 (11:59 pm) · 9 replies

Has anyone implemented any mouse tracking code? I am able to process the mouse clicks, but can't seem to track the specific mouse movement. I thought that binding to the MoveMapTypes.StickAnalogHorizontal would do it, but it doesn't seem to work for me (unless I'm missing something). Here's some of my sample code.

protected override void _SetupInputMap()
{
    InputMap.BindMove( 0, (int)XMouseDevice.MouseObjects.X, MoveMapTypes.StickAnalogHorizontal, 1);
}


public void ProcessTick(Move move, float elapsed)
{
    if (_enabled)
    {
        MouseState state = Mouse.GetState();
 
        if (state.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
        {
                float rotX = move.Sticks[1].X * move.Sticks[1].X;
                if (move.Sticks[1].X < 0.0f)
                    rotX = -rotX;
 
                float rotY = move.Sticks[1].Y * move.Sticks[1].Y;
                if (move.Sticks[1].Y < 0.0f)
                    rotY = -rotY;
         }
    }
}

With this code implementation, state.LeftButton is properly set to "Pressed" as a recognized mouse click, but the move.Sticks[1].X is always 0. True I've mapped this to "Sticks" which is normally for the gamepad, but there doesn't seem to be a Move structure specific to the mouse. Any ideas would be greatly appreciated.

John K.

About the author

John Kanalakis is the owner of EnvyGames, an independent game development studio in Silicon Valley that produces games and tools for Xbox 360, Windows, and the Web.


#1
12/27/2007 (6:26 am)
Okay, so, some deeper digging is bringing me a lot closer. I'll keep rambling on this thread in case someone in the future is trying to accomplish the same thing. Essentially, I'm trying to implement code that moves the camera around the scene when the mouse is dragged (mouse move + button down). Here's what I have now:

Binding
protected virtual void _SetupInputMap()
        {
            if (PlayerManager.Instance.GetPlayer(_playerIndex).ControlObject == null)
            {
                PlayerManager.Instance.GetPlayer(_playerIndex).ControlObject = Owner;
                _inputMap = PlayerManager.Instance.GetPlayer(_playerIndex).InputMap;
            }
            else
            {
                _inputMap = new InputMap();
            }

            int mouseId = InputManager.Instance.FindDevice("mouse");
            if (mouseId >= 0)
            {
                _inputMap.BindMove(mouseId, (int)XMouseDevice.MouseObjects.LeftButton, MoveMapTypes.Button, 0);
                _inputMap.BindMove(mouseId, (int)XMouseDevice.MouseObjects.RightButton, MoveMapTypes.Button, 0);
                _inputMap.BindMove(mouseId, (int)XMouseDevice.MouseObjects.X, MoveMapTypes.StickAnalogHorizontal, 0);
                _inputMap.BindMove(mouseId, (int)XMouseDevice.MouseObjects.Y, MoveMapTypes.StickAnalogVertical, 0);
            }
        }

ProcessTick() method
public void ProcessTick(Move move, float elapsed)
        {
            if (move == null)
                return;
            Vector3 vel = Vector3.Zero;

            if (move.Buttons[0].Pushed)
            {
                if (move.Sticks.Count > 0)
                {
                    Vector3 right = MatrixUtil.MatrixGetRow(0, ref _transform);
                    Vector3 forward = MatrixUtil.MatrixGetRow(1, ref _transform);
                    vel += ((forward * move.Sticks[0].Y) + (right * move.Sticks[0].X)) * _cameraMoveSpeed;
                }
            }
            SceneGroup.Position += vel;
        }

This should move the camera around the scene while the button is pressed. But, it kinda seems like I get either valid mouse X-Y movement tracking or notification that the button is pressed. I never seem to get a Move structure with X-Y movement information AND button pressed information.

So, does the button press clear out the move structure? As always, thoughts are welcome.

John K.
#2
12/27/2007 (6:50 am)
In my guibutton enhanced button, I supported the mouse activity by pretty much foregoing the move structure, and forwarding the action via a delegate. I wonder if you could do something similar, and call a delegate passing in your MouseState when the mouse is within a certain position or state. I did this specific to my button:

public void ProcessTick(Move move, float elapsed)
        {
            if (this.Awake)
            {
                MouseState state = Mouse.GetState();
                if (state.X > this.Position.X
                    && state.X < this.Position.X + this.Size.Width
                    && state.Y > this.Position.Y
                    && state.Y < this.Position.Y + this.Size.Height)
                {
                    // If it does not have the focus, set it to be focused
                    if (!GUICanvas.Instance.ControlHasFocus(this))
                    {
                        GUICanvas.Instance.SetFocusControl(this);
                    }
                    if (_processMouseEvents)
                    {
                        if (state.LeftButton == Microsoft.Xna.Framework.Input.ButtonState.Pressed)
                        {
                            // This means they are within the bounds of the button, and the button is pressed
                            if (_onMouseClick != null)
                            {
                                ProcessList.Instance.SetEnabled(this, false); // disable it as we will be switching canvases
                                GameData.Instance.SoundBank.PlayCue("mouseDown"); // Play the mousedown sound
                                _onMouseClick(state); // Call the delegate set by the caller
                            }
                        }
                        else
                        {
                            if (_onMouseHover != null)
                            {
                                _onMouseHover(state);
                            }
                        }
                    }
                }
            }
        }

Just an idea :D
#3
12/27/2007 (7:03 am)
David, thank you for the helpful thoughts. I might need to take a new direction as you've outlined above. The problem I seem to have is that I can track a mouse press and I can track mouse movement - but - I can not track mouse movement with a mouse pressed (for a dragging effect).

It seems like each event (mouse press and mouse click) generate a new Move structure, so as I process the mouse movement, a mouse press clears the movement data. I'll try a new approach based on your example. Maybe to set a "lock" variable when the mouse is down, then process the movement while the "lock" variable is set, and reset the "lock" variable when the mouse is up.

John K.
#4
12/27/2007 (7:31 am)
Ahh, ok. Hmm, I wonder if you had a mousetracking class and when several processticks have passed, and the mousebutton is still pressed but the x and y have changed within a set range, it could raise a mousedrag event on the mousetracking class. When I was going through the torquex code for the mouse a while back, it looked like it is meant for basic movement and actions. At some point, I plan on implementing my own mousesupport class to handle events like drag n drop,etc. Let me know what you come up with, I would be curious to see the various ideas on this.
#5
12/27/2007 (7:39 am)
Mission Accomplished ;)

It turns out that there's an overloaded method for the BindMove() method that accepts input modifiers (such as mouse down). So, the binding code above DOES NOT accept movements with mouse pressed intentionally. To ACCEPT mouse movements with mouse pressed, set the binding as follows:

_inputMap.BindMove(mouseId, (int)XMouseDevice.MouseObjects.X, TorqueInputDevice.Action.LeftClick, MoveMapTypes.StickAnalogHorizontal, 0);
_inputMap.BindMove(mouseId, (int)XMouseDevice.MouseObjects.Y, TorqueInputDevice.Action.LeftClick, MoveMapTypes.StickAnalogVertical, 0);

Note the new TorqueInputDevice.Action.LeftClick third parameter.

Then, you can check for the mouse button press along with your mouse movements in the ProcessTick() method with the following

public void ProcessTick(Move move, float elapsed)
{
     MouseState state = Mouse.GetState();
 
     if (move.Sticks[0].Y > 0.0 || move.Sticks[0].X > 0.0f)
     {
          if (state.LeftButton == ButtonState.Pressed)
          {
               //you are currently dragging the mouse ;)
          }
     }
}

That seems to do it. Thank you David for helping me through this.

John K.
#6
12/27/2007 (8:17 am)
Ahh, is that 1.5 and 1.1, or just 1.5? Another thread for me to bookmark , good work! :)
#7
12/27/2007 (8:21 am)
I'm running version 1.5. I don't think it was around for version 1.1, but it's really useful - a great way to filter input (when you know that it actually exists ;) ). Also, in case my last post was misleading, you don't *need* to check if the button is pressed as you will only get a Move structure if the button is already pressed.

John K.
#8
01/16/2008 (9:28 pm)
FYI, if anyone cares how to do this in straight XNA, or if you want a component that allows windows like events, I wrote a component that will do this:

http://underdog32.spaces.live.com/default.aspx
#9
05/01/2008 (2:04 pm)
After implementing Johns code above, it seems as though I am unable to click-drag select objects when starting from top-left going to bottom-right. Is anyone else seeing this? All other directions of selection seem to be working fine.