背包系统(2) 详细笔记

29.选中物体跟随鼠标移动


如图,Picked要用InventoryManager来管理.
首先把Prefab中的item添加入Canvas里面,改名PickedItem.
这个Item就是鼠标点击之后跟随鼠标移动的Item.
原理就是点击Slot里面的Item,把这个Item复制到PickedItem上面.
Slot里面的Item要Destroy掉.
然后把这个PickedItem放在鼠标下面,跟随鼠标移动.
在ItemUI中构造3个方法:
    public void Show()//设置出现
    {
        gameObject.SetActive(true);
    }
    public void Hide()//设置隐藏
    {
        gameObject.SetActive(false);
    }
    public void SetLocalPosition(Vector3 position)//设置该物体的位置,LocalPosition画布位置.
    {
        transform.localPosition = position;
    }
在InventoryManager中.
    private ItemUI pickedItem;
    void Start()
    {
        ParseItemJson();//开始解析Json
        toolTip = GameObject.FindObjectOfType<ToolTip>();
        //因为只有一个ToolTip类型,所以用FindObjectOfType来查找.
        canvas = GameObject.Find("Canvas").GetComponent<Canvas>();
        pickedItem = GameObject.Find("PickedItem").GetComponent<ItemUI>();
        //通过ItemUI来控制PickedItem的状态.
    }
这样我们就能在InventoryManager中得到ItemUI的显示/隐藏方法,同时也能设置他的位置.
那么,只要在InventoryManager中控制什么情况下显示/隐藏.
然后得到他应该显示的位置,然后把这个位置赋值给ItemUI中SetLocalPosition设置位置的方法就好了.
30.列出MUL关系图
一共是9种情况.
这个功能要做成点击Slot然后进行条件判断,所以这个功能要放在Slot脚本里面做.
首先给出一个接口检测鼠标按下 然后实现这个接口.
public class Slot : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler,IPointerDownHandler
    public void OnPointerDown(PointerEventData eventData)
    {
        //各种判断条件
    }
31.捡起物品功能.
我们首先做捡起物品的功能,也就是PickedItem上面没有Item,Solt上有Item.
首先做这个的原因:因为别的功能会基于PickedItem不为空.
我们首先判断PickedItem是否为空.
么就要在InventoryManager中得到该组件.
    private bool isPickedItem=false;//判断当前的鼠标有没有选中物体
    public bool IsPickedItem//构造一个函数方便外界调用.
    {
        get { return isPickedItem; }
    }
    private ItemUI pickedItem;//鼠标选中的物体(这里修改成public的话就可以不用下面的构造函数,但是会不安全.)
    public ItemUI PickedItem//这里做这个构造函数主要是为了让外部可以访问他.
    {
        get { return pickedItem; }//这里只有get函数,只能访问不能修改.
    }
果想把Slot中的ItemUI复制给PickedItem,那么就要在ItemUI中做一个方法.
这里注意为什么是复制ItemUI而不是Item.
Item里面存储的是物品的基本属性.
而ItemUI里面存储的是 Item Amount 图片
所以这里Solt和PickedItem交换的都是ItemUI.
    public void SetItem(Item item, int amount = 1)
    {
        this.Item = item;
        this.Amount = amount;
        ItemImage.sprite = Resources.Load<Sprite>(item.Sprite);
        //itemImage.sprite表示在itemImage下面的sprite组件.也就是这个组件的渲染图片
        //Resources.Load<a>(b);表示加载a类型的b路径的一个组件.
        if (Item.Capacity > 1)
        {
            AmountText.text = Amount.ToString();
        }
        else
        {
            AmountText.text = "";
        }
        //表示让这个数量转化成字符串显示.
    }
    public void SetItem(ItemUI itemUI)//这个方法调用了上面的方法.虽然名字一样,但是参数不一样.
    {
        SetItem(itemUI.Item,itemUI.Amount);
    }
