装备系统步骤

2021/10/2 23:14:31

本文主要是介绍装备系统步骤,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

装备系统可以与背包相似,而装备与道具类似,区别在于装备系统的道具无法堆叠,且装备栏的格子较少。

装备的数据结构,使用数组来保存各个位置的信息。

下标位置代表了各个部位

EQUIP_DATA

WEAPON,ACCESSORY,HELMET,CHEST,SHOULDER,PANTS,BOOTS

然后用一个枚举

Enum Equip{
WEAPON,
ACCESSORY,
HELMET,
CHEST,
SHOULDER,
PANTS,
BOOTS
}

增加的协议

enum ITEM_TYPE{
	EQUIP= 3; //装备类型
}
enum EQUIP_SLOT{
	WEAPON = 0;
	ACCESSORY = 1;
	HELMET = 2 ; //头盔
	CHEST = 3;//胸甲
	SHOULDER = 4; //护肩
	PANTS = 5; //裤子
	BOOTS = 6; //靴子
	SLOT_MAX = 7;
}

message NCharacterInfo {
	bytes Equips = 12;
}

message NetMessageRequest{
ItemEquipRequest itemEquip = 12;
}

message NetMessageResponse{
ItemEquipResponse itemEquip = 12;
}

message ItemBuyRequest    
{
int32 shopId = 1;
int32 shopItemId = 2;
}

message ItemBuyResponse  
{
RESULT result = 1;
string errormsg = 2;
}

增加装备的实体类。

public enum EquipSlot {
		WEAPON,
		ACCESSORY,
		HELMET,
		CHEST,
		SHOULDER,
		PANTS,
		BOOTS
	}
public class EquipDefine{
		public int ID { get; set; }
		public EquipSlot Slot { get; set; }
		public string Category { get; set; }
		public float STR { get; set; }
		public float INT { get; set; }
		public float DEX { get; set; }
		public float HP { get; set; }
		public float MP { get; set; }
		public float AD { get; set; }
		public float AP { get; set; }
		public float DEF { get; set; }
		public float MDEF { get; set; }
		public float SPD { get; set; }
		public float CRI { get; set; }
	}

在数据库的Character表里增加Equips字段,设置最大长度为28,存储格式为Binary二进制。(为什么是28字节。)

服务器端

在Character实体类增加

this.Info.Equips = cha.Equips;

将数据库里的装备信息加载入内存。

在DataManager里面加入装载数据的方法。

在ItemService里添加关于装备动作的监听接受request,并且调用EquipManager的方法。EquipManager是单例类,与ItemManager不同,ItemManager是因为Character实体类里有ItemManager,所以需要绑定进去不能是单例。

根据穿装备来考虑EquipManager要做的事,首先考虑谁要穿装备,装备穿上的槽位,道具ID,道具是穿还是脱。

然后直接从session里取出Character.ItemManager,并且根据ItemManager里的数据检验角色是否拥有这件道具。

之后利用与背包系统类似的二维数组的方式存储装备,注意此处是直接用int类型保存ItemId,所以用int指针即可。

class EquipManager : Singleton<EquipManager>
    {
        public Result EquipItem(NetConnection<NetSession> sender,int slot,int itemId,bool isEquip) {
            Character character = sender.Session.Character;
            if (!character.itemManager.Items.ContainsKey(itemId))  //判断角色是否拥有道具
            {
                return Result.Failed;
            }
            UpdateEquip(character.Data.Equips, slot, itemId, isEquip);
            DBService.Instance.Save();
            return Result.Success;
        }
        unsafe void UpdateEquip(byte[] equipData,int slot,int itemId,bool isEquip) {
            fixed (byte* first = equipData) {
                int* equip = (int*)(first + slot * sizeof(int));
                if (isEquip)
                { 
                    *equip = itemId;
                }
                else {
                    *equip = 0;
                } 
            }
        }
    }

客户端

在Item实体类增加关于装备的信息类。

public EquipDefine EquipInfo;
DataManager.Instance.Equips.TryGetValue(itemId,out EquipInfo);

