第八章 装备系统
装备系统是提升角色属性的重要系统,本篇博客重点实现装备系统UI的设计以及装备栏与物品栏的交互。
8.1 基础界面的设计
导入装备UI的模型,命名为Equipment,并添加5个方框,用以放置装备,如下图
![](https://i-blog.csdnimg.cn/blog_migrate/4b6a26b8de34abd18373904f092e33c8.png)
当点击功能面板的装备按钮时,显示动画(方法见
https://blog.csdn.net/s1314_JHC/article/details/79690742 下的5.5节),不赘述。
我们在每个格子中再创建一个Child Sprite,当实例化时直接给这个Child Sprite添加装备图标即可。拖放到Prefab之中,方便之后使用
![](https://i-blog.csdnimg.cn/blog_migrate/e194b8ff31bc344d57ff592fab204727.png)
在Equipment脚本中管理这6个格子
private GameObject headgear; //创建GameObject并赋值
void Awake()
{
headgear = transform.Find ("Headgear").gameObject;
armor = transform.Find ("Armor").gameObject;
left_hand = transform.Find ("Left_hand").gameObject;
right_hand = transform.Find ("Right_hand").gameObject;
shoe = transform.Find ("Shoe").gameObject;
accessory = transform.Find ("Accessory").gameObject;
}
8.2 装备信息的添加与管理
这节我们实现装备信息的添加以及模拟拾取功能,与药品信息类似,我们创建装备信息的格式如下。
![](https://i-blog.csdnimg.cn/blog_migrate/b553912bd23b6ac46d0fde9b1db0b7a1.png)
内容依旧添加在之前的文档ObjectsInfoInList之中,创建示例如下所示。
2001,simpleHeltForMagician,icon-helm-03,Equip,0,10,0,Headgear,Magician,60,150
2002,fineHeltForMagician,icon-helm-02,Equip,0,20,0,Headgear,Magician,80,200
2003,brokenArmorForMagician,armor3-icon,Equip,0,30,0,Armor,Magician,60,150
2004,fineArmorForMagician,armor2-icon,Equip,0,50,0,Armor,Magician,80,200
2005,brokenShield,icon-shield,Equip,0,30,0,Left_hand,Common,80,200
2006,fineShield,icon-shield1,Equip,0,50,0,Left_hand,Common,100,250
2007,brokenRod,rod-icon,Equip,30,0,0,Right_hand,Magician,60,150
2008,fineRod,rod-icon02,Equip,30,0,0,Right_hand,Magician,80,200
2009,brokenShoe,icon-boot0,Equip,0,0,30,Shoe,Common,60,150
2010,fineShoe,icon-boot0-01,Equip,0,0,50,Shoe,Common,80,200
2011,brokenRing,icon-ring-01,Equip,0,30,0,Accessory,Common,60,150
2012,fineRing,icon-ring,Equip,0,50,0,Accessory,Common,80,200
在ObjectsInfo之中,我们在public class ObjectInfo添加几个适用于装备的成员变量
public class ObjectInfo{
public int attack; //攻击
public int defense; //防御
public int speed; //速度
public ApplicationType appType; //武器适用角色
public DressType dressType; //穿戴部位
}
其中ApplicationType和DressType单独定义为枚举类型,即
public enum ApplicationType{
Swordman,
Magician,
Common
}
public enum DressType{
Headgear,
Armor,
Left_hand,
Right_hand,
Shoe,
Accessory
}
在从ObjectsInfoInList.txt文档中读取数据到字典objectInfoDict的时候,之前在药品信息系统中所采用的判断语句if(type == ObjectType.Drug),对其进行修改,即可添加装备信息
else if(type == ObjectType.Equip)
{
info.attack = int.Parse(proArray[4]);
info.defense = int.Parse(proArray[5]);
info.speed = int.Parse(proArray[6]);
info.price_sell = int.Parse(proArray[9]);
info.price_buy = int.Parse(proArray[10]);
string str_dressType = int.Parse(proArray[7]);
switch(str_dressType)
{
case "Headgear":
info.dressType = DressType.Headgear;
break;
case "Armor":
info.dressType = DressType.Armor;
break;
case "Left_hand":
info.dressType = DressType.Left_hand;
break;
case "Right_hand":
info.dressType = DressType.Right_hand;
break;
case "Shoe":
info.dressType = DressType.Shoe;
break;
case "Accessory":
info.dressType = DressType.Accessory;
break;
}
string str_appType = int.Parse(proArray[8]);
switch(str_appType)
{
case "Swordman":
info.appType = ApplicationType.Swordman;
break;
case "Magician":
info.appType = ApplicationType.Magician;
break;
case "Common":
info.appType = ApplicationType.Common;
break;
}
}
即可,添加完后应当可以在物品栏中通过“X”键的拾取模拟来添加装备
(参考
https://blog.csdn.net/s1314_JHC/article/details/79690742 5.4节,只需修改随机数的范围即可),判断是否添加成功,如下左图所示
![](https://i-blog.csdnimg.cn/blog_migrate/236e5bcab306dd280f0852bc038c6ea1.png)
8.3 装备信息提示的更新
模拟添加成功后,将鼠标移到装备上方,此时的物品显示存在问题(上右图),需要进行修改
修改处在InventoryDes的Show()方法下,在之前的判断中,用的是switch (info.type) 的case:Drug来控制药品信息栏的显示,针对装备,我们增加case ObjectsInfo.ObjectType.Equip: 以控制装备的显示,即
switch (info.type) {
case ObjectsInfo.ObjectType.Drug:
des = GetDrugDes(info);
break;
case ObjectsInfo.ObjectType.Equip:
des = GetEquipDes(info);
break;
}
string GetEquipDes(ObjectsInfo.ObjectInfo info)
{
string str = "";
str += "名称:" + info.name + "\n";
switch (info.dressType)
{
case ObjectsInfo.DressType.Headgear:
str += "类型:头盔" +"\n";
break;
case ObjectsInfo.DressType.Armor:
str += "类型:护甲" +"\n";
break;
case ObjectsInfo.DressType.Left_hand:
str += "类型:左手" +"\n";
break;
case ObjectsInfo.DressType.Right_hand:
str += "类型:右手" +"\n";
break;
case ObjectsInfo.DressType.Shoe:
str += "类型:鞋" +"\n";
break;
case ObjectsInfo.DressType.Accessory:
str += "类型:饰品" +"\n";
break;
}
switch (info.appType)
{
case ObjectsInfo.ApplicationType.Swordman:
str += "适用角色:剑士"+"\n";
break;
case ObjectsInfo.ApplicationType.Magician:
str += "适用角色:魔法师"+"\n";
break;
case ObjectsInfo.ApplicationType.Common;
str += "适用角色:通用"+"\n";
break;
}
str += "增加速度:" + info.attack + "\n";
str += "增加防御:" + info.defense +"\n";
str += "增加速度:" + info.speed +"\n";
str += "出售价:" + info.price_sell + "\n";
str += "购买价:" +info.price_buy + "\n";
return str;
}
即可实现,如下图
![](https://i-blog.csdnimg.cn/blog_migrate/9646475ea2e044ebf448c474a870ff19.png)
8.4 实现穿戴功能
接下来实现点击鼠标右键进行穿戴的功能,需要与装备栏进行交互。在InventoryInsideItem之中,当isHover为true时,即鼠标位于物体之上,我们实现穿戴功能。
在Magician下的PlayerStatus脚本中加入一个角色种类,分为魔法师和剑士,并在函数内赋值
public enum playerRole{
Swordman,
Magician
}
public class PlayerStatus : MonoBehaviour {
public playerRole role = playerRole.Magician;
}
上述代码在穿戴的角色判断时需要用到,不同的角色所穿戴的部分装备是有限制的,我们在装备界面Equipment脚本中实现穿戴DressEquip()功能
8.4.1 无法穿戴的情形
针对当前的角色魔法师,我们首先考虑三种情况是无法穿戴的:
- 当前物品不是装备
- 当前角色不是魔法师
- 当前角色虽然是魔法师,但穿戴类型为剑士
public bool DressEquip(int id)
{
ObjectsInfo.ObjectInfo info = ObjectsInfo._instance.GetObjectInfoFromDict (id);
if (info.type != ObjectsInfo.ObjectType.Equip) //情况1
{
return false;
}
if (ps.role == playerRole.Swordman) //情况2
{
return false;
}
if (ps.role == playerRole.Magician) //情况3
{
if(info.appType == ObjectsInfo.ApplicationType.Swordman)
{
return false;
}
}
}
8.4.2 根据穿戴类型及部位更新显示
之后考虑可以穿戴的情况,首先判断DressEquip(int id)当前id对应物品的穿戴类型,并用一个名为parentOfEquipItem的GameObject存储,之后根据parentOfEquipItem的GameObject访问它的子类以实现装备的更新。
GameObject parentOfEquipItem = null;
switch (info.dressType) {
case ObjectsInfo.DressType.Headgear:
parentOfEquipItem = headgear;
break;
case ObjectsInfo.DressType.Armor:
parentOfEquipItem = armor;
break;
case ObjectsInfo.DressType.Left_hand:
parentOfEquipItem = left_hand;
break;
case ObjectsInfo.DressType.Right_hand:
parentOfEquipItem = right_hand;
break;
case ObjectsInfo.DressType.Shoe:
parentOfEquipItem = shoe;
break;
case ObjectsInfo.DressType.Accessory:
parentOfEquipItem = accessory;
break;
之后在Equipment之中创建一个public GameObject equipmentItem;作为parentOfEquipItem的子类,通过equipmentItem更改显示的装备
![](https://i-blog.csdnimg.cn/blog_migrate/6796f9651618439264f0ddd1af994ea0.png)
在之前存为Prefabs的EquipmentItem中新建一个脚本,命名为EquipmentItem,控制装备栏里物品的脱下与更新操作
private UISprite sprite; //控制装备的外观显示
private int id; //得到当前装备的id
void Awake()
{
sprite = this.GetComponent<UISprite> ();
}
public void SetId(int id) //通过id得到装备的info信息
{
this.id = id;
ObjectsInfo.ObjectInfo info = ObjectsInfo._instance.GetObjectInfoFromDict (id);
SetInfo (info);
}
public void SetInfo(ObjectsInfo.ObjectInfo info) //直接得到装备的info信息
{
this.id = info.id;
sprite.spriteName = info.icon_name;
}
有了这些功能,我们直接在Equipment中设置物品的显示
EquipmentItem item = parentOfEquipItem.GetComponentsInChildren<EquipmentItem> (); 实例化一个item,控制物品显示
if (item != null) //如果parentOfEquipItem的子类EquipmentItem不为空,即该位置已穿戴装备
{
item.SetInfo(info); //调用SetInfo(info)函数更新Sprite的显示
} else //未穿戴装备
{
GameObject itemGO = NGUITools.AddChild(parentOfEquipItem,equipmentItem); //新建一个parentOfEquipItem的子类equipmentItem,显示装备
itemGO.transform.localPosition = Vector3.zero;
itemGO.GetComponent<EquipmentItem>().SetInfo(info);
}
8.4.3右键点击穿戴,更新装备栏
在InventoryInsideItem中,当点击右键时,实现更新装备显示和物品栏信息更新的效果,在Update()中实现
void Update()
{
if (isHover)
{
InventoryDes._instance.Show (id);
if(Input.GetMouseButtonDown(1)) //点击右键
{
bool successDress = Equipment._instance.DressEquip(id); 判断是否成功穿戴
if(successDress)
{
transform.parent.GetComponent<InventoryItemGrid>().MinusNumber(); //若成功穿戴,更新显示信息
}
}
}
}
其中,Equipment脚本中的DressEquip()函数如下,除去之前三种无法穿戴的情况,当符合穿戴要求时
EquipmentItem item = parentOfEquipItem.GetComponentInChildren<EquipmentItem> (); //实例化item,用以判断当前装备部位是否有装备
if (item != null) //非空,表示已有装备
{
Inventory._instance.GetId(item.id); //将当前装备脱下
item.SetInfo(info); //显示鼠标右键穿上的装备
} else //没穿装备的情况
{
GameObject itemGO = NGUITools.AddChild(parentOfEquipItem,equipmentItem); //新建Equipment的子类equipmentItem,实例化为itemGO
itemGO.transform.localPosition = Vector3.zero;
itemGO.GetComponentInChildren<EquipmentItem>().SetInfo(info); //新建信息
}
当装备成功穿戴后,我们还需要对物品栏信息进行更新
通过InventoryItemGrid脚本中的MinusNumber()函数实现,并在上述代码的 if(successDress)中调用。
public void MinusNumber(int number = 1)
{
if (this.num >= num) //当前网格数量大于0
{
this.num -= number; //数量减1
numberLabel.text = this.num.ToString (); //更新显示
}
if (this.num == 0) //若当前网格数量为0
{
GameObject.Destroy(this.GetComponentInChildren<InventoryInsideItem>().gameObject); //销毁并清空该网格数据
ClearInfo();
}
}
完成后显示效果如下图
![](https://i-blog.csdnimg.cn/blog_migrate/1842e721b262f3b35ac64ce3a2c427e0.png)
8.4.4 装备卸下功能
将Prefabs下的EquipmentItem拖回UI root下,为其添加box collider,并设置
box collider的大小为50x50,即与显示框大小一致。
在EquipmentItem脚本中添加如下代码
private bool isHover = false;
void OnHover(bool isOver) //OnHover事件,当鼠标放在物体上方时,isOver为true,离开物体,isOver为false
{
isHover = isOver;
}
void Update()
{
if (isHover) //放在装备栏的装备上方
{
if(Input.GetMouseButtonDown(1)) //且按下鼠标右键
{
Inventory._instance.GetId(id); //将该装备添加到物品栏中,之后销毁
GameObject.Destroy(this.gameObject);
}
}
}
8.5 实现装备穿戴对属性的影响
在Equipment之中定义三个变量,并控制属性的变化。
private int attack = 0;
private int defense = 0;
private int speed = 0;
void UpdateProperty()
{
this.attack = 0; //每次更新的时候先赋值为0
this.defense = 0;
this.speed = 0;
EquipmentItem headgearItem = headgear.GetComponentInChildren<EquipmentItem> (); //以头盔部分为例,实例化EquipmentItem>的headgearItem
if (headgearItem != null) //如果装备栏中已经有
{
ObjectsInfo.ObjectInfo equipInfo = ObjectsInfo._instance.GetObjectInfoFromDict(headgearItem.id); //通过id得到当前物品的信息equipInfo
this.attack += equipInfo.attack; //将属性添加到三个定义的变量中
this.defense += equipInfo.defense;
this.speed += equipInfo.speed;
}
}
其余的5个装备的操作类似,因此可以抽象出一个方法PlusProperty(),控制属性的增加
void PlusProperty(EquipmentItem item)
{
if (item != null)
{
ObjectsInfo.ObjectInfo equipInfo = ObjectsInfo._instance.GetObjectInfoFromDict(item.id);
this.attack += equipInfo.attack;
this.defense += equipInfo.defense;
this.speed += equipInfo.speed;
}
}
至此就可以简化为
EquipmentItem headgearItem = headgear.GetComponentInChildren<EquipmentItem> ();
PlusProperty (headgearItem);
当装备穿上或者装备卸下的时候,需要调用UpdateProperty()方法,穿上对应InventoryInsideItem中的DressEquip()方法,卸下对应EquipmentItem中的ifHover为正且鼠标右键点击时触发。即
public bool DressEquip(int id) //仅显示添加部分
{
UpdateProperty ();
return true;
}
以及
if (isHover)
{
if(Input.GetMouseButtonDown(1))
{
Inventory._instance.GetId(id);
GameObject.Destroy(this.gameObject);
Equipment._instance.UpdateProperty();
}
}
这里先留出了接口,之后再解决装备信息与状态系统的交互功能。