Game Development Community

An Improved mouseDraggableBehavior

by Charlie Patterson · in Torque Game Builder · 05/10/2011 (2:03 pm) · 1 replies

My first little win! The following is an upgraded mouseDraggableBehavior.

Background


The draggable behavior already allowed for a two-click drag, where the first click selects the object, and the second click releases it. Between the clicks, the object is attached to the mouse.

The behavior also allowed for a "single-click drag", where if you move the mouse while the button is down, the behavior assumes you are using a single click drag. When the mouse is let up the first time, the object is released. There is no second click.

Problem


In a game, with twitching high, it was easy to move the mouse a bit on the first click, even though the player meant to use a two-click drag. The behavior would register this as a single-click drag.

Solution


Now, there is a little play at the beginning of a drag. If you only move the mouse a little bit, the behavior is lenient and still assumes you meant a two-click drag. However, if you *meant* to move the object just a little bit the behavior also notices that and does NOT start a two-click drag (by using the time passed).

Code


Go to mouseDraggableBehavior.cs and
Add these lines to the end of your onMouseDown:

function MouseDraggableBehavior::onMouseDown(%this, %modifier, %worldPos)
...
   // the user may mean to "toggle drag" but accidentally move the mouse a smidgen before letting
   // the mouse up.  In the case we want to provide a little leeway in dragging.
   %this.startDragCanvasPos = sceneWindow2D.getCanvasPoint(sceneWindow2D.getWindowPoint(%worldPos));
   %this.startDragTime = getSimTime();
}

And add replace your onMouseDragged with the following:
function MouseDraggableBehavior::onMouseDragged(%this, %modifier, %worldPos)
{
   if (%this.dragging)
   {
      %timePassed = getSimTime() - %this.startDragTime;
      %currentCanvasPos = sceneWindow2D.getCanvasPoint(sceneWindow2D.getWindowPoint(%worldPos));
      %distanceMoved = t2dVectorSub(%currentCanvasPos, %this.startDragCanvasPos);
      %maxAxisDistance = t2dGetMax(mAbs(getWord(%distanceMoved, 0)), mAbs(getWord(%distanceMoved, 1)));
      
      if (%maxAxisDistance > 200 || %timePassed > 100) {
         // Once we have really dragged a bit of a distance, then we know we aren't using drag toggle.
         // it was possible that we meant to click once to start a drag but moved the mouse a bit,
         // especially if we were in a game situation where we were trying to "two-click drag" quickly.
         // echo("distance" SPC %maxAxisDistance SPC %timePassed);
         %this.cancelOnMouseUp = true;
      }
      
      %this.moveToMouse(%worldPos);
      
   }
}

Notes

The play (or lenience) I chose, after an hour of experimentation, was 200 pixels of accidental drag or 100 ms of time! These seem large, but they appears to work best for me. They could be parametrized but it seems unnecessary at this point.

Any further improvements appreciated!

#1
05/11/2011 (7:00 am)
It will be beautiful if you manage to get it working on iTGB