How do I spawn an actor and snap its location to a grid in the middle of Drag & Drop Operation (Widget)?

I’m doing a 3D board game with grids with widgets at its side as drag&droppable items on to the board game.

I want to create a silhoutte 3D actor that snaps on the board grid while dragging it from widget menu before dropping it.

Is there a way to spawn the silhouette 3D Actor and SetActorLocation (snapping to grid) in the middle of dragging operation?

Yes,

If you don´t know how to start a D&D, here is a short example of my Inventory System:


This Drag Detected should be located in your OnMouseButtonDown Function Override of your UI Slots / Card / Icon…etc.
Edit:
You see, i don´t use hardcoded Key bindings here… I just ask for Keys of the Player Input Settings (ProjectPreferences Input). “Select” is my LeftMouse per Default… but can be Changed via User Settings at any Time.


Here, in the OnDragDetected Function override, you create a Widget as Placeholder, that is automatically attached to your Cursor.
Important:
As DragOperation Class, you need to create yourself a custom one, that holds the Class of the Actor you want to spawn, as exposed Variables.
Like my Quantity, Index, SourceType and Name. See:

You now want to call yozur PlayerController and switch on a Bool, called “SpawnDragEnable” and set a Class Reference called “SpawnActorClass”.
Best in a Function of the PlayerController

Back to your OnDragDetected of your Widget, right after you set the Drag Operation, just call that Function in your Player Controller.
The class should be the Actor class, you want to Spawn later.

Since you want a Tick in your PlayerController, you simply add a Bool to check the true state of SpawnDragEnable, and spawn the Actor you want. In my following Screenshot, i spawn this actor one time only and just replace it on a grid. I set an Actor reference as Variable for that:

Nvm the Tick Graph… i use to put the Tick Events in a standalone Graph of the BPs.

So… you now want to get the Mouse Position in your Viewport. Here is my little function for that:


This allows you to get the Mouse Position in Viewport, scaled by the Viewport Scale if wanted. Since you by default want it scaled, just set the Default Value of the Input “scaled” as true.
Set this function as “Pure”, since it needs no Execution Input.

Drag thet function into your Tick.
You now want to define the Gridposition, based on the Cursor Position.
Since the Mouse is workin inside the Viewport and not the World, convert the Viewport Location to World Location. first.
Use the “DeprojectScreenToWorld” for that.

You now got the World Location under your Cursor. whats next?
Tiling!
Here is a simple pseudo Math for that… you, so i think, can convert it to BP Nodes:

// Get the Tile Position floored
xPos = floor(Mouse.x / TileSize.x);
yPos = floor(Mouse.y / TileSize.y);

// Multiply this by TileSize again, to get World Location
xPos = xPos * TileSize.x;
yPos = yPos * TileSize.y;

// Now add an offset to place the Actor in the Center of the Tile.
Offset = Vector2(TileSize.x/2, TileSize.y/2);
xPos = xPos += Offset.x;
yPos = yPos += Offset.y;

After that, xPos and yPos are your Actor Location in the World. Before that, store the Location in a Variable (StoredLocation here)
F.e.:

Last Step… you want to place the actor fixed in the world.
In your Widget, add an override of the OnDrop Event.

Call your PlayerController again.

In your Player Controller, add a function to actually place this Actor on the Grid… call it from your Widget:


That is all… just a small example… perhaps needs some tweaking…

Edit:
If OnDrop is not working… perhaps cause you not drop on a Widget… Try OnDragCancelled

1 Like

I’m actually stuck at creating a custom DragOperation Class. How do you do that?

Rightclick in your content browser and add a new Bluprint class.

In the Selection Window, where you can select Actor, PlayerController, Pawn, Character…etc… Select nothing, but expand the list at the bottom of the window.
In the search field of this List, type “DragDropOperation” and select the class in the list, that matches this Name.
Create it and you will have your very own DDOperation to deal with.

Its really the same as a default Blueprint Actor Graph.

Thanks! I got the custom DragDropOperation created.

Sorry for the late response, I’m quite new to UE & Blueprints, still digesting to understand your solution.

I tried calling my PlayerControl BP from Widget BP but it comesback with an error saying “Accessed none at Playercontrol BP”. Screenshot of my blueprint below

And also another problem was the GetMousePosition doesnt seem to work.

I tried to DeprojectScreentoWorld immediately at the GetMousePos function, but the return value is all just zero.

Is there anything I did wrong? Appreciate your help

I am still struggling to get communication established from Widget BP to my Player Control BP. I tried creating an Interface and switch on the boolean by calling interface function from Widget BP and receiving as an event inside Player Control BP. But the problem was that the interface itself is not working and I don’t understand why. My screenshots below


From the WidgetBP, it does not recognise my PlayerControlBP as valid, there even sending the boolean variable through interface is not working


This is the receiving event inside Player Control BP

Sorry, I’m a real noob. Really appreciate your help on this