背包系统(4) 详细笔记

51.合成/锻造系统
在装备界面复制一个背包系统出来.
在界面删除其他的Slot 留下2个Slot作为放入锻造的材料格子.
删除原来的脚本,添加新脚本ForgePannel.
增加一个button组件.

52.编辑Json.
将编写好的Json放在Resources下面.

新建一个配方Formula脚本.这个脚本只存放配方,他不是一个组件,不用继承自MonoBehavior.
public class Formula  {
    //放在锻造第一个格子的ID和数量
     int Item1ID { get set ; }
     int Item1Amount { get ; set ; }
    //放在锻造第二个格子的ID和数量
     int Item2ID { get ; set ; }
     int Item2Amount { get ; set ; }
     int ResID { get ; set ; } //锻造结果的物品
    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;
    }
}
53.解析Json.
    public override void Start ()
    {
        base .Start();
        ParseFormulaJson();
    }
    void ParseFormulaJson()
    {
        formulaArray = new List(); //这里要先声明以个新的List,等下用来存放解析出来的物品.
        TextAsset text = Resources.Load( "Formulas" );
        string jsonText = text.text;
        JSONObject jo = new JSONObject(jsonText);
        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 f = new Formula(item1ID, item1Amount, item2ID, item2Amount, resID);
            formulaArray.Add(f);
        }
    }
54.锻造系统的核心算法.
<1>得到锻造槽内所有的物品.(包括物品的ID和Amount).
        存储方式为:叠加ID的数量.
<2>在秘籍类(Formula)中得到秘籍的所需的物品ID和Amount.存储方式也是叠加ID的数量.
<3>匹配锻造槽和秘籍中的ID和是否一致.(可能有多个重复的ID)
<4>如果匹配成功,合成装备.并减少锻造槽内对应数量的ID.

首先在Button下添加触发事件.

在点击button的时候触发Forge里面的ForgePannel脚本的ForgeItem功能.
ForgePannel脚本:
    public void ForgeItem() //得到当前拥有的物体
    {
        List< int > haveItemIDList = new List< int >(); //要把现在拥有的物体都放在这个List中.
        /// 通过遍历Solt来得到里面所有的物体  如果有多个物体,那么在List中存储多次ID
        /// 在这里一个ID就代表一个物体,相当于钱包中的100快,我们有几百块就在钱包里有几张100,而不是只有1张100
        foreach (Slot slot in slotList) //其实这里只会得到锻造槽内的物品...
        {
            if (slot.transform.childCount>0)
            {
                ItemUI itemUI = slot.transform.GetChild(0).GetComponent();
                /// 这里得到了当前格子里面的物体.
                /// 这个格子有多少个物体就要,存储这个ID多少次
                for ( int i = 0; i < itemUI.Amount; i++)
                {
                    haveItemIDList.Add(itemUI.Item.ID);
                }
            }
        } //经行完这个循环之后haveItemIDList里面存储的就是所有拥有的物品ID
        foreach (Formula formula in formulaArray) //遍历秘籍,看每一本秘籍是否符合
        {
            bool isSucceed=formula.Match(haveItemIDList);
            if (isSucceed)
            {
                Knapsack.Instance.StoreItem(formula.ResID); //把锻造出来的物品ID传进去.单是怎么样得到formula对应的ResID呢.
            }
        }
    }
