item can not drag and move

manscom

Member
I am using the item shape grid but after I drag and move the items on the grid few times during run time, my scene editor shows up a few Red Cross and I could not drag and move the item which is on the Red Cross but the item which is not on the Red Cross can be drag as normal.

Please see the below image for your reference.
Thank you!
螢幕截圖 2021-05-17 下午10.08.24.png
 
Interesting... I haven't seen that before.

Usually a cross in the UI means a rect transform/image that has a negative height or width. Since it seems to prevent your items from being dragged and dropped, then probably that rect transform is on top of your items.

Could you select those red cross in the hierarchy and take a screen shot or a video such that we can identify what they are and what components they are using.
 
Last edited:
Interesting... I haven't seen that before.

Usually a cross in the UI means a rect transform/image that has a negative height or width. Since it seems to prevent your items from being dragged and dropped, then probably that rect transform is on top of your items.

Could you select those red cross in the hierarchy and take a screen shot or a video such that we can identify what they are and what components they are using.
Hi there

just like you said, I clicked on the cross and the rect transform has a negative height or width. I also found out the problem occurs was after I used a new item slot prefab on the category item view set to display my weapon icon. As I changed it back to the default setting which only use the default item slot prefab for all the items, then there has no Red Cross on the screen and everything works prefect. But I do need to display different infos for my item, so please assist me wit this problem.

Please read the following images for your reference.
Thank you
螢幕截圖 2021-05-18 下午8.02.46.png螢幕截圖 2021-05-18 下午8.05.15.png
 
Thank you for the screenshots, I was able to find the bug and fix it, by replicating your setup.

There are two issues, both cause by the object pooling
1) Pooling moves the UI to another gameobject when it is returned to the pool. That object is not a canvas and that seems to be causing the negative width/height

To fix that add this on line 325 of the Item Shape Grid script:
Code:
view.RectTransform.sizeDelta = m_ItemShapeSize;
right below the if condition and the line where I assigne the anchoredPosition

2) For some reason the Item View in the foreground stops ignoring raycasts which block the background from receiving the UI events. I use the background item view to receive raycasts because they are of fixed size.

To fix that replace this function in the Item Shape Item View script around line 230:
Code:
/// <summary>
/// Change the layer state between foreground and background.
/// </summary>
/// <param name="foreground">Is it foreground or background?</param>
protected virtual void ChangeLayerState(bool foreground)
{
    m_Foreground = foreground;
    if (m_Foreground) {
        m_ForegroundItemView = null;
    }
    m_View.CanvasGroup.interactable = !foreground;
    m_View.CanvasGroup.blocksRaycasts = !foreground;
    for (int i = 0; i < m_ForegroundActive.Length; i++) {
        m_ForegroundActive[i].SetActive(m_Foreground);
    }
    for (int i = 0; i < m_BackgroundActive.Length; i++) {
        m_BackgroundActive[i].SetActive(m_Foreground == false);
    }
}
 
Thank you for the screenshots, I was able to find the bug and fix it, by replicating your setup.

There are two issues, both cause by the object pooling
1) Pooling moves the UI to another gameobject when it is returned to the pool. That object is not a canvas and that seems to be causing the negative width/height

To fix that add this on line 325 of the Item Shape Grid script:
Code:
view.RectTransform.sizeDelta = m_ItemShapeSize;
right below the if condition and the line where I assigne the anchoredPosition

2) For some reason the Item View in the foreground stops ignoring raycasts which block the background from receiving the UI events. I use the background item view to receive raycasts because they are of fixed size.

To fix that replace this function in the Item Shape Item View script around line 230:
Code:
/// <summary>
/// Change the layer state between foreground and background.
/// </summary>
/// <param name="foreground">Is it foreground or background?</param>
protected virtual void ChangeLayerState(bool foreground)
{
    m_Foreground = foreground;
    if (m_Foreground) {
        m_ForegroundItemView = null;
    }
    m_View.CanvasGroup.interactable = !foreground;
    m_View.CanvasGroup.blocksRaycasts = !foreground;
    for (int i = 0; i < m_ForegroundActive.Length; i++) {
        m_ForegroundActive[i].SetActive(m_Foreground);
    }
    for (int i = 0; i < m_BackgroundActive.Length; i++) {
        m_BackgroundActive[i].SetActive(m_Foreground == false);
    }
}
Thank you so much for your assistance, the code works!

