基于Unity3D(UGUI)的背包系统<三>

这一篇,主要讲解UI逻辑处理方面,以及UI和该篇中的数据两者之间的使用。

首先补充一个上篇中缺少的一个配方类:这个类主要是用来保存锻造的所需的材料及锻造出来的结果。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

/// <summary>
/// 配方类:用来保存锻造的所需的材料及锻造出来的结果
/// </summary>
public class Formula{

    public int Item1ID { get; private  set; }//用来锻造的物品1的ID
    public int Item1Amount { get; private set; }//用来锻造的物品1的数量
    public int Item2ID { get; private set; }//用来锻造的物品2的ID
    public int Item2Amount { get; private set; }//用来锻造的物品2的数量

    public int ResID { get; set; }//保存锻造结果的ID

    private List<int> needIDList = new List<int>();//保存锻造所需要材料的ID(相当于锻造的配方)
    public List<int> NeedIDList { get { return needIDList; } }

    public Formula(int item1ID, int item1Amount, int item2ID, int item2Amount, int resID )
    {
        this.Item1ID = item1ID;
        this.Item1Amount = item1Amount;
        this.Item2ID = item2ID;
        this.Item2Amount = item2Amount;
        this.ResID = resID;

        //初始化配方ID
        for (int i = 0; i < Item1Amount; i++)
        {
            needIDList.Add(Item1ID);
        }
        for (int i = 0; i < Item2Amount; i++)
        {
            needIDList.Add(Item2ID);
        }
    }

    /// <summary>
    /// 匹配所提供的物品是否 包含 锻造所需要的物品(利用ID匹配)
    /// </summary>
    /// <returns></returns>
    public bool Match( List<int> idList ) 
    {
        List<int> tempIDList = new List<int>(idList);//临时保存函数参数数据(所拥有的物品ID),防止下面Remove代码移除时被修改
        foreach (int id in needIDList)
        {
            bool isSuccess = tempIDList.Remove(id);
            if (isSuccess == false)
            {
                return false;//拥有的物品和锻造所需的物品匹配失败
            }
        }
        return true;//物品匹配成功
    }

}

接着,重点部分就来了。正如第一部分图中那样。总的有5个面板:背包面板,箱子面板,角色面板,商店小贩面板,以及锻造面板。其中,每一个面板都有一个基类(Inventory类),因为这些面板中有一些相似的功能和方法,所以选择使用了继承。各自对应的代码如下:

①基类Inventory:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text;

/// <summary>
///存货类, 背包和箱子的基类
/// </summary>
public class Inventroy : MonoBehaviour {

    protected Slot[] slotArray;//存放物品槽的数组

    //控制背包的显示和隐藏相关变量
    private float targetAlpha = 1f;//显示目标值
    private float smothing = 4f;//渐变平滑速度
    private CanvasGroup canvasGroupMy;
    public CanvasGroup CanvasGroupMy      //对CanvasGroup的引用,用于制作隐藏显示效果
    {
        get
        {
            if (canvasGroupMy == null)
            {
                canvasGroupMy = GetComponent<CanvasGroup>();
            }
            return canvasGroupMy;
        }
    }

    // Use this for initialization
    public virtual void Start () {//声明为虚函数,方便子类重写
        slotArray = GetComponentsInChildren<Slot>();
         if (canvasGroupMy == null)
            {
                canvasGroupMy = GetComponent<CanvasGroup>();
            }
    }

    void Update() 
    {
        if (this.CanvasGroupMy.alpha != targetAlpha)
        {
            this.CanvasGroupMy.alpha = Mathf.Lerp(this.CanvasGroupMy.alpha, targetAlpha, smothing * Time.deltaTime);
            if (Mathf.Abs(this.CanvasGroupMy.alpha - targetAlpha)<.01f)
            {
                this.CanvasGroupMy.alpha = targetAlpha;
            }
        }
    }

    //根据Id存储物品
    public bool StoreItem(int id) 
    {
       Item item = InventroyManager.Instance.GetItemById(id);
       return StoreItem(item);
    }