在ItemService中增加传输方法,监听返回结果的方法。

				Item pendingEquip = null; //当前身上的装备
        bool isEquip;
        public bool SendEquipItem(Item equip,bool isEquip)
        {
            Debug.Log("SendEquipItem");
            if (pendingEquip != null) {  //如果穿了装备,
                Debug.Log("身上穿了装备");
                return false;
            }
            pendingEquip = equip; //穿上装备
            this.isEquip = isEquip;
            NetMessage message = new NetMessage();
            message.Request = new NetMessageRequest();
            message.Request.itemEquip = new ItemEquipRequest();
            message.Request.itemEquip.isEquip = isEquip;
            message.Request.itemEquip.itemId = equip.itemId;
            message.Request.itemEquip.Slot = (int)equip.EquipInfo.Slot;
            NetClient.Instance.SendMessage(message);
            return true;
        }

        private void OnItemEquip(object sender, ItemEquipResponse message) {
            if (message.Result == Result.Success) {
                if (pendingEquip != null) {  //身上穿了装备
                    if (this.isEquip)
                    {
                        EquipManager.Instance.OnEquipItem(pendingEquip);
                    }
                    else {
                        EquipManager.Instance.OnUnEquipItem(pendingEquip.EquipInfo.Slot);
                    }
                }
            }
        }

在EquipManager管理类中制定委托OnEquipChangeHandler和事件OnEquipChanged,用以处理装备脱穿后的效果,该方法要由UI层的方法注册。

  • #EquipManager

    class EquipManager : Singleton<EquipManager>
    	   {  
            public delegate void OnEquipChangeHandler();
    				//UI变更事件,作用是当数据层面发生装备变动时,调用UI层的装备变动方法,改变UI效果。
            public event OnEquipChangeHandler OnEquipChanged;
    				
    			  //存放装备界面上已经装备了的道具。
            public Item[] Equips = new Item[(int)EquipSlot.SLOTMAX];
    				
            byte[] Data; //int list
    
            //初始化方法,将byte数组的数据
            unsafe public void Init(byte[]data) {
                this.Data = data;
                this.ParaseEquipData(data);
            }
            public void EquipItem(Item equip) {
                ItemService.Instance.SendEquipItem(equip, true);
            }
    
            public void UnEquipItem(Item equip) {
                ItemService.Instance.SendEquipItem(equip, false);
            }     
     
    			//用于对比是否装备了形参ID的道具。
            public bool Contains(int equipId){
                for (int i = 0; i < this.Equips.Length; i++) {
                    if(Equips[i]!=null && Equips[i].itemId == equipId)
                        return true;
                }
                return false;
            }
            public Item GetEquip(EquipSlot slot)
            {
                return Equips[(int)slot];
            }
            public unsafe void ParaseEquipData(byte[] data)
            {
                fixed (byte* pt = this.Data)
                {
                    for (int i = 0; i < this.Equips.Length; i++)
                    {
                        int itemId = *(int*)(pt + 1 * sizeof(int));
                        if (itemId > 0)
                            Equips[i] = ItemManager.Instance.Items[itemId];
                        else
                            Equips[i] = null;
                    }
                }
            }
    				//将装备信息转换为字节流
            public unsafe byte[] GetEquipData() {
                fixed (byte* pt = this.Data) {
                    for (int i = 0; i < (int)EquipSlot.SLOTMAX; i++)
                    {
                        int* itemId = (int*)pt + i * sizeof(int);
                        if (Equips[i] == null)
                        {
                            *itemId = 0;
                        }
                        else { 
                        *itemId = Equips[i].itemId;
                    }
                    }
    
                }
                return this.Data;
            }
    
            public void OnEquipItem(Item equip) {
                if (this.Equips[(int)equip.EquipInfo.Slot]!=null && this.Equips[(int)equip.EquipInfo.Slot].itemId == equip.itemId) {//装备上了
                    return;
                }
                this.Equips[(int)equip.EquipInfo.Slot]=ItemManager.Instance.Items[equip.itemId];
    
                if (OnEquipChanged != null) {
                    OnEquipChanged(); //执行UI层的装备变化方法
                }
            }
    
            public void OnUnEquipItem(EquipSlot slot) {
                if (this.Equips[(int)slot] != null) {
                    this.Equips[(int)slot] = null;
                    if (OnEquipChanged != null) {
                        OnEquipChanged();//执行UI层的装备变化方法
                    }
                }
            }
        }
    