But I do still need some more help on other problems, please allow me to list the problems I am facing
1.The grid auto select other grid after I used the equip item action on the item.
2.The grid auto replace the item position after I used the equip item action on the item, but I want the items stay on the same position.
3.The item icon does not show up when I dragging the item.
4.I have setup the smart exchange for the drop handler but items can not exchange.

I have recored a short video for reference but can not upload here due to here said my file is too large but it is only 2mb. May I know how to upload it such I can show you what my problems really look like.
Thank you!
 
You can share videos using streamable.com

I'm not sure I understand 1 & 2.

3 probably has to do with the "Item View Slot Cursor Manager" component on the Inventory Canvas, check the video tutorial and the documentation about drag and drop.

4 The drop handler action must be defined on the container you are dropping the item into. If you have things setup properly and the item still cannot exchange, it might be because it does not fit.
 
You can share videos using streamable.com

I'm not sure I understand 1 & 2.

3 probably has to do with the "Item View Slot Cursor Manager" component on the Inventory Canvas, check the video tutorial and the documentation about drag and drop.

4 The drop handler action must be defined on the container you are dropping the item into. If you have things setup properly and the item still cannot exchange, it might be because it does not fit.
Please click the below link to see the videos


Thank you!
 
Thanks to your video I was able to replicate all issues, and I fixed them.
In the ItemShapeGridData script add this:
Code:
protected Dictionary<ItemStack, (Vector2Int position, ItemInfo itemInfo)> m_RemovedDirtyIndexedItems;

Then replace/add all these functions:
Code:
/// <summary>
/// Initialize
/// </summary>
/// <param name="controller">The item shape inventory grid controller.</param>
public void Initialize(ItemShapeGridController controller)
{
    if (m_Controller == controller) {
        return;
    }
    m_Controller = controller;
    m_ItemStackAnchorGrid = new GridElementData[GridColumns, GridRows];
    m_TemporaryItemStackAnchorGrid = new GridElementData[GridColumns, GridRows];
    m_RemovedDirtyIndexedItems = new Dictionary<ItemStack, (Vector2Int position, ItemInfo itemInfo)>();
}
 
/// <summary>
/// Try to find a position available for the item info.
/// </summary>
/// <param name="itemInfo">The item info.</param>
/// <param name="position">The position which fits the item.</param>
/// <returns>True if a position was found.</returns>
public bool TryFindAvailablePosition(ItemInfo itemInfo, out Vector2Int position)
{
    position = Vector2Int.zero;
    if (itemInfo.Item == null) { return false; }
   
    //Check if the item was previously added to an index
    foreach (var removedDirtyIndexedItem in m_RemovedDirtyIndexedItems) {
        var previousItemStack = removedDirtyIndexedItem.Key;
        var previousPosition = removedDirtyIndexedItem.Value.position;
        var previousItemInfo = removedDirtyIndexedItem.Value.itemInfo;
       
        if(previousItemInfo.Item != itemInfo.Item){ continue; }
       
        if (IsPositionAvailable(itemInfo, previousPosition)) {
            position = previousPosition;
            return true;
        }
    }
    for (int y = 0; y < GridRows; y++) {
        for (int x = 0; x < GridColumns; x++) {
            position = new Vector2Int(x, y);
            if (IsPositionAvailable(itemInfo, position)) {
                return true;
            }
        }
    }
    position = new Vector2Int(-1, -1);
    return false;
}
 
