Simplified XNA drag and drop
I got a question about how to implement multiple selection with drag and drop, and could see how that might be a challenge to implement to a beginning programmer. So I thought I'd make a codesample to learn from.
When I had finished coding, it struck me that I could refactor the code so the drag and drop part was tucked away in a helperclass. Then all that was needed to use it in any solution was to have the draggable objects implement an interface to let the helperclass
- know the boundaries of the object
- be able to change the position of the object
I expanded the helperclass to notify the object when the mouse was hovering over it, and whether the object was selected, so all that was left for the coder using the helperclass, would be to implement different ways of drawing the object according to what the state of IsMouseOver and IsSelected is.
So without further ado - let me present the DragAndDropController
What you get
It's as easy as this to use the controllerclass in your project:
//declare the controller somewhere on your Game class private DragAndDropController<Item> _dragDropController; //instantiate the controller somewhere _dragDropController = new DragAndDropController<Item>(this, _spriteBatch); //and add it to the Game class' Components Components.Add(_dragDropController); //add the items you want drag-and-drop enabled to the controller _dragDropController.Add(item);
The items that you add to the controller must implement the IDragAndDropItem interface:
Or in code, if you prefer that:
/// <summary> /// Interface describing necessary implementation /// for working with the DragAndDropController. /// </summary> public interface IDragAndDropItem { Vector2 Position { get; set; } bool IsSelected { set; } bool IsMouseOver { set; } bool Contains(Vector2 pointToCheck); Rectangle Border { get; } }
And that's it!
What an interface does
An interface in code is a contract that allows one piece of code (the DragAndDropController in this case) to treat objects of different types in the same way. This means that no matter whether the class implementing the interface is a "PlayerCharacter", a "MoneyToken" or a "PlayingCard", as long as they implement the abovementioned methods, the controllerclass can interact with them .
Video demonstration
The DragAndDropController<T>
Here you can see the public properties and methods of the DragAndDropController
Since it is a generic class you instantiate it to handle the type of your objects, and from then on you can add or remove items of that type to and from the controller.
You can also get the item under the mouse at any time (if any).
Source code
Here is the complete source code
January 30th, 2014 at 10:53
Hai sir, thank you for your drag and drop, it is very useful for me, because i wanted to make the inventory system.
But, i have a couple of questions to you.
How do you make the items will be visible only if the I in the keyboard is pressed? and how do you make when the item 1 in the inventory is dragged to the item 2, the item 2 will be moving to the item slot 1 instead of they are overlapping each other.
I am looking forward for it.. Thank you very much 😀 😀
January 31st, 2014 at 11:05
Hi Frendy
*** I KEY ***
I am guessing you want to show an inventory when the "I" key has been pressed? And then remove it again when the "I" key is pressed again?
For this you will need a boolean variable (e.g. "inventoryVisible"), which you toggle when the "I" key is pressed.
The easiest way to do this is:
inventoryVisible = !inventoryVisible;
which takes the opposite value of what is in the boolean variable and stores it again.
You will need to store both the current KeyboardState and the previous KeyboardState to make sure you don't just toggle (switch values) for every Update(), but only when "I" key was up in the previous Update() and down in this one.
*** Swap items ***
For this to work, you will have to
- store the original position of the item you grab with the mouse
- check when you drop an item, whether it is on top of another one
One way to check for overlap when dropping is to create two bounding rectangles, one for each item, and use the Rectangle.Intersects method (http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.rectangle.intersects.aspx) to check whether one item overlaps the other.
This way you can just set position of the item that is being dropped on to the original position of the dragged item.
If you want all items to stay in a grid, have a look at the Drag and Drop with snap to tiles tutorial:
http://xnafan.net/2012/07/simple-drag-and-drop-with-snap-to-tiles-in-xna/
Kind regards - Jakob
February 2nd, 2014 at 08:25
Hi again Frendy
I've made a small codesample for you to show you how to swap the positions of two items in a grid:
http://www.xnafan.net/downloads/_tutorials/dragandswap/dragandswaptotilessolution.zip
Kind regards - Jakob
November 4th, 2014 at 13:53
Jakob. Thank you very much for that tile swap demo. Helped me a lot!
November 21st, 2014 at 09:26
Super, glad to hear it!
If you feel like it, send a link to whatever you're working on, if you finish it.
It would be fun to see :).
Kind regards - Jakob
P.S. Sorry for the late answer, for some reason WordPress stopped notifying me of comments ... :-/