书写UI层面的类UICharEquip,该类掌控了整个角色装备栏界面,首先先给EquipManager注册方法,方法为刷新UI界面。这个方法在装备栏被点开时就会调用一次。

刷新要调用

ClearAllEquipList(); InitAllEquipItems(); ClearEquipedList(); InitAllEquipItems();

四种方法。

ClearAllEquipList()方法:是清空可装备道具栏里的所有GameObject。

InitAllEquipItems()方法:是先遍历背包里的道具,并且找出里面装备类型Type为Equip的道具(顺便和EquipManager里的已装备道具做对比),之后在列表里生成Item预制体,取得预制体里的UIEquipItem代码,赋予其道具信息。

ClearEquipedList()方法:清空装备栏的数据。

InitEquipItems():初始化装备栏的数据,直接用EquipManager的已装备数据,来把数据导入到ui中。

  • #UICharEquip

    public class UICharEquip : UIWindow {
    	public Text money;
      //在装备道具栏里的单个物品类
    	public GameObject itemPrefab;
      //装备栏里单个物品类
    	public GameObject itemEquipedPrefab;
      //装备道具栏
    	public Transform itemListRoot;
    
    	public List<Transform> slots;
        // Use this for initialization
        private void OnEnable()
        {
    		RefreshUI();
    	}
        void Start () {
    		
    		//注册方法
    		EquipManager.Instance.OnEquipChanged +=RefreshUI;
    	}
    
    	void OnDestory() {
    		//注销注册方法
    		EquipManager.Instance.OnEquipChanged -= RefreshUI;
    	}
    
        private void RefreshUI()
        {
    		ClearAllEquipList();
    		InitAllEquipItems();
    		ClearEquipedList();
    		InitEquipItems();
    		this.money.text = User.Instance.CurrentCharacter.Gold.ToString();
        }
    
    	public void OnSelectEquip(int idx) {
    		UIEquipItem[] items = itemListRoot.GetComponentsInChildren<UIEquipItem>();
    		
    		for (int k = 0; k< items.Length;k++)
    		{
    			if (k != idx) {
    				items[k].Selected = false;
    			}
    		}
    	}
    	
    	/// <summary>
    	/// 初始化已经装备的列表
    	/// </summary>
        private void InitEquipItems()
        {//根据装备槽给装备槽增添装备
    		for (int i = 0; i < (int)EquipSlot.SlotMax; i++) {
    			Item item =EquipManager.Instance.Equips[i];
    			if (item != null) { 
    			UIEquipItem ui = Instantiate(itemEquipedPrefab, this.slots[i]).GetComponent<UIEquipItem>();
    			ui.SetEquipItem(i,item,this,true);
    			}
    		}
        }
    
        /// <summary>
        /// 初始化所有装备列表
        /// 
        /// </summary>
        private void InitAllEquipItems()
        {
    		int idx = 0;
    		foreach (var kv in ItemManager.Instance.Items) {
    			if (kv.Value.define.Type == ItemType.Equip) {
    				//已经装备就不显示了
    				if (EquipManager.Instance.Contains(kv.Key)) {
    					continue;
    				}
    				
    				GameObject go = Instantiate(itemPrefab,itemListRoot);
    				
    				UIEquipItem ui = go.GetComponent<UIEquipItem>();
    				ui.SetEquipItem(kv.Key,kv.Value,this,false, idx);
    				idx += 1;
    
    			}
    		}
        }
    
        private void ClearAllEquipList()
        {
    		foreach (var item in itemListRoot.GetComponentsInChildren<UIEquipItem>()) {
    			Destroy(item.gameObject);
    		}
        }
    
    	private void ClearEquipedList()
    	{
    		foreach (var item in slots) {
    			if (item.childCount>0){
    				Destroy(item.GetChild(0).gameObject);
    			}
    		}
    	}
    
    	public void DoEquip(Item item) {
    		EquipManager.Instance.EquipItem(item);
    	}
    
    	public void UnEquip(Item item)
    	{
    		EquipManager.Instance.UnEquipItem(item);
    	}
    }
    