/// <summary>
/// An item was removed, therefore remove it from the grid.
/// </summary>
/// <param name="itemInfoRemoved">The item info was removed.</param>
public void OnItemRemoved(ItemInfo itemInfoRemoved)
{
    //Clean up the grid from null items when an item is removed.
    //This works because the item stack is reset if an item is removed from the inventory.
    for (int row = 0; row < m_GridSize.y; row++) {
        for (int col = 0; col < m_GridSize.x; col++) {
            var gridElement = m_ItemStackAnchorGrid[col, row];
            var itemStack = gridElement.ItemStack;
            if (itemStack == null) {
                m_ItemStackAnchorGrid[col, row] = GridElementData.None;
                continue;
            }
            if (itemStack.Item != null) { continue; }
            if (gridElement.IsAnchor) {
                var position = new Vector2Int(col, row);
                Debug.Log("REmoving "+position+" "+gridElement.ItemInfo);
                m_RemovedDirtyIndexedItems[itemStack] = (position, gridElement.ItemInfo);
            }
               
            m_ItemStackAnchorGrid[col, row] = GridElementData.None;
        }
    }
}
 
/// <summary>
/// Cleanup some data such that the cached indezes can be removed.
/// We do not cleanup automatically in case an item moves multiple time within one frame.
/// Example when the item move collection it is removed and then added, which used to forget the index.
/// </summary>
public void Cleanup()
{
    m_RemovedDirtyIndexedItems.Clear();
}

I added a way for the grid to remember where the item was even if its ItemStack changes (this happens when the item moves between Item Collections)

You'll also need to add this function to the ItemShapeGridController script:
Code:
/// <summary>
/// Cleanup the Inventory Grid Indexer every frame.
/// </summary>
protected virtual void LateUpdate()
{
    for (int i = 0; i < m_ItemShapeGridData.Count; i++) {
        m_ItemShapeGridData[i].Cleanup();
    }
}
 
To fix the problem with the Item disappearing on drag & drop, that's because the Item View used is one of the ItemShapeView pooled instances. And due to the foreground/background nature of the item shape view it wasn't being properly set each time.
I would highly recommend you set an Category Item View Set for when drag and dropping, That component is usually on your Inventory Canvas
XAM-F66FFKcp6LmQ4XeBIcptKuraapQ__rOUuiklHY2dIkfaOlmHgJwuBoLBkxalecLzQeVLPJ25TH38jMBiZxxRvMR5Z1ps3fLSMflOFFuf3UBzeLRZ2Hc7WvBmVlBhbYZ0HANy

If you do so another prefab can be used on for the drag/drop movement and it can be separate from the Container one. Check out the video tutorial about the drag/drop and the Item Shape Grid if you haven't done so yet.


Some people might still want to use the Item Shape Item View from the Item Shape Grid, so I made a change to the Item Shape Item View script.
Make the Item Shape Item View script inherit the IViewModuleMovable interface
Code:
public class ItemShapeItemView : ItemViewModule, IViewModuleMovable
and then add this two functions to it:
Code:
 public void SetAsMoving()
 {
     ChangeLayerState(true);
 }
 
public void SetAsMovingSource(bool movingSource)
{
    //nothing
}

I hope that solves all your issues, I'll make sure to include all those changes in the next major update of the inventory system
 
Thanks to your video I was able to replicate all issues, and I fixed them.
In the ItemShapeGridData script add this:
Code:
protected Dictionary<ItemStack, (Vector2Int position, ItemInfo itemInfo)> m_RemovedDirtyIndexedItems;

Then replace/add all these functions:
Code:
/// <summary>
/// Initialize
/// </summary>
/// <param name="controller">The item shape inventory grid controller.</param>
public void Initialize(ItemShapeGridController controller)
{
    if (m_Controller == controller) {
        return;
    }
    m_Controller = controller;
    m_ItemStackAnchorGrid = new GridElementData[GridColumns, GridRows];
    m_TemporaryItemStackAnchorGrid = new GridElementData[GridColumns, GridRows];
    m_RemovedDirtyIndexedItems = new Dictionary<ItemStack, (Vector2Int position, ItemInfo itemInfo)>();
}
 
