Architecture - Blueprint Inventory Part 2: Inventory Functionality, Drag and Drop

One of the implementations I really wanted to add to the inventory system was being able to move the widget around. Drag and Drop operations, as it turns out, aren't as simple as just drag and drop. A whole new BP must be created that will be used by whatever it is you want to drag, and several functions must be overwritten to do so.

As mentioned in the previous blog post, I have started this project again, as the backup I had wasn;t totally up to date and it could stand to be a lot more cleaner. If you have been following along, there is a chance some of the variables or blueprints may not be the same.

As always, if you read this blog post and would like more information, please view the original tutorial by youtube user "Unreal Gaime Dev"


The first step



The first thing to be done is to create a new BP with a parent class of "DragDropOperation." There is nothing required in the construction script or the event graph, it simply requires to variables. The Widget to drag, variable of type UserWidget, and a variable called mouse offset as a Vector2D. 

Dragging and dropping items will come later, the first thing to drag and drop will be the inventory widget itself. Hence, this drag and drop blueprint contains a variable for user widgets that must be defined.

Widget drag

Head over to the inventory widget, and override a function called on mouse button down.

The following function is very simple, it only needs to recognise when the player has pressed down the mouse button, and we tell it to return a Vector2D if it picks up a drag when a certain button is held down. In this case, the left mouse button. 


If it does pick up a drag, we need to override another function, this time the "On Drag Detected" function. We will use this to create a drag and drop operation, of our new operation that I called "Widget Drag." 



A known bug with Unreal 4.13 is that the moues offset input doesn't work as intended, and upon searching for a work around, taking the screen position of our pointer and converting it to an absolute coordinate works, as pictured above. The pivot should also be set to mouse down, to avoid the drag animations not showing at the correct area on screen.

When testing this blueprint as it is above, holding down the mouse button and dragging will duplicate the inventory widget as it is, and follow the mouse cursor, however a duplicate will be left at its original position that we gave it when we first draw the widget, and also dropping the widget will delete it instead of giving it a new position.


Fixing the simpler task first, simply removing the inventory widget from the parent before returning will delete the old left-behind widget that wasn't a part of the drag function.

Widget drop

In order to properly drop the widget on screen and this be its new position, we have to override one last function, called "OnDrop." Make sure that this is casted to the dragdrop blueprint we created, as if something else is dropped that doesn't apply to our widget drag, we don't want to do anything.


As the comments say, by using a similar method to what we used with the drag function, the drop function requires us to first get the screen position of the pointer, and then convert it to an absolute coordinate. However, this time, we take the mouse offset from our dragdrop blueprint and subtract it from the return value of the coordinates. This will give us a new Vector2D that accurately drops the widget on top of our cursor. To fix the drop deleting the widget, simply take the target widget to drag from our dragdrop blueprint, and add it back to the viewport at the calculated position. 


Extended inventory functionality

For this blog post, we will be adding four new functions to our inventory: Remove items, Swap item positions, split an item stack into two smaller stacks, and use items. This won't be fully implemented yet, as the first step is to get it all working. Hence, the split stack will split 25 items, and the discard will discard 50. In the game, when this is properly implemented, we want the player to determine how many to split or discard

Remove item at index

This function will require two inputs, both integers, and a boolean output. For work flows sake, promote these two inputs to local variables. 

The first thing to check in this function is that the slot isn't empty, and that the amount we want to remove is greater than 0. In both of these instances, if the slot is empty or the player wants to remove 0, simply do nothing.


If the slot contains something and we want to remove more than 0, the next thing to check is whether or not the amount to remove is greater than the amount of items at the specified index. As an example, if we want to remove 80 health potions from a 50 potion stack, simply clear out the index, as it will achieve the same thing. 
The note is simply the compiler telling me to end the update slot at index with a return node. Return with Success bool =1
If the amount to remove is smaller than the amount at the index, then we want to subtract the amount at the index by our local "amount to remove" and plug these into the array element. Setting it to 20 is the same as doing 50 - 30.


Swap slots at index

As with the previous function, it makes the blueprints easier and cleaner to follow if we start by promoting the two input integers (Index 1, Index 2) to local variables.


After that, we need to make sure that we aren't trying to swap indexes that are outside of our arrays current range. The range was set up in the Inventory BP to have a certain amount of indexes. If any of the input indexes are greater than the last index, do nothing and return with a Success bool =0


If this returns false, as it should do, we want to store a local variable of one of these indexes. The comments explain why, although you could set the index 1 as a local variable if you wanted. We just have to make sure the index we change last is stored as a local variable so that the s_ItemInfo isn't lost.

Split Stack

As with the previous functions, begin with two inputs, integers, one for the stack index, and the other for the amount to split. Promote these to local variables.

Before we split anything, we want to make sure that not only is the item we are trying to split a stackable item (Example, Health Potions are stackable. Swords are not.) but that we are not trying to split 99 potions from a stack of 99, as this accomplishes absolutely nothing. If either of these return false, return with the success bool=0. 


If the item can be stacked, and we are looking to split less than the total amount at the index, then we call the "Search Empty Slot" that was created in the last blog post. This will return a bool, and an integer of the found index.

This int should also be promoted to a local variable for easier storage.


Take the local stack index, and subtract the amount in the index by the amount to split. Then, set the amount we split into a new array element, at the returned index of the function. Then update the slots and return.

Use Item

This is a custom event within the inventory blueprint. Get the index of the item to use, and check that the class is valid. If it is valid, spawn an actor in the world of this item type, and open up the "on use" event in the master item blueprint.


The proper implementation of this will not be set up yet, as a lot of the functionality will be tied to the item, as an example a health potion shouldn't do the same as an item that increases experience gains for a short amount of time. So, until the blog post where we add an example of an item use, we simply print a text (for debuggings sake) saying "You used X" and remove one of the item at the used item index. Two new variables are also added here, both editable and exposed on spawn.

Reconnect the new variables back to the "SpawnActor" in the inventory event graph.


Fire off new functions

Then, to finish up, because the implementation isn't successfully working yet, go to the top down character and add inputs to fire off these functions to check they all work. 


End

The proper implementation will be in an upcoming blog post, stay tuned!

Time Scale

So as previously mentioned I started fresh with this projects inventory system to try and tidy it up, and am meeting a fair few bugs, both new and old. The aim is to have the merchants and currency working again by roughly the 24th of March, although I can forsee this taking less time this redo, as I feel more confident in getting the basics set up rather than reading a guide every single step of the way.

Because I let AV slip, I want to have a soundtrack done by the 27th. There is a lot I wish I could do with the soundtrack but composition has proven to be a very tough challenge, so I will be happy with any starting point.

Comments

Popular posts from this blog

Architecture - Blueprint Inventory Part One [Long Post!]