UIEquipItem为角色装备界面的道具类。使用了继承IPointerClickHandler的方法来响应点击。

  • #UIEquipItem

    class UIEquipItem : MonoBehaviour, IPointerClickHandler
    {
        public Image icon;
        public Text title, level, limitClass, limitCategory;
        
        public Image background;
        public Sprite normalBg, selectBg;
        private int EquipCIdx;
        //是否被选中
        private bool selected;
    
        public bool Selected { get { return selected; } set {
                
                selected = value;
                this.background.overrideSprite = selected ? selectBg : normalBg;
                
            } }
    
        public int index { get; set; }
    
        private Item item;
        private UICharEquip owner;
        bool isEquiped = false;
    //构建装备栏时初始化物品信息
        public void SetEquipItem(int idx, Item item, UICharEquip owner, bool equiped)
        {
            this.owner = owner;
            this.index = idx;
            this.item = item;
            this.isEquiped = equiped;
    
            if (this.title != null) { this.title.text = this.item.define.Name; }
            if (this.level != null) this.level.text = item.define.Level.ToString();
            if (this.limitClass != null) this.limitClass.text = item.define.LimitClass.ToString();
            if (this.limitCategory != null) this.limitCategory.text = item.define.Category.ToString();
            if (this.icon != null) this.icon.overrideSprite = Resloader.Load<Sprite>(this.item.define.Icon);
            
        }
    //构建装备栏时初始化物品信息(有下标,用以响应点击效果。)
        public void SetEquipItem(int idx, Item item, UICharEquip owner, bool equiped,int EquipCIdx)
        {
            this.owner = owner;
            this.index = idx;
            this.item = item;
            this.isEquiped = equiped;
            this.EquipCIdx = EquipCIdx;
            if (this.title != null) { this.title.text = this.item.define.Name; }
            if (this.level != null) this.level.text = item.define.Level.ToString();
            if (this.limitClass != null) this.limitClass.text = item.define.LimitClass.ToString();
            if (this.limitCategory != null) this.limitCategory.text = item.define.Category.ToString();
            if (this.icon != null) this.icon.overrideSprite = Resloader.Load<Sprite>(this.item.define.Icon);
    
        }
    
        public void OnPointerClick(PointerEventData eventData)
        {
            if (this.isEquiped)
                UnEquip();
            else
                if (this.selected)
            {
                DoEquip();
                //this.Selected = false;
            }
            else {
                this.Selected = true;
    				   //让列表里其他物品的点击效果消失。
                this.owner.OnSelectEquip(EquipCIdx);
    
            }
        }
    
        private void UnEquip()
        {
            var msg = MessageBox.Show(string.Format("要取下{0}吗?", this.item.define.Name), "确认", MessageBoxType.Confirm);
            msg.OnYes = () =>
            {
                this.owner.UnEquip(this.item);
            };
        }
    
        private void DoEquip()
        {
            var msg = MessageBox.Show(string.Format("要装备{0}吗?", this.item.define.Name), "确认", MessageBoxType.Confirm);
            msg.OnYes = () =>
            {
                var oldEquip = EquipManager.Instance.GetEquip(item.EquipInfo.Slot);
                if (oldEquip != null)
                {
                    var newmsg = MessageBox.Show(string.Format("要替换掉[{0}]吗?", oldEquip.define.Name), "确认", MessageBoxType.Confirm);
                    newmsg.OnYes = () =>
                    {
                        this.owner.DoEquip(this.item);
                    };
    
                }
                else
                {
                    this.owner.DoEquip(this.item);
                }
            };
        }
    
     
    }
    

流程顺序为:



这篇关于装备系统步骤的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程