    //根据Item存储物品(重点)
    public bool StoreItem(Item item) 
    {
        if (item.ID == 0)
        {
            Debug.LogWarning("要存储物品的ID不存在");
            return false;
        }

        if (item.Capacity == 1)//如果此物品只能放一个,那就找一个空的物品槽来存放即可
        {
           Slot slot = FindEmptySlot();
           if (slot == null)//如果空的物品槽没有了
           {
               Debug.LogWarning("没有空的物品槽可供使用");
               return false;//存储失败
           }
           else     //空的物品槽还有,那就把物品添加进去
           {
               slot.StoreItem(item);
           }
        }
        else//如果此物品能放多个
        {
            Slot slot = FindSameIDSlot(item);
            if (slot != null)//找到了符合条件的物品槽,那就把物品存起来
            {
                slot.StoreItem(item);
            }
            else //没有找到符合条件的物品槽,那就找一个没有存放物品的物品槽去存放物品
            {
                Slot emptySlot = FindEmptySlot();
                if (emptySlot != null)
                {
                    emptySlot.StoreItem(item);//空的物品槽去存放物品
                }
                else // 如果连空的物品槽,也就是没有存储物品的物品槽都找不到
                {
                    Debug.LogWarning("没有空的物品槽可供使用");
                    return false;//存储失败
                }
            }
        }
        return true; //存储成功
    }

    //寻找空的物品槽
    private Slot FindEmptySlot() 
    {
        foreach (Slot slot  in slotArray)
        {
            if (slot.transform.childCount == 0)//物品槽下面无子类,说明该物品槽为空,返回它即可
            {
                return slot;
            }
        }
        return null;
    }

    //查找存放的物品是相同的物品槽
    private Slot FindSameIDSlot(Item item)
    {
        foreach (Slot slot in slotArray)
        {
            //如果当前的物品槽已经有物品了,并且里面的物品的类型和需要找的类型一样,并且物品槽还没有被填满
            if (slot.transform.childCount >= 1 && item.ID == slot.GetItemID() && slot.isFiled() == false)
            {
                return slot;
            }
        }
        return null;
    }

    //面板的显示方法
    public void Show() 
    {
        this.CanvasGroupMy.blocksRaycasts = true;//面板显示时为可交互状态
        this.targetAlpha = 1;
    }
    //面板的隐藏方法
    public void Hide() 
    {
        this.CanvasGroupMy.blocksRaycasts = false;//面板隐藏后为不可交互状态
        this.targetAlpha = 0;
    }
    //控制面板的显示及隐藏关系
    public void DisplaySwitch() 
    {
        if (this.CanvasGroupMy.alpha == 0)
        {
            Show();
        }
        if (this.CanvasGroupMy.alpha == 1)
        {
            Hide();
        }
    }

    //控制物品信息的保存(ID,Amount数量)
    public void SaveInventory() 
    {
        StringBuilder sb = new StringBuilder();//用来保存物品信息的字符串
        foreach (Slot slot in slotArray)
        {
            if (slot.transform.childCount > 0 )
            {
                ItemUI  itemUI = slot.transform.GetChild(0).GetComponent<ItemUI>();
                sb.Append(itemUI.Item.ID + "," + itemUI.Amount + "-");//用逗号分隔一个物品中的ID和数量,用 - 分隔多个物品
            }
            else
            {
                sb.Append("0-");//如果物品槽里没有物品就是0
            }
        }
        PlayerPrefs.SetString(this.gameObject.name, sb.ToString());//保存字符串数据
    }

    //控制物品信息的加载(根据ID,Amount数量)
    public void LoadInventory() 
    {
        if (PlayerPrefs.HasKey(this.gameObject.name) == false) return;//判断保存的这个关键码Key是否存在,不存在就不做处理
        string str = PlayerPrefs.GetString(this.gameObject.name);//获取上面保存的字符串数据
        string[] itemArray = str.Split('-');//按照  -  分隔多个物品
        for (int i = 0; i < itemArray.Length-1; i++)//长度减1是因为最后一个字符是 “-”,不需要取它
        {
            string itemStr = itemArray[i];
            if (itemStr != "0")
            {
                string[] temp = itemStr.Split(',');//按照逗号分隔这个物品的信息(ID和Amoun数量)
                int id = int.Parse(temp[0]);
                Item item = InventroyManager.Instance.GetItemById(id);//通过物品ID得到该物品
                int amount = int.Parse(temp[1]);
                for (int j = 0; j < amount; j++)//执行Amount次StoreItem方法,一个一个的存
                {
                    slotArray[i].StoreItem(item);
                }
            }
        }
    }
}

②背包面板:
using UnityEngine;
using System.Collections;
///
/// 背包类,继承自 存货类Inventroy
///
public class Knapscak : Inventroy {
//单例模式
private static Knapscak _instance;
public static Knapscak Instance {
get {
if (_instance == null)
{
_instance = GameObject.Find(“KnapscakPanel”).GetComponent();
}
return _instance;
}
}
}

