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.撒花~