/// <summary>
/// Try to find a position available for the item info.
/// </summary>
/// <param name="itemInfo">The item info.</param>
/// <param name="position">The position which fits the item.</param>
/// <returns>True if a position was found.</returns>
public bool TryFindAvailablePosition(ItemInfo itemInfo, out Vector2Int position)
{
    position = Vector2Int.zero;
    if (itemInfo.Item == null) { return false; }
  
    //Check if the item was previously added to an index
    foreach (var removedDirtyIndexedItem in m_RemovedDirtyIndexedItems) {
        var previousItemStack = removedDirtyIndexedItem.Key;
        var previousPosition = removedDirtyIndexedItem.Value.position;
        var previousItemInfo = removedDirtyIndexedItem.Value.itemInfo;
      
        if(previousItemInfo.Item != itemInfo.Item){ continue; }
      
        if (IsPositionAvailable(itemInfo, previousPosition)) {
            position = previousPosition;
            return true;
        }
    }
    for (int y = 0; y < GridRows; y++) {
        for (int x = 0; x < GridColumns; x++) {
            position = new Vector2Int(x, y);
            if (IsPositionAvailable(itemInfo, position)) {
                return true;
            }
        }
    }
    position = new Vector2Int(-1, -1);
    return false;
}
 
/// <summary>
/// An item was removed, therefore remove it from the grid.
/// </summary>
/// <param name="itemInfoRemoved">The item info was removed.</param>
public void OnItemRemoved(ItemInfo itemInfoRemoved)
{
    //Clean up the grid from null items when an item is removed.
    //This works because the item stack is reset if an item is removed from the inventory.
    for (int row = 0; row < m_GridSize.y; row++) {
        for (int col = 0; col < m_GridSize.x; col++) {
            var gridElement = m_ItemStackAnchorGrid[col, row];
            var itemStack = gridElement.ItemStack;
            if (itemStack == null) {
                m_ItemStackAnchorGrid[col, row] = GridElementData.None;
                continue;
            }
            if (itemStack.Item != null) { continue; }
            if (gridElement.IsAnchor) {
                var position = new Vector2Int(col, row);
                Debug.Log("REmoving "+position+" "+gridElement.ItemInfo);
                m_RemovedDirtyIndexedItems[itemStack] = (position, gridElement.ItemInfo);
            }
              
            m_ItemStackAnchorGrid[col, row] = GridElementData.None;
        }
    }
}
 
/// <summary>
/// Cleanup some data such that the cached indezes can be removed.
/// We do not cleanup automatically in case an item moves multiple time within one frame.
/// Example when the item move collection it is removed and then added, which used to forget the index.
/// </summary>
public void Cleanup()
{
    m_RemovedDirtyIndexedItems.Clear();
}

I added a way for the grid to remember where the item was even if its ItemStack changes (this happens when the item moves between Item Collections)

You'll also need to add this function to the ItemShapeGridController script:
Code:
/// <summary>
/// Cleanup the Inventory Grid Indexer every frame.
/// </summary>
protected virtual void LateUpdate()
{
    for (int i = 0; i < m_ItemShapeGridData.Count; i++) {
        m_ItemShapeGridData[i].Cleanup();
    }
}
Hi

I have replace this function but it has some errors.

Please see the below image for you reference.

Thank you!

螢幕截圖 2021-05-21 下午4.45.45.png
 
Ah yes, I forgot to mention the change with the GridElementData, I had to add an ItemInfo field to save the not only the ItemStack but also the Item ID.