③箱子面板

using UnityEngine;
using System.Collections;
/// <summary>
/// 箱子类,继承自 存货类Inventroy
/// </summary>
public class Chest : Inventroy {
    //单例模式
    private static Chest _instance;
    public static Chest Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = GameObject.Find("ChestPanel").GetComponent<Chest>();
            }
            return _instance;
        }
    }
}

④角色面板

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

/// <summary>
/// 角色面板类,控制角色面板的逻辑
/// </summary>
public class CharacterPanel : Inventroy
{
    //单例模式
    private static CharacterPanel _instance;
    public static CharacterPanel Instance 
    {
        get 
        {
            if (_instance == null)
            {
                _instance = GameObject.Find("CharacterPanel").GetComponent<CharacterPanel>();
            }
            return _instance;
        }
    }

    private Text characterPropertyText;//对角色属性面板中Text组件的引用
    private Player player;//对角色脚本的引用

    public override void Start()
    {
        base.Start();
        characterPropertyText = transform.Find("CharacterPropertyPanel/Text").GetComponent<Text>();
        player = GameObject.FindWithTag("Player").GetComponent<Player>();
        UpdatePropertyText();//初始化显示角色属性值
    }

    //更新角色属性显示
    private void UpdatePropertyText() 
    {
        int strength = 0, intellect = 0, agility = 0, stamina = 0, damage = 0;
        foreach (EquipmentSlot slot in slotArray)//遍历角色面板中的装备物品槽
        {
            if (slot.transform.childCount > 0)//找到有物品的物品槽,获取里面装备的属性值
            {
                Item item = slot.transform.GetChild(0).GetComponent<ItemUI>().Item;
                if (item is Equipment)//如果物品是装备,那就加角色对应的属性
                {
                    Equipment e = (Equipment)item;
                    strength += e.Strength;
                    intellect += e.Intellect;
                    agility += e.Agility;
                    stamina += e.Stamina;
                }
                else if (item is Weapon)///如果物品是武器,那就加角色的伤害(damage)属性
                {
                    Weapon w = (Weapon)item;
                    damage += w.Damage;
                }
            }
        }
        strength += player.BasicStrength;
        intellect += player.BasicIntellect;
        agility += player.BasicAgility;
        stamina += player.BasicStamina;
        damage += player.BasicDamage;
        string text = string.Format("力量:{0}\n智力:{1}\n敏捷:{2}\n体力:{3}\n攻击力:{4}\n", strength, intellect, agility, stamina, damage);
        characterPropertyText.text = text;
    }

    //直接穿戴功能(不需拖拽)
    public void PutOn(Item item) 
    {
        Item exitItem = null;//临时保存需要交换的物品
        foreach (Slot slot in slotArray)//遍历角色面板中的物品槽,查找合适的的物品槽
        {
            EquipmentSlot equipmentSlot = (EquipmentSlot)slot;
            if (equipmentSlot.IsRightItem(item)) //判断物品是否合适放置在该物品槽里
            {
                if (equipmentSlot.transform.childCount > 0)//判断角色面板中的物品槽合适的位置是否已经有了装备
                {
                    ItemUI currentItemUI = equipmentSlot.transform.GetChild(0).GetComponent<ItemUI>();
                    exitItem = currentItemUI.Item;
                    currentItemUI.SetItem(item, 1);
                }
                else
                {
                    equipmentSlot.StoreItem(item);
                }
                break;
            }
        }
        if (exitItem != null)
        {
            Knapscak.Instance.StoreItem(exitItem);//把角色面板上是物品替换到背包里面
        }
        UpdatePropertyText();//更新显示角色属性值
    }

    //脱掉装备功能(不需拖拽)
    public void PutOff(Item item) 
    {
        Knapscak.Instance.StoreItem(item);//把角色面板上是物品替换到背包里面
        UpdatePropertyText();//更新显示角色属性值
    }
}

⑤商店小贩面板

using UnityEngine;
using System.Collections;

public class Vendor : Inventroy {

