Mark Gilbert's Blog

Science and technology, served light and fluffy.

Drag-and-drop, Event-ually

I mentioned in my previous Unity post that the logic powering the dragging and dropping on the equation screen was not straightforward to develop.  I had multiple false starts looking for a pattern that could support everything I needed it to:

* Dragging operations out of the OperationsTray and dropping them onto a domino to place it
* Dragging operations out of the OperationsTray or a domino, and dropping it onto the screen to delete it
* Dragging operations out of a domino to place it into another domino
* Dragging dominos to merge them with another
* Etc.

What I finally landed on was evaluating the Input.GetMouseButtonDown, Input.GetMouseButton, and Input.GetMouseButtonUp methods in the EquationScreenController.Update event handler.  (“Mouse button” here covers both clicking a mouse button as well as touching the screen with your finger.)  These methods return true when the user first clicks the mouse button to grab something, holds the mouse button down to move it, and then releases the button to drop it, respectively.

Once the user grabbed something, I needed logic to determine what they grabbed and were now dragging.  As they were dragging it, I had to refresh the UI so that the thing being dragged would actually track with their finger.  Once they dropped it, I had to evaluate if they dropped it on a valid spot or not, and do something in both cases.

My first working iteration of this required pages and pages of conditional logic – very ugly and hard to debug.  I needed a better way.  Luckily, history repeats itself – or is it “recurses”?

Years ago, when my colleagues and I were playing with the Microsoft Kinect, we started a project where the user would dress a paper doll on screen.  The user would “pick up” some article of clothing, move it over the doll, and then “drop it”.  “Pick up” in this game translated into “hold your hand over the article of clothing on the screen for a second or two until you convinced the software that you wanted THAT one”.  At that point, it would pop it off of the “wardrobe” and being to track with your hand.  “Drop it” translated into the user pushing their hand toward the Kinect, as if he or she were pushing a piece of paper onto a corkboard.

What that app taught me was the value in custom events.  The Kinect reports the three-dimensional position of 20 different joints for the user, 30 times a second.  I ended up writing a “manager” class that would translate the raw data coming off the Kinect into a series of events being raised – specifically things like hover, pick up a piece of clothing, drop a piece of clothing, etc.  That translation layer greatly simplified writing, and especially debugging, the rest of the app.

I decided to go the same route here.  Here is a slightly simplified version of the new EquationScreenController.Update() logic:

public void Update()
{

if (Input.GetMouseButtonDown(0))
{

this._DragDropManager.EvaluateInputDown(Input.mousePosition);

}
else if (Input.GetMouseButton(0))
{

this._DragDropManager.EvaluateInputMove(Input.mousePosition);

}
else if (Input.GetMouseButtonUp(0))
{

this._DragDropManager.EvaluateInputUp(Input.mousePosition);

}

}

The DragDropManager.Evaluate… methods would translate the raw UI input into a series of events to be raised:

  • OperationPickedUp
  • DominoPickedUp
  • OperationMoved
  • DominoMoved
  • DroppedOnNothing
  • DroppedOnDomino

My EquationScreenController, then, would handle those events and do all of the necessary UI steps.

This structure allowed me to not only abstract the messy details of the translation away, but it broke up the monolithic Update() method I had going into smaller, and much easier to debug, methods.

As a bonus, the refactored structure made it possible to unit-test the three DragDropManager methods.  I could set up various scenarios, and verify that the proper events were being raised given that input.

Advertisements

October 2, 2017 - Posted by | Game - Algebra, Unity

Sorry, the comment form is closed at this time.

%d bloggers like this: