基于Unity3D(UGUI)的背包系统<四>完结篇

本文详细介绍了如何使用Unity3D的UGUI构建背包系统,包括物品槽基类Slot实现交互功能,角色面板的EquipmentSlot,商店购买的VendorSlot,物品UI管理类ItemUI,提示框类ToolTip以及模拟主角行为的Player类。提供了一个完整的背包系统实现流程。
这一篇介绍各个面板(UI)与数据的交互,以及对更细节方面的处理(如每一个面板的物品槽的管理)。PS:具体逻辑参照UML类图即可。


**①存货总管理类:重点是实现对物品Json文件的解析。**
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;

/// <summary>
/// 存货总管理类
/// </summary>
public class InventroyManager : MonoBehaviour {
    //单例模式
    private static InventroyManager _instance;
    public static InventroyManager Instance 
    {
        get {
            if (_instance == null)
            {
                _instance = GameObject.Find("InventroyManager").GetComponent<InventroyManager>();
            }
           return _instance;
        }
    }
    private List<Item> itemList;//存储json解析出来的物品列表

    private ToolTip toolTip;//获取ToolTip脚本,方便对其管理
    private bool isToolTipShow = false;//提示框是否在显示状态
    private Canvas canvas;//Canva物体
    private Vector2 toolTipOffset =new Vector2(15, -10);//设置提示框跟随时与鼠标的偏移

    private ItemUI pickedItem;//鼠标选中的物品的脚本组件,用于制作拖动功能 
    public ItemUI PickedItem { get { return pickedItem; } }
    private bool isPickedItem = false;//鼠标是否选中该物品
    public bool IsPickedItem { get { return isPickedItem; } }

    void Awake() 
    {
        ParseItemJson();
    }

    void Start() 
    {
        toolTip = GameObject.FindObjectOfType<ToolTip>();//根据类型获取
        canvas = GameObject.Find("Canvas").GetComponent<Canvas>();
        pickedItem = GameObject.Find("PickedItem").GetComponent<ItemUI>();
        pickedItem.Hide();//开始为隐藏状态
    }

    void Update() 
    {
        if (isToolTipShow == true && isPickedItem == false) //控制提示框跟随鼠标移动
        {
            Vector2 postionToolTip;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, Input.mousePosition, null, out postionToolTip);
            toolTip.SetLocalPosition(postionToolTip+toolTipOffset);//设置提示框的位置,二维坐标会自动转化为三维坐标但Z坐标为0
        }
        else if (isPickedItem == true) //控制盛放物品的容器UI跟随鼠标移动
        {
            Vector2 postionPickeItem;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, Input.mousePosition, null, out postionPickeItem);
            pickedItem.SetLocalPosition(postionPickeItem);//设置容器的位置,二维坐标会自动转化为三维坐标但Z坐标为0
        }
        //物品丢弃功能:
        if (isPickedItem == true && Input.GetMouseButtonDown(0) && UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(-1) == false )//UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject(-1) == false 表示判断鼠标是否正在在UI上
        {
            isPickedItem = false;
            pickedItem.Hide();
        }
    }

    /// <summary>
    /// 解析Json文件
    /// </summary>
    public void ParseItemJson() 
    {
        itemList = new List<Item>();
        //文本在unity里面是TextAsset类型
        TextAsset itemText = Resources.Load<TextAsset>("Item");//加载json文本
        string itemJson = itemText.text;//得到json文本里面的内容
        //bug.Log(itemJson);
        JSONObject j = new JSONObject(itemJson);
        foreach (var temp in j.list)
        {
            //物品类型字符串转化为枚举类型
            Item.ItemType type = (Item.ItemType)System.Enum.Parse(typeof(Item.ItemType), temp["type"].str);
            //print(type);
            //下面解析的是物品的共有属性:id,name,quality。。。注:temp["id"].n 的 .n,.str等是json插件的写法,用于解析
            int id = (int)(temp["id"].n);
            string name = temp["name"].str;
            Item.ItemQuality quality = (Item.ItemQuality)System.Enum.Parse(typeof(Item.ItemQuality), temp["quality"].str);
            string description = temp["description"].str;
            int capacity = (int)(temp["capacity"].n);
            int buyPrice = (int)(temp["buyPrice"].n);
            int sellPrice = (int)(temp["sellPrice"].n);
            string sprite = temp["sprite"].str;
            Item item = null;
            switch (type)
            {
                case Item.ItemType.Consumable:
                    int hp = (int)(temp["hp"].n);
                    int mp = (int)(temp["mp"].n);
                    item = new Consumable(id, name, type, quality, description, capacity, buyPrice, sellPrice, sprite, hp, mp);
                    break;
                case Item.ItemType.Equipment:
                    int strength = (int)(temp["strength"].n);
                    int intellect = (int)(temp["intellect"].n);
                    int agility = (int)(temp["agility"].n);
                    int stamina = (int)(temp["stamina"].n);
                    Equipment.EquipmentType equiType = (Equipment.EquipmentType)System.Enum.Parse(typeof(Equipment.EquipmentType), temp["equipType"].str);
                    item = new Equipment(id, name, type, quality, description, capacity, buyPrice, sellPrice, sprite,strength,intellect,agility,stamina,equiType);
                    break;
                case Item.ItemType.Weapon:
                    int damage = (int)(temp["damage"].n);
                    Weapon.WeaponType weaponType = (Weapon.WeaponType)System.Enum.Parse(typeof(Weapon.WeaponType), temp["weaponType"].str);
                    item = new Weapon(id, name, type, quality, description, capacity, buyPrice, sellPrice, sprite, damage, weaponType);
                    break;
                case Item.ItemType.Material:
                    item = new Material(id, name, type, quality, description, capacity, buyPrice, sellPrice, sprite);
                    break;
            }
            itemList.Add(item);//把解析到的物品信息加入物品列表里面
            //Debug.Log(item);
        }
    }

    //得到根据 id 得到Item
    public Item GetItemById(int id) 
    {
        foreach (Item item in itemList)
        {
            if (item.ID == id)
            {
                return item;
            }
        }
        return null;
    }

    //显示提示框方法
    public void ShowToolTip(string content) 
    {
        if (this.isPickedItem == true) return;//如果物品槽中的物品被捡起了,那就不需要再显示提示框了
        toolTip.Show(content);
        isToolTipShow = true;
    }
    //隐藏提示框方法
    public void HideToolTip() {
        toolTip.Hide();
        isToolTipShow = false;
    }

    //获取(拾取)物品槽里的指定数量的(amount)物品UI
    public void PickUpItem(Item item,int amount)
    {
        PickedItem.SetItem(item, amount);
        this.isPickedItem = true;
        PickedItem.Show();//获取到物品之后把跟随鼠标的容器(用来盛放捡起的物品的容器)显示出来
        this.toolTip.Hide();//同时隐藏物品信息提示框

        //控制盛放物品的容器UI跟随鼠标移动
            Vector2 postionPickeItem;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(canvas.transform as RectTransform, Input.mousePosition, null, out postionPickeItem);
            pickedItem.SetLocalPosition(postionPickeItem);//设置容器的位置,二维坐标会自动转化为三维坐标但Z坐标为0

    }

    //从鼠标上减少(移除)指定数量的物品
    public void ReduceAmountItem(int amount = 1) 
    {
        this.pickedItem.RemoveItemAmount(amount);
        if (pickedItem.Amount <= 0)
        {
            isPickedItem = false;
            PickedItem.Hide();//如果鼠标上没有物品了那就隐藏了
        }
    }

    //点击保存按钮,保存当前物品信息
    public void SaveInventory() 
    {
        Knapscak.Instance.SaveInventory();
        Chest.Instance.SaveInventory();
        CharacterPanel.Instance.SaveInventory();
        Forge.Instance.SaveInventory();
        PlayerPrefs.SetInt("CoinAmount", GameObject.FindGameObjectWithTag("Player").GetComponent<Player>().CoinAmount);//保存玩家金币
    }

    //点击加载按钮,加载当前物品
    public void LoadInventory() 
    {
        Knapscak.Instance.LoadInventory();
        Chest.Instance.LoadInventory();
        CharacterPanel.Instance.LoadInventory();
        Forge.Instance.LoadInventory();
        //加载玩家金币
        if (PlayerPrefs.HasKey("CoinAmount") == true)
        {
            GameObject.FindGameObjectWithTag("Player").GetComponent<Player>().CoinAmount = PlayerPrefs.GetInt("CoinAmount");
        }
    }
}

②物品槽基类(Slot):重点实现了物品槽里物品的各个交互功能

using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;

/// <summary>
/// 物品槽类
/// </summary>
public class Slot : MonoBehaviour,IPointerEnterHandler,IPointerExitHandler,IPointerDownHandler{

    public GameObject itemPrefab;//需要存储的物品预设

    /// <summary>
    ///(重点) 向物品槽中添加(存储)物品,如果自身下面已经有Item了,那就Item.amount++;
    /// 如果没有,那就根据ItemPrefab去实例化一个Item,放在其下面
    /// </summary>
    public void StoreItem(Item item) 
    {
        if (this.transform.childCount == 0)//如果这个物品槽下没有物品,那就实例化一个物品
        {
            GameObject itemGO = Instantiate<GameObject>(itemPrefab) as GameObject;
            itemGO.transform.SetParent(this.transform);//设置物品为物品槽的子物体
            itemGO.transform.localScale = Vector3.one;//正确保存物品的缩放比例
            itemGO.transform.localPosition = Vector3.zero;//设置物品的局部坐标,为了与其父亲物品槽相对应
            itemGO.GetComponent<ItemUI>().SetItem(item);//更新ItemUI
        }
        else
        {
            transform.GetChild(0).GetComponent<ItemUI>().AddItemAmount();//默认添加一个
        }
    }

    //根据索引器得到当前物品槽中的物品类型
    public Item.ItemType GetItemType() 
    {
        return transform.GetChild(0).GetComponent<ItemUI>().Item.Type;
    }

    //根据索引器得到当前物品槽中的物品ID
    public int GetItemID()
    {
        return transform.GetChild(0).GetComponent<ItemUI>().Item.ID;
    }

    //判断物品个数是否超过物品槽的容量Capacity
    public bool isFiled() 
    {
        ItemUI itemUI = transform.GetChild(0).GetComponent<ItemUI>();
        return itemUI.Amount >= itemUI.Item.Capacity; //true表示当前数量大于等于容量,false表示当前数量小于容量
    }

    //接口实现的方法,鼠标覆盖时触发
    public void OnPointerEnter(PointerEventData eventData)
    {
        if (this.transform.childCount > 0)
        {
            string toolTipText = this.transform.GetChild(0).GetComponent<ItemUI>().Item.GetToolTipText();
            InventroyManager.Instance.ShowToolTip(toolTipText);//显示提示框
        }
    }
    //接口实现的方法,鼠标离开时触发
    public void OnPointerExit(PointerEventData eventData)
    {
        if (this.transform.childCount > 0)
        {
            InventroyManager.Instance.HideToolTip();//隐藏提示框
        }
    }

    public virtual void OnPointerDown(PointerEventData eventData)//为虚函数,方便子类EquipmentSlot重写
    {
        if (eventData.button == PointerEventData.InputButton.Right)//鼠标右键点击直接实现穿戴,不经过拖拽
        {
            if (transform.childCount > 0 && InventroyManager.Instance.IsPickedItem == false)//需要穿戴的物品得有,并且鼠标上要没有物品,否则就发生:当鼠标上有物品,在其他物品上点击鼠标右键也能穿上这种情况。
            {
                ItemUI currentItemUI = transform.GetChild(0).GetComponent<ItemUI>();
                if (currentItemUI.Item is Equipment || currentItemUI.Item is Weapon)//只有装备和物品才可以穿戴
                {
                    Item currentItem = currentItemUI.Item;//临时存储物品信息,防止物品UI销毁导致物品空指针
                    currentItemUI.RemoveItemAmount(1);//当前物品槽中的物品减少1个
                    if (currentItemUI.Amount <= 0)//物品槽中的物品没有了
                    {
                        DestroyImmediate(currentItemUI.gameObject);//立即销毁物品槽中的物品
                        InventroyManager.Instance.HideToolTip();//隐藏该物品的提示框
                    }
                    CharacterPanel.Instance.PutOn(currentItem);//直接穿戴
                }
            }
        }
        if (eventData.button != PointerEventData.InputButton.Left) return;  //只有鼠标左键能够点击物品拖拽
        //情况分析如下:
        //一:自身是空
                ///1.pickedItem != null(即IsPickedItem == true),pickedItem放在这个位置
                        ////①按下Ctrl键,放置当前鼠标上的物品的一个
                        ////②没有按下Ctrl键,放置当前鼠标上物品的所有
                ///2.pickedItem==null(即IsPickedItem == false),不做任何处理
        //二:自身不是空
                ///1.pickedItem != null(即 IsPickedItem == true)
                        ////①自身的id == pickedItem.id
                                //////A.按下Ctrl键,放置当前鼠标上的物品的一个
                                //////B.没有按下Ctrl键,放置当前鼠标上物品的所有
                                       ///////a.可以完全放下
                                       ///////b.只能放下其中一部分
                        ////②自身的id != pickedItem.id,pickedItem跟当前物品交换
               ///2.pickedItem == null(即IsPickedItem == false)
                        ////①按下Ctrl键,取得当前物品槽中物品的一半
                        ////②没有按下Ctrl键,把当前物品槽里面的物品放到鼠标上

        if (transform.childCount > 0) //二:自身不是空
        {
            ItemUI currentItem = transform.GetChild(0).GetComponent<ItemUI>();//取得当前的物品
            if (InventroyManager.Instance.IsPickedItem == false)///2.pickedItem == null。如果当前没有选中任何物品,即当前鼠标上没有物品
            {
                if (Input.GetKey(KeyCode.LeftControl))////①按下Ctrl键,取得当前物品槽中物品的一半
                {
                    int amountPicked = (currentItem.Amount + 1) / 2;//如果物品为偶数就拾取刚好一般,如果为奇数就拾取一半多一个
                    InventroyManager.Instance.PickUpItem(currentItem.Item, amountPicked);
                    int amountRemained = currentItem.Amount - amountPicked;//拾取后剩余的物品个数
                    if (amountRemained<=0)//如果物品槽中没有剩余的物品了,就销毁ItemUI
                    {
                        Destroy(currentItem.gameObject);
                    }
                    else//如果物品槽中还有剩余的物品,就让它的数量减去被拾取的数量
                    {
                        currentItem.SetAmount(amountRemained);
                    }
                }
                else      ////②没有按下Ctrl键,把当前物品槽里面的物品放到鼠标上
                {
                    //InventroyManager.Instance.PickedItem.SetItemUI(currentItem);//把当前物品槽里的物品复制给PickedItem(跟随鼠标移动)
                    //InventroyManager.Instance.IsPickedItem = true;//注释的这两句合并为下面的一句
                    InventroyManager.Instance.PickUpItem(currentItem.Item, currentItem.Amount);
                    Destroy(currentItem.gameObject);//复制完之后销毁当前物品槽中的物品
                }
            }
            else
            {
                ///1.pickedItem != null(即 IsPickedItem == true)
                    ////①自身的id == pickedItem.id
                        //////A.按下Ctrl键,放置当前鼠标上的物品的一个
                        //////B.没有按下Ctrl键,放置当前鼠标上物品的所有
                                 ///////a.可以完全放下
                                 ///////b.只能放下其中一部分
                ////②自身的id != pickedItem.id,pickedItem跟当前物品交换
                if (currentItem.Item.ID == InventroyManager.Instance.PickedItem.Item.ID)
                {
                    if (Input.GetKey(KeyCode.LeftControl))
                    {
                        if (currentItem.Item.Capacity > currentItem.Amount)//如果物品槽里的物品容量大于当前物品数量,那就说明物品槽里还能再放
                        {
                            currentItem.AddItemAmount();//增加物品槽中物品数量
                            InventroyManager.Instance.ReduceAmountItem();//让鼠标上的物品减掉一个(默认移除一个)
                        }
                        else//如果物品槽里的物品容量小于当前物品数量,那就说明物品槽里不能再放了
                        {
                            return;
                        }
                    }
                    else 
                    {
                        if (currentItem.Item.Capacity > currentItem.Amount)//如果物品槽里的物品容量大于当前物品数量,那就说明物品槽里还能再放
                        {
                            int itemRemain = currentItem.Item.Capacity - currentItem.Amount;//物品槽还可以再放的数量
                            if (itemRemain >= InventroyManager.Instance.PickedItem.Amount)//如果物品槽还可以再放的数量大于等于鼠标上的数量,                                那就可以完全放下
                            {
                                currentItem.AddItemAmount(InventroyManager.Instance.PickedItem.Amount);
                                InventroyManager.Instance.ReduceAmountItem(itemRemain);
                            }
                            else//只能放下其中一部分
                            {
                                currentItem.AddItemAmount(itemRemain);
                                InventroyManager.Instance.PickedItem.RemoveItemAmount(itemRemain);
                            }
                        }
                        else//如果物品槽里的物品容量小于当前物品数量,那就说明物品槽里不能再放了
                        {
                            return;
                        }
                    }
                }
                else//②自身的id != pickedItem.id,pickedItem跟当前物品交换
                {
                    //保存当前鼠标捡起物品,用于和物品槽中的物品交换
                    Item pickedItemTemp = InventroyManager.Instance.PickedItem.Item;
                    int pickedItemAmountTemp = InventroyManager.Instance.PickedItem.Amount;

                    //保存当前物品槽中的物品,用于和鼠标上的物品交换
                    Item currentItemTemp = currentItem.Item;
                    int currentItemAmountTemp = currentItem.Amount;
                    //两者交换
                    currentItem.SetItem(pickedItemTemp, pickedItemAmountTemp);//把当前鼠标上的物品放入物品槽
                    InventroyManager.Instance.PickedItem.SetItem(currentItemTemp, currentItemAmountTemp);//把当前物品槽中的物品放在鼠标上
                }
            }
        }
        else//一:自身是空
        { 
            ///1.pickedItem != null(即IsPickedItem == true),pickedItem放在这个位置
                ////①按下Ctrl键,放置当前鼠标上的物品的一个
                ////②没有按下Ctrl键,放置当前鼠标上物品的所有
            ///2.pickedItem==null(即IsPickedItem == false),不做任何处理
            if (InventroyManager.Instance.IsPickedItem == true)
            {
                if (Input.GetKey(KeyCode.LeftControl))
                {
                    this.StoreItem(InventroyManager.Instance.PickedItem.Item);
                    InventroyManager.Instance.ReduceAmountItem();
                }
                else//②没有按下Ctrl键,放置当前鼠标上物品的所有
                {
                    for(int i = 0 ; i<InventroyManager.Instance.PickedItem.Amount ; i++)
                    {
                        this.StoreItem(InventroyManager.Instance.PickedItem.Item);
                    }
                    InventroyManager.Instance.ReduceAmountItem(InventroyManager.Instance.PickedItem.Amount);
                }
            }
            else
            {
                return;
            }
        }
    }
}

