RPG游戏《黑暗之光》流程介绍与代码分析之(八):装备系统的实现

第七章 装备系统

装备系统是提升角色属性的重要系统,本篇博客重点实现装备系统UI的设计以及装备栏与物品栏的交互。

7.1 基础界面的设计

导入装备UI的模型,命名为Equipment,并添加5个方框,用以放置装备,如下图

当点击功能面板的装备按钮时,显示动画(方法见 https://blog.csdn.net/s1314_JHC/article/details/79690742 下的5.5节),不赘述。
我们在每个格子中再创建一个Child Sprite,当实例化时直接给这个Child Sprite添加装备图标即可。拖放到Prefab之中,方便之后使用

在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;
    }

7.2 装备信息的添加与管理

这节我们实现装备信息的添加以及模拟拾取功能,与药品信息类似,我们创建装备信息的格式如下。

内容依旧添加在之前的文档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节,只需修改随机数的范围即可),判断是否添加成功,如下左图所示

7.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;
    }
即可实现,如下图

7.4 实现穿戴功能

接下来实现点击鼠标右键进行穿戴的功能,需要与装备栏进行交互。在InventoryInsideItem之中,当isHover为true时,即鼠标位于物体之上,我们实现穿戴功能。

在Magician下的PlayerStatus脚本中加入一个角色种类,分为魔法师和剑士,并在函数内赋值
public enum playerRole{
    Swordman,
    Magician
}
public class PlayerStatus : MonoBehaviour {

    public playerRole role = playerRole.Magician;
}
上述代码在穿戴的角色判断时需要用到,不同的角色所穿戴的部分装备是有限制的,我们在装备界面Equipment脚本中实现穿戴DressEquip()功能

7.4.1 无法穿戴的情形

针对当前的角色魔法师,我们首先考虑三种情况是无法穿戴的:
  1. 当前物品不是装备
  2. 当前角色不是魔法师
  3. 当前角色虽然是魔法师,但穿戴类型为剑士
    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;
            }
        }
    }

7.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更改显示的装备

在之前存为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);    
        }

7.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();        
        }
    }
完成后显示效果如下图

7.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);    
            }
        }
    }

7.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();
            }
        }
这里先留出了接口,之后再解决装备信息与状态系统的交互功能。

猜你喜欢

转载自blog.csdn.net/s1314_JHC/article/details/79938267
今日推荐