商店系统步骤

首先制定实体类和传输协议。

  • #ShopDefine 商店类型实体

    public class ShopDefine
        {
            public int ID{get;set;}  //
            public stirng Name {get;set;}
            public string Icon {get;set;}
            public string Description {get;set;}
    
            public int Status {get;set;}
    
        }
    
  • #ShopItemDefine 商店里的物品实体

    public class ShopItemDefine
        {
            public int ItemID{get;set;}
            public int Count {get;set;}
            public int Price {get;set;}
            public int Status{get;set;} 
        }
    
  • 传输协议:

    message NCharacterInfo {
    	
    	int64 gold = 12; --往人物信息增加金钱
    }
    
    --状态协议
    enum STATUS_ACTION 
    {
    UPDATE = 0; --数量更新
    ADD = 1;    --增加道具等
    DELETE = 2; --删除道具等
    }
    
    enum STATUS_TYPE --变动的类型
    {
    MONEY = 0;
    EXP = 1;
    SKILL_POINT = 2;
    ITEM = 3;
    }
    
    enum STATUS_SOURCE
    {
    UPDATE = 0;
    ADD = 1;
    DELETE = 2;
    }
    
    message NStatus --状态的结构
    {
    STATUS_TYPE type = 1;
    STATUS_ACTION action = 2;
    int32 Id = 3;
    int32 value = 4;
    }
    
    message StatusNotify  --状态更新,里面是个数组 包含了所有更新。
    {
    repeated NStatus status = 1;
    }
    
    message NetMessageRequest
    {
    	ItemBuyRequest itemBuy = 10; --增加购买的请求
    }
    message NetMessageResponse
    {
    	ItemBuyResponse itemBuy = 10; --增加购买的服务器反馈
    	StatusNotify statusNotify = 100; --反馈的状态
    }
    
    message ItemBuyRequest    --增加购买的请求
    {
    int32 shopId = 1;
    int32 shopItemId = 2;
    }
    message ItemBuyResponse   --增加购买的回馈
    {
    RESULT result = 1;
    string errormsg = 2;
    }
    

个人见解


构建UIShop管理商店页面,与背包系统类似,需要管理商店UI的标题Title,显示的金钱数money,需要根据导入的ShopItems并instantiate的自定义Prefab:UIShopItem,Tab页。

对于UIShop:

UIShop首先需要将DataManager的数据加载到本地类中,并且使用

Dictionary<int ShopID,Dictionary<int id,Item item>>保存,创建一个public方法,参数为ShopId,作用是每当玩家点击不同的商家时,加载该商家的数据,并且遍历指定商家的道具,创建UIShopItem。

玩家点击购买button后会遍历Tab页下的ShopItem,统计物品的购买数量。

对于UIShopItem:

有关于道具的各项属性,例如购买价格,鼠标移到物品上有物品的信息,有选定物品数量的按钮。


  • 遇到问题1:

    UISHOP里的数据信息何时才会更新。

类职能阐述:

客户端


UIShop:

掌管Shop商店UI,包括了初始化商店物品列表,商店的text信息,物品的点击事件等。

UIShopItem:

掌管Shop商店的单个物品信息,有初始化自身Text信息的public方法。自身被UIShop用做物品列表里的物品元素。响应点击事件,当发生点击时,将自身传回UIShop的点击方法中,让UIShop做处理。

UIShopManager:

创建响应点击NPC时要执行的方法,注册给NpcManager,要执行的方法是取出要显示的商店数据,并且显示商店UI。

响应购买物品动作,与Service层(ItemService)交互。

ItemService:

与服务器端交互,传递商店ID与商品物品ID。

服务器端


ItemService:

响应购买服务的方法,

ShopManager:

响应购买服务的方法,要为所有购买的请求服务,所以要把所有购买的请求session作为参数传进来,进行购买操作,扣除金币,存储数据库等,而后返回一个结果值。

UserService:

新增初始金币。

Character:

增加金币

StatusManager:

管理角色操作的状态,例如当发生金钱变动,物品变动时,可在角色Character实体中的StatusManager增加相应的状态,并把变化量也记录下来,会有一个List将其保存。


服务器端:

新增状态管理器StatusManager,并且改动了服务端传输Response的操作。