③处理角色面板的物品槽类(EquipmentSlot),继承自Slot类:

using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;

/// <summary>
/// 处理角色面板上的装备物品槽类(有特殊限制的Slot:只能存放装备),不同格子只能存放这个格子应该有的装备。
/// </summary>
public class EquipmentSlot :Slot
{
    public Equipment.EquipmentType equipmentSoltType;//角色装备里每个物品槽的物品类型。因为每个物品槽能装备的物品类型不同,所以才分类型,比如说,头部只能放头部,腿部只能放腿部之类的。主手只能放武器。
    public Weapon.WeaponType wpType;//武器类型,只有副手和主手能有武器,其他为Null



    public override void OnPointerDown(UnityEngine.EventSystems.PointerEventData eventData)//重写父类Slot的方法
    {
        if (eventData.button == PointerEventData.InputButton.Right)//鼠标右键点击直接实现脱掉,不经过拖拽
        {
            if (transform.childCount > 0 && InventroyManager.Instance.IsPickedItem == false)//需要脱掉的物品得有,并且鼠标上要没有物品,否则就发生:当鼠标上有物品,在其他物品上点击鼠标右键也能脱掉这种情况。
            {
                ItemUI currentItemUI = transform.GetChild(0).GetComponent<ItemUI>();
                Item item = currentItemUI.Item;//临时保存物品信息,防止下面一销毁就没了
                DestroyImmediate(currentItemUI.gameObject);//立即销毁物品槽中的物品
                transform.parent.SendMessage("PutOff", item);//脱掉物品放入背包里(发送消息方式)
                InventroyManager.Instance.HideToolTip();//隐藏该物品的提示框
            }
        }
        if (eventData.button != PointerEventData.InputButton.Left) return;  //只有鼠标左键能够点击物品拖动
        //情况分析:
                //一:鼠标上有物品
                        //1.当前装备槽有装备
                        //2.当前装备槽无装备
               //二:鼠标上没有物品
                        //1.当前装备槽有装备
                       //2.当前装备槽无装备(不做任何处理)
        bool isUpdataProperty = false;//是否需要更新角色属性
        if (InventroyManager.Instance.IsPickedItem == true)//一:鼠标上有物品
        {
            ItemUI pickedItemUI = InventroyManager.Instance.PickedItem;//鼠标上的物品
            if (transform.childCount > 0)//1.当前装备槽有装备
            {
                ItemUI currentItemUI = transform.GetChild(0).GetComponent<ItemUI>();//当前物品槽中的物品
                if (IsRightItem(pickedItemUI.Item) && pickedItemUI.Amount == 1)//如果鼠标上的物品是否适合放在该位置并且鼠标上的物品只有一个时,那就交换,否则不做处理
                {
                    pickedItemUI.Exchange(currentItemUI);
                    isUpdataProperty = true;//需要更新角色属性
                }
            }
            else//2.当前装备槽无装备
            {
                if (IsRightItem(pickedItemUI.Item))//如果鼠标上的物品是否适合放在该位置,那就把该物品放入角色面板,并且鼠标上的物品减少一个,否则不做处理
                {
                    this.StoreItem(pickedItemUI.Item);
                    InventroyManager.Instance.ReduceAmountItem(1);
                    isUpdataProperty = true;//需要更新角色属性
                }
            }
        }
        else//二:鼠标上没有物品
        {
            if (transform.childCount>0) //1.当前装备槽有装备,把装备去到鼠标上,销毁物品槽中的物品
            {
                ItemUI currentItemUI = transform.GetChild(0).GetComponent<ItemUI>();
                InventroyManager.Instance.PickUpItem(currentItemUI.Item, currentItemUI.Amount);
                Destroy(currentItemUI.gameObject);
                isUpdataProperty = true;//需要更新角色属性
            } //2.当前装备槽无装备(不做任何处理)
        }
        if (isUpdataProperty == true)
        {
            transform.parent.SendMessage("UpdatePropertyText");
        }
    }