Formula中:
public class Formula   {
    //放在锻造第一个格子的ID和数量
   public   int Item1ID { get set ; }
    public int Item1Amount { get ; set ; }
    //放在锻造第二个格子的ID和数量
    public int Item2ID { get ; set ; }
    public int Item2Amount { get ; set ; }
    public int ResID { get ; set ; } //锻造结果的物品
    private List< int > needItem = new List< int >(); //锻造物品需要的Item
    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;
        for ( int i = 0; i < Item1Amount; i++)
        {
            needItem.Add(Item1ID);
        }
        for ( int i = 0; i < Item2Amount; i++)
        {
            needItem.Add(Item2ID);
        }
    }
    public bool Match(List< int > idList) //匹配传递过来的值和秘籍里面的值是否一致.
    {
        List< int > tempList = idList; //设置一个临时的List和传递过来的一样.因为等下要remove掉里面的ID.
        foreach ( int i in needItem)
        {
            bool isSucceed = tempList.Remove(i); //这个Remove方法有返回bool值.表示是否成功移除.
            if (isSucceed== false )
            {
                return false ;
            }
        }
        return true ; //如果返回true,表示这个需求的ID在背包中都有,表示可以合成.
    }
}
此时就能用锻造槽锻造出物品了.
55.接下来要把锻造槽内的消耗的物品减少.
删减锻造槽里物品需要注意的点:
得到锻造秘籍的List,遍历这个list.
如果当前的锻造槽里面的ItemUI.Item.ID=这个秘籍里面的id
那么调用Reduce();让它的数量减一.
数量小于等于0时,销毁该物体.
    public void ForgeItem() //得到当前拥有的物体
    {
        List< int > haveItemIDList = new List< int >(); //要把现在拥有的物体都放在这个List中.
        /// 通过遍历Solt来得到里面所有的物体  如果有多个物体,那么在List中存储多次ID
        /// 在这里一个ID就代表一个物体,相当于钱包中的100快,我们有几百块就在钱包里有几张100,而不是只有1张100
        foreach (Slot slot in slotList) //其实这里只会得到锻造槽内的物品...
        {
            if (slot.transform.childCount > 0)
            {
                ItemUI itemUI = slot.transform.GetChild(0).GetComponent();
                /// 这里得到了当前格子里面的物体.
                /// 这个格子有多少个物体就要,存储这个ID多少次
                for ( int i = 0; i < itemUI.Amount; i++)
                {
                    haveItemIDList.Add(itemUI.Item.ID);
                }
            }
        } //经行完这个循环之后haveItemIDList里面存储的就是所有拥有的物品ID
        //我们想知道它用的那本秘籍进行的锻造,我们可以先定义一个空的秘籍,然后在锻造的时候给他赋值.
        Formula matchedFormula = null ;
        foreach (Formula formula in formulaArray) //遍历秘籍,看每一本秘籍是否符合
        {
            bool isSucceed = formula.Match(haveItemIDList);
            if (isSucceed)
            {
                //这里说明锻造成功.
                matchedFormula = formula; //现在matchedFormula就是我们使用的秘籍.
                break ;
            }
        }
        if (matchedFormula != null )
        {
            Knapsack.Instance.StoreItem(matchedFormula.ResID); //在背包中存储锻造出来的东西
            foreach ( int i in matchedFormula.NeedItem) //遍历秘籍里面的ID
            {
                foreach (Slot slot in slotList) //遍历锻造槽
                {
                    if (slot.transform.childCount> 0) //如果锻造槽里面有子物体
                    {
                        ItemUI itemUI = slot .transform.GetChild(0).GetComponent();
                        //上面这句代码是要得到当前的格子下的ItemUI.所以一定要记得加上slot.transform
                        if (itemUI.Item.ID == i) //如果子物体的ID和当前存储的ITem.ID一样
                        {
                            itemUI.ReduceAmount(); //减少当前的一个数量
                            if (ite mUI.Amount <= 0) //如果ItemUI=0的话,
                            {
                                DestroyImmediate(itemUI.gameObject); //立即销毁当前物体.
                            }
                            break ;
                        }
                    }                    
                }
            }
        }
    }