然后再在Slot中做条件判断.
其实下面的表就是上面哪个图片用C#的形式表现出来.
    //当在格子上鼠标按下的时候.
    public void OnPointerDown(PointerEventData eventData)
    {
        if (transform.childCount != 0) //格子不空
        {
            if (InventoryManager.Instance.PickedItem == null) //鼠标是空
            {
                if (Input.GetKey(KeyCode.LeftControl))//按下Ctrl
                {
                    //获取一半格子物品
                }
                else//不按Ctrl
                {
                    //获取格子全部物品
                }
            }
            else//鼠标不空
            {
                if (InventoryManager.Instance.PickedItem.Item.ID !=
                    transform.GetChild(0).GetComponent<ItemUI>().Item.ID) //格子和鼠标物体不一样
                {
                    //交换鼠标和格子上的物体.
                }
                else//格子和鼠标物体一样.
                {
                    if (Input.GetKey(KeyCode.LeftControl)) //按下Ctrl
                    {
                        //鼠标上的一个Item放到格子上
                    }
                    else//不按Ctrl
                    {
                        if (InventoryManager.Instance.PickedItem.Item.Capacity >=
                            transform.GetChild(0).GetComponent<ItemUI>().Amount +
                            InventoryManager.Instance.PickedItem.Amount)
                            //物品的最大容量不小于格子和鼠标上的和.
                        {
                            //放下鼠标的物体,并销毁
                        }
                        else//格子上放不下所有的物体
                        {
                            //格子放满,鼠标上留下剩下的物体.
                        }
                    }
                }
            }
        }
        else//格子是空
        {
            if (InventoryManager.Instance.PickedItem == null) //鼠标也为空.
            {
                //不做处理.
            }
            else//鼠标不为空.
            {
                if (Input.GetKey(KeyCode.LeftControl)) //按下Ctrl
                {
                    //鼠标上的一个Item放到格子上
                }
                else//不按Ctrl
                {
                    //放置全部Item.
                }
            }
        }
    }
31.完成捡起物品,捡起一半物品的功能.
首先在InventoryManager中添加捡起Item的方法
    public void PickupItem(Item item,int amount)//捡起Item,并指定数量
    {
        PickedItem.SetItem(item,amount);//把Solt里面的ItemUI复制到鼠标上
        isPickedItem = true;//把鼠标上是否有东西的标志位设置为true
    }
在ItemUI中设置物品槽的物品数量,所以要添加一个方法
     public void SetAmount(int amount)//设置当前slot位置上剩余的数量
    {
        this.Amount = amount;
        //跟新UI显示
        if (Item.Capacity > 1)
        {
            AmountText.text = Amount.ToString();
        }
        else
        {
            AmountText.text = "";
        }
    }