Code:
/// <summary>
/// The struct for data of the the grid element.
/// </summary>
public struct GridElementData
{
    public static GridElementData None => new GridElementData();
    public ItemInfo ItemInfo { get; private set; }
    public ItemStack ItemStack { get => ItemInfo.ItemStack;}
    public bool IsAnchor { get; private set; }
    public bool IsEmpty => ItemStack == null;
    public bool IsOccupied => ItemStack != null;
    /// <summary>
    /// Constructor.
    /// </summary>
    /// <param name="itemStack">The item stack.</param>
    /// <param name="isAnchor">Is the element an anchor.</param>
    public GridElementData(ItemStack itemStack, bool isAnchor)
    {
        //Debug.Log(itemStack);
        ItemInfo = new ItemInfo(itemStack);
        IsAnchor = isAnchor;
        //Debug.Log(IsOccupied);
    }
    /// <summary>
    /// To string.
    /// </summary>
    /// <returns>The string.</returns>
    public override string ToString()
    {
        return $"Grid ElementData : [Is Anchor '{IsAnchor}' -> {ItemStack}]";
    }
}
 
Ah yes, I forgot to mention the change with the GridElementData, I had to add an ItemInfo field to save the not only the ItemStack but also the Item ID.

Code:
/// <summary>
/// The struct for data of the the grid element.
/// </summary>
public struct GridElementData
{
    public static GridElementData None => new GridElementData();
    public ItemInfo ItemInfo { get; private set; }
    public ItemStack ItemStack { get => ItemInfo.ItemStack;}
    public bool IsAnchor { get; private set; }
    public bool IsEmpty => ItemStack == null;
    public bool IsOccupied => ItemStack != null;
    /// <summary>
    /// Constructor.
    /// </summary>
    /// <param name="itemStack">The item stack.</param>
    /// <param name="isAnchor">Is the element an anchor.</param>
    public GridElementData(ItemStack itemStack, bool isAnchor)
    {
        //Debug.Log(itemStack);
        ItemInfo = new ItemInfo(itemStack);
        IsAnchor = isAnchor;
        //Debug.Log(IsOccupied);
    }
    /// <summary>
    /// To string.
    /// </summary>
    /// <returns>The string.</returns>
    public override string ToString()
    {
        return $"Grid ElementData : [Is Anchor '{IsAnchor}' -> {ItemStack}]";
    }
}
Thanks for your code, the items now stay on the same position which just what I want, but I still find some problems, let me list the problems below.

1.some unclick slots still auto select after using the item action.
2.when I keep equipping the item by using the equip item action, one of the weapon just disappear with an error stack overflow exception. Please see the below image.
螢幕截圖 2021-05-21 下午7.51.56.png

I also have recorded a video, please click the below link to watch the video for your reference.

Thank you!
 
I'm sorry that there are so many bugs with this, I thought I had tested it thoroughly but clearly I missed a few edge cases.

I was able to replicate both issues, but I haven't found a proper solution yet.

For now you can add this on line 87 of the ItemShapeItemView script:
Code:
if (anchorItemView == View) {
    //Debug.LogWarning("The anchorItemView is not set as the anchor", gameObject);
    return m_ForegroundItemView;
}
That will prevent the stack overflow error from happening. But I haven't found the cause for that.

I'm still looking into why it is sometimes highlighting the wrong item, I wonder if both issues are related or not.
 
I'm sorry that there are so many bugs with this, I thought I had tested it thoroughly but clearly I missed a few edge cases.

I was able to replicate both issues, but I haven't found a proper solution yet.

For now you can add this on line 87 of the ItemShapeItemView script:
Code:
if (anchorItemView == View) {
    //Debug.LogWarning("The anchorItemView is not set as the anchor", gameObject);
    return m_ForegroundItemView;
}
That will prevent the stack overflow error from happening. But I haven't found the cause for that.

I'm still looking into why it is sometimes highlighting the wrong item, I wonder if both issues are related or not.
Honestly, keep watching all the tutorials videos over and over, I still not able to find a smooth way to customize the system because there are so many components on the gameobjects after the setup which for me, is still hard to fully understand how everything works. Therefore, I wonder if causing these bugs was my problem with not setting the system right.

Would you mind to set up a full functional item shape grid inventory and see if these bugs are still occurring with your setup?

I really love the idea of the item shape grid inventory style. i really want my game to have it.

Thank You
 
Top