以前的传输方式:

NetMessage message = new NetMessage();
message.Response = new NetMessageResponse();
message.Response.userRegister = new UserRegisterResponse();
byte[] data = PackageHandler.PackMessage(message);
message.Response.userRegister.Result = Result.Failed;
sender.SendData(data, 0, data.Length);

修改后:

首先对存放会话的Session做修改,

NetSession:
NetMessage response;
public NetMessageResponse Response {
            get {
                if (response == null) {
                    response = new NetMessage();

                }
                if (response.Response == null) {
                    response.Response = new NetMessageResponse();
                }
                return response.Response;
            
            } 
        }

public byte[] GetResponse() {
            if (response != null) {
                if (this.Character != null && this.Character.statusManager.HasStatus) {
										//将所有需要更新的状态都压入NetMessageResponse.statusNotify这个容器里
                    this.Character.statusManager.ApplyResponse(Response);
                }
                //包装成字节流。
                byte[] data = PackageHandler.PackMessage(response);
                response = null;
                return data;
            }
            return null;
        }

而NetConnection则只需要增加

public void SendResponse() {
            byte[] data = session.GetResponse();
            this.SendData(data,0,data.Length);
        }

购买经过的流程为

大体上:

ItemService.OnItemBuy→ShopManager.BuyItem

→NetSession.Character.itemManager

→NetSession.Character.statusManager

→ShopManager.DBService.Instance.Save()

→ItemService

→NetSession.GetResponse

→NetSession.Character.statusManager.ApplyResponse →PackageHandler.PackMessage

ItemService接收到请求

→将session,request里的shopId和shopItemId传入ShopManager的购买方法

→ShopManager进行商店与商店物品的判断,对session里character实体类的各项manager做操作(ItemManager等)。

→ItemManager等有关于各项数据库更新的方法,都附带了Character.statusManager.AddItemChange —更新物品

Character.statusManager.AddGoldChange —更新金钱

把购买的操作以状态的形式记录下来。记录的位置是

session(NetConnection.NetSession).Character.statusManager.Status(List<NStatus> Status)

→在准备发送给客户端的Response里,在构造完NetMessageResponse里请求所需的消息后(如购买道具则是):

sender.Session.Response.itemBuy = new ItemBuyResponse();
sender.Session.Response.itemBuy.Result = result;

还需要调用NetSession的GetResponse()方法,该方法会先将Character.statusManager.Status里的状态遍历压入NetMessageResponse.statusNotify中,并将整个NetMessageResponse打包成字节流,再发送到客户端。

一切的操作都在OnItemBuy的会话参数NetConnection<NetSession> sender中。

  • #StatusManager:

    public class StatusManager 
        {
            Character Owner;
            private List<NStatus> Status { get; set; }
            public bool HasStatus { get { return this.Status.Count > 0; } }
    
            public StatusManager(Character owner) {
                this.Owner = owner;
                this.Status = new List<NStatus>();
            }
    				//将物品的状态更新压入状态存储List里。
            public void AddStatus(StatusType type,int id,int value,StatusAction action)
            { 
                this.Status.Add(new NStatus()
                {
                    Type = type,    //操作了什么类型,MONEY金钱为0:MONEY,EXP,SKILL_POINT,ITEM
                    Id = id,        //操作了的ID:ItemId什么的。
                    Value = value,  //操作的值
                    Action = action //操作是什么:UPDATE更新操作,ADD增加操作,DELETE删除操作
                });
               
            }
    			 
    				//金钱操作调用这个
            public void AddGoldChange(int goldDelta) {
                if (goldDelta > 0) {
                    this.AddStatus(StatusType.Money,0,goldDelta,StatusAction.Add);
                 
                }
                if (goldDelta < 0) {
                    this.AddStatus(StatusType.Money,0,-goldDelta,StatusAction.Delete);
                }
            
            }
    				//物品操作调用这个
            public void AddItemChange(int id,int count,StatusAction action) {
                this.AddStatus(StatusType.Item,id,count,action);
    
            }
    			
            public void ApplyResponse(NetMessageResponse message) {
                if (message.statusNotify == null) {//为response新增一个状态存储容器。
                    message.statusNotify = new StatusNotify();
                }
    				//将上面操作过的所有状态都压入response参数的状态存储容器中。
                foreach (var status in this.Status) {
                    message.statusNotify.Status.Add(status);
                }
                this.Status.Clear(); //清空掉存储的状态容器。
            }
        }
    