    //判断鼠标上的物品是否适合放在该位置
    public bool IsRightItem(Item item) 
    {
        if ((item is Equipment && ((Equipment)(item)).EquipType == this.equipmentSoltType) || (item is Weapon && ((Weapon)(item)).WpType == this.wpType))//如果此物品是装备并且此物品的装备类型和当前物品槽中的装备类型相同   或者   此物品是武器并且此武器的类型和当前物品槽中的武器类型相同,那就可以合适放在该位置,否则不合适。
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

④处理商店购买物品面板的物品槽类(VendorSlot),同样继承自Slot类:

using UnityEngine;
using System.Collections;

public class VendorSlot : Slot {

    //重写父类Slot的鼠标点击方法,但是什么都不用做,因为不需要交互,商贩只管卖物品
    public override void OnPointerDown(UnityEngine.EventSystems.PointerEventData eventData)
    {
        if (eventData.button == UnityEngine.EventSystems.PointerEventData.InputButton.Right)//在商贩那里点击右键直接购买物品
        {
            if (transform.childCount > 0 && InventroyManager.Instance.IsPickedItem == false)//首先商贩得有物品,其次鼠标上没有物品
            {
                Item currentItem = transform.GetChild(0).GetComponent<ItemUI>().Item;//取得当前点击的要买的物品
                transform.parent.parent.SendMessage("BuyItem",currentItem);
            }
        }
        else if (eventData.button == UnityEngine.EventSystems.PointerEventData.InputButton.Left && InventroyManager.Instance.IsPickedItem == true)//在背包鼠标左键拖动售卖物品
        {
            transform.parent.parent.SendMessage("SellItem");
        }
    }
}

⑤物品UI处理类(ItemUI):

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class ItemUI : MonoBehaviour
{

    public Item Item { get; private set; } //UI上的物品
    public int Amount { get; private  set; }//物品数量

    private Image itemImage;//获取item的Image组件
    private Text amountText;//获取item下子物体用于显示数量的组件

    private float targetScale = 1f;//目标缩放大小
    private Vector3 animationScale = new Vector3(1.4f, 1.4f, 1.4f);
    private float smothing = 4f;//动画平滑过渡时间

    void Awake() //可用 属性get方式替代
    {
        itemImage = this.GetComponent<Image>();
        amountText = this.GetComponentInChildren<Text>();
    }

    void Update()
    {
        if (this.transform.localScale.x != targetScale)//设置物品动画
        {
            float scaleTemp = Mathf.Lerp(this.transform.localScale.x, targetScale, smothing*Time.deltaTime);
            this.transform.localScale = new Vector3(scaleTemp, scaleTemp, scaleTemp);
            if (Mathf.Abs(transform.localScale.x-targetScale) < 0.02f)//插值运算达不到临界值,比较耗性能,加上临界值判断能更好的控制
            {
                this.transform.localScale = new Vector3(targetScale, targetScale, targetScale);
            }
        }
    }

    /// <summary>
    ///更新item的UI显示,默认数量为1个
    /// </summary>
    /// <param name="item"></param>
    public void SetItem(Item item, int amount = 1)
    {
        this.transform.localScale = this.animationScale;//物品更新时放大UI,用于动画
        this.Item = item;
        this.Amount = amount;
        this.itemImage.sprite = Resources.Load<Sprite>(item.Sprite);        //更新UI
        if (this.Amount > 1)
        {
            this.amountText.text = Amount.ToString();
        }
        else
        {
            this.amountText.text = "";
        }
    }
    /// <summary>
    /// 添加item数量
    /// </summary>
    /// <param name="num"></param>
    public void AddItemAmount(int num = 1)
    {
        this.transform.localScale = this.animationScale;//物品更新时放大UI,用于动画
        this.Amount += num;
        if (this.Amount> 1)//更新UI
        {
            this.amountText.text = Amount.ToString();
        }
        else
        {
            this.amountText.text = "";
        }
    }
    //设置item的个数
    public void SetAmount(int amount) {
        this.transform.localScale = this.animationScale;//物品更新时放大UI,用于动画
        this.Amount = amount;
        if (this.Amount > 1)//更新UI
        {
            this.amountText.text = Amount.ToString();
        }
        else
        {
            this.amountText.text = "";
        }
    }

    //减少物品数量
    public void RemoveItemAmount(int amount = 1) 
    {
        this.transform.localScale = this.animationScale;//物品更新时放大UI,用于动画
        this.Amount -= amount;
        if (this.Amount > 1)//更新UI
        {
            this.amountText.text = Amount.ToString();
        }
        else
        {
            this.amountText.text = "";
        }
    }

    //显示方法
    public void Show() {
        gameObject.SetActive(true);
    }

    //隐藏方法
    public void Hide() {
        gameObject.SetActive(false);
    }

    //设置位置方法
    public void SetLocalPosition(Vector3 position)
    {
        this.transform.localPosition = position;
    }

    //当前物品(UI)和 出入物品(UI)交换显示
    public void Exchange(ItemUI itemUI) 
    {
        Item itemTemp = itemUI.Item;
        int amountTemp = itemUI.Amount;
        itemUI.SetItem(this.Item, this.Amount);
        this.SetItem(itemTemp, amountTemp);
    }
}

⑥信息提示框类(ToolTip),处理提示框的各种功能:

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
/// <summary>
/// 提示框类
/// </summary>
public class ToolTip : MonoBehaviour {

    private Text toolTipText;//提示框的父Text,主要用来控制提示框的大小
    private Text contentText;//提示框的子Text,主要用来显示提示
    private CanvasGroup toolTipCanvasGroup;//提示框的CanvasGroup组件,用来制作显示和隐藏功能
    private float targetAlpha = 0.0f ;//设置提示框的Alpha值,0代表隐藏,1代表显示
    public float smothing = 1.0f;//用于显示和隐藏的插值运输

    void Awake() 
    {
        toolTipText = this.GetComponent<Text>();
        contentText = this.transform.Find("Content").GetComponent<Text>();
        toolTipCanvasGroup = this.GetComponent<CanvasGroup>();
    }

    // Update is called once per frame
    void Update () {
        if (toolTipCanvasGroup.alpha != targetAlpha)
        {
            toolTipCanvasGroup.alpha = Mathf.Lerp(toolTipCanvasGroup.alpha, targetAlpha, smothing*Time.deltaTime);
            if (Mathf.Abs(targetAlpha - toolTipCanvasGroup.alpha) < 0.01f)//如果当前提示框的Alpha值与目标Alpha值相差很小,那就设置为目表值
            {
                toolTipCanvasGroup.alpha = targetAlpha;
            }
        }
    }

    //提示框的显示方法
    public void Show(string text) 
    {
        this.toolTipText.text = text;
        this.contentText.text = text;
        this.targetAlpha = 1;
    }
    //提示框的隐藏方法
    public void Hide() 
    {
        this.targetAlpha = 0;
    }

    //设置提示框自身的位置
    public void SetLocalPosition(Vector3 postion) 
    {
       this.transform.localPosition = postion;
    }
}

⑦模拟主角行为类(Player):

using UnityEngine;
using System.Collections;
using UnityEngine.UI;
/// <summary>
/// 模拟主角类
/// </summary>
public class Player : MonoBehaviour {

    //角色基本属性:
    private int basicStrength = 10;
    public int BasicStrength { get { return basicStrength;} }//基本力量

    private int basicIntellect = 10;
    public int BasicIntellect { get { return basicIntellect; } }//基本智力

    private int basicAgility = 10;
    public int BasicAgility { get { return basicAgility; } }//基本敏捷

    private int basicStamina = 10;
    public int BasicStamina { get { return basicStamina; } }//基本体力

    private int basicDamage = 10;
    public int BasicDamage { get { return basicDamage; } }//基本伤害

    private Text coinText;//对金币Text组件的引用
    private int coinAmount = 100;//角色所持有的金币,用于从商贩那里购买物品
    public int CoinAmount {
        get { return coinAmount; }
        set { coinAmount = value; coinText.text = coinAmount.ToString(); }
    }


    // Use this for initialization
    void Start () {
        coinText = GameObject.Find("Coin").GetComponentInChildren<Text>();
        coinText.text = coinAmount.ToString();
    }

    // Update is called once per frame
    void Update () {
        //按G键随机得到一个物品
        if (Input.GetKeyDown(KeyCode.G))
        {
            int id = Random.Range(1, 23);
            Knapscak.Instance.StoreItem(id);
        }
        //按下B键控制背包的显示和隐藏
        if (Input.GetKeyDown(KeyCode.B))
        {
            Knapscak.Instance.DisplaySwitch();
        }
        //按下H键控制箱子的显示和隐藏
        if (Input.GetKeyDown(KeyCode.H))
        {
            Chest.Instance.DisplaySwitch();
        }
        //按下V键控制角色面板的显示和隐藏
        if (Input.GetKeyDown(KeyCode.V))
        {
            CharacterPanel.Instance.DisplaySwitch();
        }
        //按下N键商店小贩面板的显示和隐藏
        if (Input.GetKeyDown(KeyCode.N))
        {
            Vendor.Instance.DisplaySwitch();
        }
        //按下M键锻造面板的显示和隐藏
        if (Input.GetKeyDown(KeyCode.M))
        {
           Forge.Instance.DisplaySwitch();
        }
    }

    //消费金币
    public bool ConsumeCoin(int amount) 
    {
        if (coinAmount >= amount)
        {
            coinAmount -= amount;
            coinText.text = coinAmount.ToString();//更新金币数量
            return true;//消费成功
        }
        return false;//否则消费失败
    }

    //赚取金币
    public void EarnCoin(int amount) 
    {
        this.coinAmount += amount;
        coinText.text = coinAmount.ToString();//更新金币数量
    }
}

好了,一个较为完整的背包系统整理完毕。如果其中有错请与我及时联系改正,期待与你交流!若有需要源项目工程的,请留言!

评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值