Unity Backpack System - Split

        I have already explained the specific realization of the basic functions of the backpack system in the previous part of the backpack system. Here, I will only explain the split function of my backpack system separately, because when each grid occupies a certain number of items, we are likely to encounter them. When it is necessary to split the item, the code of this time is the same as the previous one (but the wrong description before it has been changed).

        First release the attribute part of the class in the code

    private GameObject image;//物品栏图片组件

    private GameObject Re_gameObject;//拖动前父物体

    private bool Shift_Drag;//是否是按下shift键下拖拽,当然键位可以自定义

    private bool Shift_Drag_End;//是否是真正的拆分情况

    private GameObject Current_image;//临时存放原组物体

        This is the first method body. Press shift to modify Shift_Drag , because splitting and dragging items are different. When splitting an item, the original grid still has an object, and the taken out object is a copy of this object. Then just do the subtraction operation on the characters of the displayed quantity of the object on the molecule, copy the body quantity system, so you need a bool to mark whether it is a split object, but please note that if the quantity of the object is only one, then it It is not considered a real split. It cannot copy the original object and then reduce the number of the original object by one (there will be a problem of 0 objects). Shift_Drag_End is to indicate whether the split operation is really done.

    //点击物品,准备拖动时,执行一次
    public void OnBeginDrag(PointerEventData eventData)
    {
        //获取到需要拖动的物品
        GameObject image_info = eventData.pointerCurrentRaycast.gameObject;
        if (image_info.CompareTag("goods"))
        {
            if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift) && !Shift_Drag)//在按下shift情况下的单拖
            {
                Shift_Drag = true;//按下了shfit,但不一定视为拆分操作
            }
            //拿到移动前的父物体
            Re_gameObject = image_info.transform.parent.gameObject;
            
            image = image_info;//保存图片信息
            image.transform.SetParent(transform);//设置父物体使得图像始终在背包界面最上层
        }
    }

        The following is the operation of splitting the copied object. Text_Num is to obtain the number displayed by the text component and return the value. After execution, you need to put num-=set_num inside the if, because the number of your items will be modified later, which is also reserved for subsequent multi-order splits), which means that it is a split operation.

    //在按住物品进行拖动时执行
    public void OnDrag(PointerEventData eventData)
    {
        if (image != null)//如果玩家手上有拖动中的物品
        {
            Vector3 New_Position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            New_Position.z = 0;
            if (Shift_Drag)//进行的是拆分移动
            {
                int num = Text_Num(image);
                num--;
                if(num > 0)//数量不足够进行拆分
                {
                    //更改物品数量
                    image.GetComponentInChildren<TMP_Text>().text = num.ToString();
                    //复制一个物品
                    GameObject game = Instantiate(image, New_Position, Quaternion.identity);
                    //将物体的拆分转为移动中的物体而不是全部物体
                    game.transform.SetParent(Re_gameObject.transform);
                    game.transform.localScale = image.transform.localScale;
                    //更改原物体的父子关系,回到原格子中
                    image.transform.SetParent(Re_gameObject.transform);
                    Current_image = image;
                    image = game;//设置image为新物品
                    //标记数字
                    image.GetComponentInChildren<TMP_Text>().text = "1";
                    image.transform.SetParent(transform);//设置父物体使得新物品始终在背包界面最上层
                    Shift_Drag_End = true;//确认进行了拆分操作
                }
                Shift_Drag = false;//重置Shift_Drag
            } 
            image.GetComponent<CanvasGroup>().blocksRaycasts = false;//让物品不再被拖拽检测
            image.transform.position = New_Position;//实时改变物品的位置和鼠标保持一致
        }
    }

        loaclScale is to keep the image size of the clone consistent with the original image, and current_image is the game object class that records the original image group. In theory, Re_gameobject.transform.getchild(0).gameobject can be used instead. When judging whether it is a split operation, you must set Shift_Drag to false. Some people may think that because after the image split is set, the value returned by Text_num will always be num before you select a new item, so it is not necessary It needs to be modified, but if you have multiple keys to control different numbers of splits, such as CTRL to control 10 splits at a time, conflicts may occur. Another problem is that when you hold down shift to split, items may not necessarily be copied , and when it is placed on a new grid, the processing method for splitting and not happening is different, so you need to use the principle of Shift_Drag_End instead of Shift_Drag .

        The following is the last part of the code for processing logic.

    //鼠标放开执行的操作
    public void OnEndDrag(PointerEventData eventData)
    {
        GameObject No_gameobject = eventData.pointerCurrentRaycast.gameObject;
        if (image != null && No_gameobject == null)//超出边界的情况
        {
            Goods_RePosition();
            image.GetComponent<CanvasGroup>().blocksRaycasts = true;//可以在次被检测拖拽
        }
        else if(image != null && No_gameobject != null)//如果玩家手上有拖动中的物品
        {
            if (No_gameobject.transform.CompareTag("item"))
            {
                //判断是否放开的位置是在格子上还是物品上,如果是格子看是否为空格子,是则直接将物品放入
                //不是,则把GameObject的指向的物体转换为这个物品并进行之后的操作
                if (No_gameobject.transform.childCount >= 1)//该格子上已有物品
                {
                    //将物体组件指向为该物品而不是格子
                    No_gameobject = No_gameobject.transform.GetChild(0).gameObject;
                    Goods_Change(No_gameobject);
                }
                else//对应情况为,格子上无物品,直接放入
                {
                    Position_Change(image, No_gameobject);
                    image.GetComponent<CanvasGroup>().blocksRaycasts = true;//可以在次被检测拖拽
                }
            }
            else if (No_gameobject.CompareTag("goods"))//放置的位置在物品上
            {
                Goods_Change(No_gameobject);
            }
            else//放置的不再任何合法位置上
            {
                Goods_RePosition();
            }
        }
        Shift_Drag_End = false;
        image = null;
    }

    //将指定为子物体的位置置于父物体,并修改为父子关系
    private void Position_Change(GameObject Son_GameObject,GameObject Fat_GameOject)
    {
        Son_GameObject.transform.position = Fat_GameOject.transform.position;
        Son_GameObject.transform.SetParent(Fat_GameOject.transform);
    }

    //返回物品数量,只限于物品本身没有脚本的情况的代码,不建议
    private int Text_Num(GameObject gameObject)
    {
        string text = gameObject.GetComponentInChildren<TMP_Text>().text;
        int.TryParse(text, out int u_text);//拿到物品的数量
        return u_text;
    }

    //合并物品组
    private void Shift_Drags(GameObject gameObject)
    {
        int G_Num = Text_Num(gameObject);
        int I_Num = Text_Num(image);
        G_Num += I_Num;
        gameObject.GetComponentInChildren<TMP_Text>().text = G_Num.ToString();
        Destroy(image);
        Current_image = null;
    }

    //比较是否是同一类物体,利用对比是否是同一图片,这是不建议的方式
    //实际身上应该使用在物品上挂载脚本设置数量,最大堆叠数量,编号等等,也能为后续增加更多功能
    //所以这是一种参考方法,主要是学习实现思想
    private bool Goods_Compare(GameObject gameObject)
    {
        return gameObject.GetComponent<Image>().sprite.name == image.GetComponent<Image>().sprite.name;
    }

    private void Goods_Change(GameObject gameobject)//将物体置于新位置
    {
        if (Goods_Compare(gameobject))//对应情况为,格子上有物品为同一组
        {
            Shift_Drags(gameobject);//合并两个物品组
        }
        else if (Shift_Drag_End)//对应情况为,格子上有物品但是不是同一组,并是拆分下的物品
        {
            Shift_Drags(Current_image);//将拆分出的物品放回原物体组
        }
        else//物品不是同一组但不是拆分情况
        {
            Position_Change(image, gameobject.transform.parent.gameObject);//先将传入的物品放入这个物品的格子上
            Position_Change(gameobject, Re_gameObject);//再将这个格子上的物体放入原传入物体的位置上
            image.GetComponent<CanvasGroup>().blocksRaycasts = true;//可以在次被检测拖拽
        }
    }

    private void Goods_RePosition()//将物体回归原位置
    {
        if (Shift_Drag_End)//传过来的是拆分出的物品
        {
            Shift_Drags(Current_image);//将物品放回原组
        }
        else//传过来的不是拆分出的物品
        {
            Position_Change(image, Re_gameObject);//将物品放回格子
            image.GetComponent<CanvasGroup>().blocksRaycasts = true;//可以在次被检测拖拽
        }
    }

        When Shift_Drag_End occurs ( that is, when the split operation actually occurs ), the object may be placed on a new empty grid, or it may be placed on the same item (here I have not made the upper limit function of the number of stacks, but if it can I don’t think it will be a big problem to learn to understand the split logic to do this function) and not on the same object. When the first situation occurs, it is similar to preventing the new object from being created in a new position, while the latter two One needs to destroy the item itself and then do numerical processing on the original/new item group. Then see the code for the specific judgment processing logic, because this is not easy to explain, but the core idea is the most important.

        Finally, check whether there is a problem with the split logic in the system.

 

Guess you like

Origin blog.csdn.net/WEIWEI6661012/article/details/130274569