客户端:

新增StatusService用于接收服务端传来的状态信息,创建注册用的Dictionary容器eventMap,将StatusType状态类型作为key,delegate bool StatusNotifyHandle(NStatus status)作为value,当有相同的key时,利用+=叠加deletegate值。

当接收到状态信息时,利用foreach遍历出里面的NStatus数据,并且逐个对比注册事件表eventMap,执行他们。

  • #StatusService

    class StatusService : Singleton<StatusService>, IDisposable
        {
            public delegate bool StatusNotifyHandler(NStatus status);
    				
            Dictionary<StatusType, StatusNotifyHandler> eventMap = new Dictionary<StatusType, StatusNotifyHandler>();
            HashSet<StatusNotifyHandler> handles = new HashSet<StatusNotifyHandler>();
            public void Init() { }
            public StatusService()
            {
                MessageDistributer.Instance.Subscribe<StatusNotify>(this.OnStatusNotify);
            }
            public void Dispose()
            {
                MessageDistributer.Instance.Unsubscribe<StatusNotify>(this.OnStatusNotify);
            } 
    				//function参数作为状态信息可理解为行为,action为该行为下要做出的动作。
            public void RegisterStatusNotify(StatusType function, StatusNotifyHandler action) {
                //避免注册重复的action
    						if (handles.Contains(action))
                    return;
                if (!eventMap.ContainsKey(function)) {
                    eventMap[function] = action;
                }
                else {
    								//该行为下可能会做出不止一种动作。
                    eventMap[function] += action;
                }
                handles.Add(action);
            }
    
            private void OnStatusNotify(object sender, StatusNotify notify)
            {
                foreach (NStatus status in notify.Status) {
                    Notify(status);
                }
                
            }
    
            public void Notify(NStatus status) {
                Debug.LogFormat("StatusNotify:[{0}][{1}]{2}:{3}",status.Type,status.Action,status.Id,status.Value);
                if (status.Type == StatusType.Money) {
                    if (status.Action == StatusAction.Add) {
                        User.Instance.AddGold(status.Value);
                    }
                    if (status.Action == StatusAction.Delete)
                    {
                        User.Instance.AddGold(-status.Value);
                    }
                }
    
                StatusNotifyHandler handler;
                if (eventMap.TryGetValue(status.Type, out handler)) {
                     handler(status);
                }
    
            }
    
          
        }
    

ItemManager增加OnItemNotify方法,并且将方法注册给StatusService,ItemManager管理道具的删减,所以注册的状态为StatusType.Item

(StatusService.Instance.RegisterStatusNotify(StatusType.Item,OnItemNotify);),

作用是当有状态是增加道具时(Status.Action==StatusAction.Add),调用AddItem方法增加道具。

  • #AddItem

    private void AddItem(int itemId, int count)
            {
                Item item = null;
    						//先从玩家已拥有的数据里取。
                if (this.Items.TryGetValue(itemId, out item))
                {
                    item.Count += count;
                }
                else {
                    //玩家没有,就构建道具导入。
                    item = new Item(itemId,count);
                    this.Items.Add(itemId,item);
                }
    				BagManager.Instance.AddItem(itemId,count);
            }
    

作用是当有状态是减少道具时(Status.Action==StatusAction.Delete),调用RemoveItem方法增加道具。

  • #RemoveItem

    void RemoveItem(int itemId, int count) {
                if (!this.Items.ContainsKey(itemId)) {
                    return;
                }
                Item item = this.Items[itemId];
                if (item.Count < count) {
                    return;
                }
                item.Count -= count;
                BagManager.Instance.RemoveItem(itemId,count);
            }
    

之后道具的增加还要实施到背包的UI中,

有关整个道具系统的变化是客户端Service接收到服务端的状态消息(StatusService接受信息),然后通知注册表里的方法(通知ItemManager进行用户物品的加减),然后再执行背包系统的道具加减(通知BagManager进行物品的加减,注意物品上线数量的拆分。)

(注意)

需要在Common的NetWork里配置消息分发器。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值