slot中的代码
        if (transform.childCount > 0) //格子不空
        {
            ItemUI currentItem = transform.GetChild(0).GetComponent<ItemUI>();
            if (InventoryManager.Instance.IsPickedItem == false) //鼠标是空
            {
                if (Input.GetKey(KeyCode.LeftControl))//按下Ctrl
                {
                    //获取一半格子物品.
                    int amountPicked = (currentItem.Amount + 1) / 2;//这个只会对奇数产生影响.如果是偶数就没有影响
                    InventoryManager.Instance.PickupItem(currentItem.Item, amountPicked);
                    if (currentItem.Amount-amountPicked<=0)//当全部拿走的时候
                    {
                        Destroy(currentItem.gameObject);
                    }
                    else//格子里面还有剩余的时候
                    {
                        currentItem.SetAmount(currentItem.Amount - amountPicked);
                    }
                }
                else//不按Ctrl
                {
                    //获取格子全部物品
                    InventoryManager.Instance.PickupItem(currentItem.Item,currentItem.Amount);
                    /*下面的这个方法在InventoryManager中用PickupItem代替.
                     * InventoryManager.Instance.PickedItem.SetItem(currentItem);
                    在ItemUI中有SetItem方法,能复制ItemUI.
                    InventoryManager.Instance.IsPickedItem = true;
                    当他得到物品之后就设置他的属性为true;*/
                    Destroy(currentItem.gameObject);
                }
            }
32.让选中的物体跟随鼠标移动
首先把隐藏的PickedItem显示出来.
在InventoryManager中
    public void PickupItem(Item item,int amount)//捡起Item,指定数量
    {
        PickedItem.SetItem(item,amount);//把Solt里面的ItemUI复制到鼠标上
        PickedItem.Show();
        isPickedItem = true;//把鼠标上是否有东西的标志位设置为true
    }
然后再Update中书写功能
        if (isPickedItem)//如果鼠标选中物体,让物体跟随鼠标
        {
            Vector2 position;
            //下面的函数用来得到鼠标的位置,并返回到position上.
            RectTransformUtility.ScreenPointToLocalPointInRectangle
                (canvas.transform as RectTransform, Input.mousePosition, null, out position);
            pickedItem.SetLocalPosition(position);
        }
在拿起物品的时候就不应该显示tooltip了
所以.Update下面的Tooltip就要用else if语句,先判断是不是有东西如果没有东西在进行判断是不是要给tooltip.
  void Update()
    {
        if (isPickedItem)//如果鼠标选中物体,让物体跟随鼠标
        {
           xxxx
        }else if (isToolTipShow)//如果ToolTip显示出来,让tooltip跟随鼠标
        {
           xxxx
        }
    }
在PickupItem的时候马上把当前tooltip隐藏掉.
public void PickupItem(Item item,int amount)//捡起Item,指定数量
    {
        PickedItem.SetItem(item,amount);//把Solt里面的ItemUI复制到鼠标上
        isPickedItem = true;//把鼠标上是否有东西的标志位设置为true
        PickedItem.Show();
        this.toolTip.Hide();//如果鼠标上有东西就不显示该物体的tooltip
    }
此外,在鼠标移动到别的Slot上面也不显示tooltip
    public void ShowToolTip(string content)
    {
        if (isPickedItem)//如果鼠标上有东西就不显示tooltip 直接跳出
        {
            return;
        }
        isToolTipShow = true;//标志位,用来查看是否显示提示信息.
        toolTip.Show(content);
    }
33.物体选中的动画效果.
首先修改一个问题.
我们创建出来Item的时候,物体会在放Canvas的Slot里面.但是Canvas本身就要Scale.并且Scale不为1.

所以我们创建出来的物体,本身的大小会被缩放.


这时候我们要在Slot存储这个Item的时候把这个Item的Sacle设置成1.
    public void StoreItem(Item item)//用于存储Item
    {
        if (transform.childCount == 0)//如果是个空物品槽,实例化出来一个
        {
            //实例化出来一个itemPrefab.把这个itemPrefab作为Gameobject
            GameObject itemGameObject = Instantiate(itemPrefab) as GameObject;
            //把父类的位置和自身的位置重合
            itemGameObject.transform.SetParent(this.transform);
            itemGameObject.transform.localScale = Vector3.one;//将准备存储在Slot的Item的比例缩放成1.
            itemGameObject.transform.localPosition = Vector3.zero;
            //这里他的父类和自身都是中心点设计,所以设置Vector3.zero(位置归零)
            itemGameObject.GetComponent<ItemUI>().SetItem(item); //得到ItemUI组件,设置图片和数量.
        }
这个时候,在创建出来的物体的比例就是1了.

接下来就可以做动画效果了.
所谓的动画效果就是让Item在选中的时候放大一下,然后在以一定的速率恢复到原来的大小.
因为这个动画是在Item上产生,所以要放在ItemUI上来做.
需要做动画效果的地方有SetItem SetAmount AddMount
    #region 设置动画
        //动画效果为:再点击或者增加的时候图片会瞬间变大,然后再慢慢缩小.
    private float targetScale = 1f;//这个是最后的比例大小,动画最后一定是要还原的,所以这里的目标值为1
    private Vector3 animationScale = new Vector3(1.2f, 1.2f, 1.2f);//这个是动画开始时候的效果,最开始的时候目标动画是放大的
    private float smoothing = 4f;//缩小的速度
    void Update()
    {
        if (transform.localScale.x != targetScale)//当图片目前的大小和目标大小/原大小(targetSacle)不一致的时候.
        {
            float scale = Mathf.Lerp(transform.localScale.x, targetScale, Time.deltaTime * smoothing);
            //得到一个缩放比例插值,从当前的大小,变化到原大小.
            //在物体被存储或者数量有变化的时候,在最开始,会把动画的最开始的大小赋值给图片.
            //也就是把animationScale赋值给图片.
            if (Mathf.Abs(transform.localScale.x - targetScale) < 0.01f)//为了减轻运算负担,当他们的差值小于0.01的时候我们就认为他们已经相等了.插值运算的当前值永远不会到达目标值
            {
                transform.localScale = Vector3.one;
            }
            //把得到的插值放到当前的图片比例当中.
            transform.localScale = new Vector3(scale, scale, scale);
        }
    }
    #endregion
    在下面的三个函数中分别让他们能的初始大小变成animationScale大小.
    也就是在他们的函数里面加入:transform.localScale = animationScale; 这句代码
    public void SetItem(Item item, int amount = 1)
    public void AddAmount(int amount = 1)
    public void SetAmount(int amount)//设置当前slot位置上剩余的数量
这样就完成了动画效果.
34.完成鼠标和格子物品一样时候的按下Ctrl的功能.
这时候点击鼠标左键,会产生2个效果,slot里面的物品+1
鼠标上的物品-1
减少一个Item的数量,这个功能要做在ItemUI里面.
    #region 减少鼠标上的物品数量
    public void ReduceAmount(int amount = 1)
    {
        this.Amount -= amount;
        transform.localScale = animationScale;
        //跟新UI显示
        if (Item.Capacity > 1)
        {
            AmountText.text = Amount.ToString();
        }
        else
        {
            AmountText.text = "";
        }
    }
    #endregion
鼠标上减少一个物体,这个功能要做在inventoryManager里面.
因为是用InventoryManager来管理鼠标上的PickedItem的.
    #region 减少鼠标上的一个Item
    public void RemoveOneItem()
    {
        PickedItem.ReduceAmount();
        if (pickedItem.Amount<=0)
        {
            isPickedItem = false;
            pickedItem.Hide();
        }
    }
#endregion
Slot里面的存储功能.(按下Ctrl)
                else//格子和鼠标物体一样.
                {
                    if (Input.GetKey(KeyCode.LeftControl)) //按下Ctrl
                    {
                        //鼠标上的一个Item放到格子上
                        if (currentItem.Item.Capacity>currentItem.Amount)//如果当前的最大容量没有满
                        {
                            currentItem.AddAmount();//增加格子上一个物品的个数.
                            //鼠标上减少一个物品
                            InventoryManager.Instance.RemoveOneItem();
                        }
                    }
35.鼠标和格子上面有相同Item 将鼠标上的Item放置在格子里面.
不按Ctrl
                    else//不按Ctrl
                    {
                        if (InventoryManager.Instance.PickedItem.Item.Capacity >=
                           currentItem.Amount +
                            InventoryManager.Instance.PickedItem.Amount)
                        //物品的最大容量不小于格子和鼠标上的和.
                        {
                            //放下鼠标的物体,并销毁.格子上增加物体
                            currentItem.SetAmount(currentItem.Amount + InventoryManager.Instance.PickedItem.Amount);
                            InventoryManager.Instance.RemoveAllItem();
                        }
                        else//格子上放不下所有的物体
                        {
                            //格子放满,鼠标上留下剩下的物体.
                            InventoryManager.Instance.PickedItem.SetAmount(currentItem.Amount + InventoryManager.Instance.PickedItem.Amount - currentItem.Item.Capacity);
                            currentItem.SetAmount(currentItem.Item.Capacity);
                        }
                    }
36.格子为空.
分为2种情况,1鼠标上有物体 2鼠标上没有物体
        else//格子是空
        {
            if (InventoryManager.Instance.IsPickedItem == false) //鼠标也为空.
            {
                //不做处理.
            }
            else//鼠标不为空.
            {
                if (Input.GetKey(KeyCode.LeftControl)) //按下Ctrl
                {
                    //鼠标上的一个Item放到格子上
                    StoreItem(InventoryManager.Instance.PickedItem.Item);
                    InventoryManager.Instance.RemoveOneItem();
                }
                else//不按Ctrl
                {
                    //放置全部Item.
                    StoreItem(InventoryManager.Instance.PickedItem.Item);
                    transform.GetChild(0).GetComponent<ItemUI>().SetAmount(InventoryManager.Instance.PickedItem.Amount);
                    InventoryManager.Instance.RemoveAllItem();
                }
            }
        }
因为格子是空的,所以不能直接得到GetChild(0),所以要在这个格子上先实例化出来一个物体.
然后在改变这个物体的数量. 
37.鼠标和格子物品交换.
 else//鼠标不空
            {
                if (InventoryManager.Instance.PickedItem.Item.ID !=
                   currentItem.Item.ID) //格子和鼠标物体不一样
                {
                    //交换鼠标和格子上的物体.
                    Item tempItem = InventoryManager.Instance.PickedItem.Item;
                    int tempAmount = InventoryManager.Instance.PickedItem.Amount;
                    //Item和Amount要分开记录.我也不知道为什么..
                    InventoryManager.Instance.PickedItem.SetItem(currentItem.Item, currentItem.Amount);
                    currentItem.SetItem(tempItem, tempAmount);
                }
 38.物品的丢弃.
物品的丢失功能是在鼠标选取物体之后,在空白的地方点击就会丢弃物品.
这个功能做在InventoryManager的Update中.
        //丢弃物体的功能
        //要符合三个条件才会丢弃物品
        /// 1.鼠标上有物体
        /// 2.按下鼠标左键
        /// 3.当前的鼠标位置下面没有任何UI组件
        if (isPickedItem&&Input.GetMouseButtonDown(0)&&UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(-1)==false )
        {
            //UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(-1)
            //上面可以得到现在鼠标左键下是否有UI组件.false为没有 true为有.
            isPickedItem = false;
            pickedItem.Hide();
        }
获取鼠标在屏幕上的位置:
UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(-1)
这里的参数-1为鼠标左键.
记住就好.别问为什么.我也不知道.

这里有一点要注意:
如果一个UI添加了CanvasGroup组件.
而且他没有勾选Blocks Raycasts.那么这个UI就不会有交互.
也就是说这时候放置鼠标上的物体的时候,物体直接会消失.
到此,鼠标和Slot的交互功能就完成了. 













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值