56.接下来,数据的保存于加载.
保存的中心思想:
因为所有的物品都保存在Inventory中.所以这个加载保存功能就做在Inventory中.
让所有的数据都保存成字符串形式.每一个物品槽都用符号分割.物品槽内的物品也用不同的符号分割.
加载的中心思想:
用刚才保存的数据进行拆分.拆分成不同的数组.
然后再保存这个数组里面的ID.保存的次数就是他后面的哪个数.
    #region 保存和加载
    public void SaveInventory() //保存物品的代码
    {
        StringBuilder sb = new StringBuilder();
        foreach (Slot slot in slotList) //遍历每一个格子
        {
            if (slot.transform.childCount > 0) //如果这个格子不是空的
            {
                ItemUI itemUI = slot.transform.GetChild(0).GetComponent(); //得到当前格子下的ItemUI
                sb.Append(itemUI.Item.ID + "," + itemUI.Amount + "-" ); //存储他的Item.ID和Amount用","分开.和不同的格子用"-"分开
            }
            else //如果格子是空的.
            {
                sb.Append( "0-" ); //如果格子是空的,那么就要在这个数组中保存 "0-"
            }
        }
        //保存物品的核心代码.这个字符串将保存在本机.
        PlayerPrefs.SetString( this .gameObject.name, sb.ToString());
    }
    public void LoadInventory() //加载物品的代码
    {
        if (PlayerPrefs.HasKey( this .gameObject.name) == false ) return ; //查找有没有这个名字,如果没有的话,直接返回.
        string str = PlayerPrefs.GetString( this .gameObject.name); //得到这个存储的字符串.
        string [] itemArray = str.Split( '-' ); //得到用'-'分开的数组.这个数组就是每一个格子的存储的ID和Amount
        //这里注意!!!!!!!遍历的这个数组的长度不是Length.而是Length-1,因为我们上面得到的数组时,
        //最有一个是0- 那么用Split('-')拆分的话,我们得到的最后一个字符串就是空字符.但是我们并没有格子能对应这个空字符.
        //所以不遍历最后一个
        for ( int i=0;i //遍历这个数组.
        {
            string itemStr = itemArray[i];
            if (itemStr != "0" ) //如果不是0,也就是说这个格子里面有物体,那么保存这个物体
            {
                string [] temp = itemStr.Split( ',' ); //得到的这个数组就是上面我们保存的ID个Amount
                int id = int .Parse(temp[0]); //解析这个字符串,获取ID
                int amount = int .Parse(temp[1]); //解析这个字符串,获取Amount
                Item item=InventoryManager.Instance.GetItemById(id); //通过这个ID得到Item
                for ( int j = 0; j < amount; j++) //将这个物品保存Amount次
                slotList[i].StoreItem(item); //保存这个物品到对应的格子里面.
                    //这里如果直接保存的话就会把所有物体重新排列,但是如果用slot[i]就会保存在原来的格子里面
                }
            }
        }
    #endregion

57.测试保存和 加载功能.
要在这个面板中管理所有的存储相关功能.包括:
所以这个存储的功能放在InventoryManager中.
这几个脚本中都要增加单例模式.
在面板中添加保存和加载这2个选项.
在InventoryManager中添加方法:
    public void SaveButton() //点击保存按钮
    {
        Knapsack.Instance.SaveInventory();
        CharacterPannel.Instance.SaveInventory();
        ForgePannel.Instance.SaveInventory();
    }
    public void LoadButton() //点击加载按钮
    {
        Knapsack.Instance.LoadInventory();
        CharacterPannel.Instance.LoadInventory();
        ForgePannel.Instance.LoadInventory();
    }

把这个方法添加进去.Load也是一样.
58.修改金币的保存.
在Player中得到金币,并且可以修改金币.
    public int CoinAmount
    {
        get
        {
            return coinAmount;
        }
        set
        {
            coinAmount= value;
            text.text = coinAmount.ToString(); //因为金币数量有变化,别忘当前金币显示
        }
    }
在InventoryManager中:
    public void SaveButton() //点击保存按钮
    {
        Knapsack.Instance.SaveInventory();
        CharacterPannel.Instance.SaveInventory();
       Vendor.Instance.SsaveInventory();
        ForgePannel.Instance.SaveInventory();
        PlayerPrefs.SetInt( "CoinAmount" , GameObject.FindGameObjectWithTag( "Player" ).GetComponent().CoinAmount);
    }
    public void LoadButton() //点击加载按钮
    {
        Knapsack.Instance.LoadInventory();
        CharacterPannel.Instance.LoadInventory();
        Vendor.Instance.LoadInventory();
        ForgePannel.Instance.LoadInventory();
        if (PlayerPrefs.HasKey( "CoinAmount" )!= false )
        {
            GameObject.FindGameObjectWithTag( "Player" ).GetComponent().CoinAmount=PlayerPrefs.GetInt( "CoinAmount" );
        }
    }
59.不能用空格得到物品,因为空格相当于是左键.
改回用G得到物品.
60.打包.放在当前目录下.
把当前场景放在打包工程里面.


End.撒花~

你可能感兴趣的:(背包系统(4) 详细笔记)