    //单例模式
    private static Vendor _instance;
    public static Vendor Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = GameObject.Find("VendorPanel").GetComponent<Vendor>();
            }
            return _instance;
        }
    }

    public int[] itemIdArray;//一个物品ID的数组,用于给商贩初始化
    private Player player;//对主角Player脚本的引用,用于购买物品功能

    public override void Start()
    {
        base.Start();
        InitShop();
        player = GameObject.FindWithTag("Player").GetComponent<Player>();
        Hide();
    }

    //初始化商贩
    private void InitShop() 
    {
        foreach (int itemId in itemIdArray)
        {
            StoreItem(itemId);
        }
    }

    //主角购买物品
    public void BuyItem(Item item) 
    {
        bool isSusscess = player.ConsumeCoin(item.BuyPrice);//主角消耗金币购买物品
        if (isSusscess)
        {
            Knapscak.Instance.StoreItem(item);
        }
    }

    //主角售卖物品
    public void SellItem() 
    {
        int sellAmount = 1;//销售数量
        if (Input.GetKey(KeyCode.LeftControl))//按住坐标Ctrl键物品一个一个的售卖,否则全部售卖
        {
            sellAmount = 1;
        }
        else
        {
            sellAmount = InventroyManager.Instance.PickedItem.Amount;
        }
        int coinAmount = InventroyManager.Instance.PickedItem.Item.SellPrice * sellAmount;//售卖所获得的金币总数
        player.EarnCoin(coinAmount);//主角赚取到售卖物品的金币
        InventroyManager.Instance.ReduceAmountItem(sellAmount);//鼠标上的物品减少或者销毁
    }
}

⑥锻造面板

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

/// <summary>
/// 锻造类:实现材料锻造成装备或者武器
/// </summary>
public class Forge : Inventroy {

    //单例模式
    private static Forge _instance;
    public static Forge Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = GameObject.Find("ForgePanel").GetComponent<Forge>();
            }
            return _instance;
        }
    }

    private List<Formula> formulaList = null;//用来存放解析出来的材料

    public override void Start()
    {
        base.Start();
        ParseFormulaJSON();
        Hide();
    }

    //解析武器锻造配方Jso文件
    public void ParseFormulaJSON()
    {
        formulaList = new List<Formula>();
        TextAsset formulaText = Resources.Load<TextAsset>("Formulas");
        string formulaJson = formulaText.text;
        JSONObject jo = new JSONObject(formulaJson);
        foreach (JSONObject temp in jo.list)
        {
            int item1ID = (int)temp["Item1ID"].n;
            int item1Amount = (int)temp["Item1Amount"].n;
            int item2ID = (int)temp["Item2ID"].n;
            int item2Amount = (int)temp["Item2Amount"].n;
            int resID = (int)temp["ResID"].n;
            Formula formula = new Formula(item1ID, item1Amount, item2ID, item2Amount, resID);
            formulaList.Add(formula);
        }
        //Debug.Log(formulaList[1].ResID);
    }

    /// <summary>
    /// 锻造物品功能:重点
    /// </summary>
    public void ForgeItem() 
    {
        //得到当前锻造面板里面有哪些材料
        List<int> haveMaterialIDList = new List<int>();//存储当前锻造面板里面拥有的材料的ID
        foreach (Slot  slot in slotArray)
        {
            if (slot.transform.childCount > 0)
            {
                ItemUI currentItemUI = slot.transform.GetChild(0).GetComponent<ItemUI>();
                for (int i = 0; i < currentItemUI.Amount; i++)
                {
                    haveMaterialIDList.Add(currentItemUI.Item.ID);//物品槽里有多少个物品,就存储多少个ID
                }
            }
        }
        //Debug.Log(haveMaterialIDList[0].ToString());
        //判断满足哪一个锻造配方的需求
        Formula matchedFormula = null;
        foreach (Formula formula in formulaList)
        {
            bool isMatch = formula.Match(haveMaterialIDList);
            //Debug.Log(isMatch);
            if (isMatch)
            {     
                matchedFormula = formula;
                break;
            }
        }
       // Debug.Log(matchedFormula.ResID);
        if (matchedFormula != null)
        {

            Knapscak.Instance.StoreItem(matchedFormula.ResID);//把锻造出来的物品放入背包
            //减掉消耗的材料
            foreach (int id in matchedFormula.NeedIDList)
            {
                foreach (Slot slot in slotArray)
                {
                    if (slot.transform.childCount > 0)
                    {
                        ItemUI itemUI = slot.transform.GetChild(0).GetComponent<ItemUI>();
                        if (itemUI.Item.ID == id && itemUI.Amount > 0)
                        {
                            itemUI.RemoveItemAmount();
                            if (itemUI.Amount <= 0)
                            {
                                DestroyImmediate(itemUI.gameObject);
                            }
                            break;
                        }
                    }
                }
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Say__Yes/article/details/72905102