最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網 會員登陸 & 注冊

unity基于網絡從登錄到背包與商店系統(tǒng)的簡單實例

2022-08-05 13:43 作者:限量版范兒  | 我要投稿

環(huán)境準備

客戶端:unity2021
服務端:vs2019
工具:protobuf、cJson、libuv

流程圖如下

角色登錄與創(chuàng)建

協(xié)議

查看代碼

客戶端

通過UI點擊事件作為驅動邏輯發(fā)送網絡請求,接受請求的時候也作出相應回調

? ?private void OnLoginClick() ? ?{ ? ? ? ?//預先判斷賬號密碼是否為空 ? ? ? ?if (string.IsNullOrEmpty(playerId.text)) ? ? ? ?{ ? ? ? ? ? ?Debug.Log("用戶名為空"); ? ? ? ? ? ?return; ? ? ? ?} ? ? ? ?if (string.IsNullOrEmpty(password.text)) ? ? ? ?{ ? ? ? ? ? ?Debug.Log("密碼為空"); ? ? ? ? ? ?return; ? ? ? ?} ? ? ? ?UserService.Instance().SendPlayerLogin(this.playerId.text, this.password.text); ? ?} ? ?private void OnLogin(int result,string reason) ? ?{ ? ? ? ?//能夠成功登錄 ? ? ? ?if (result == 0) ? ? ? ?{ ? ? ? ? ? ?SceneManager.LoadScene(1); ? ? ? ? ? ?UserService.Instance().SendPlayerInfoReq(Player.Instance().PlayerID); ? ? ? ?} ? ? ? ?//登錄失敗 ? ? ? ?else ? ? ? ?{ ? ? ? ? ? ?Debug.LogFormat("Login Fail [Result:{0} Reason:{1}]", result, reason); ? ? ? ?} ? ?}

UserService.cs
當客戶端接收到Response,Service接收到該事件,并向UI層和其他數據管理模塊進行回調
和NetWork的事件注冊邏輯

? ?public UserService() ? ?{ ? ? ? ?EventModule.Instance().AddNetEvent((int)SERVER_CMD.ServerLoginRsp, OnPlayerLogin); ? ? ? ?EventModule.Instance().AddNetEvent((int)SERVER_CMD.ServerCreateRsp, OnPlayerCreate); ? ? ? ?EventModule.Instance().AddNetEvent((int)SERVER_CMD.ServerShopbuyRsp, OnShopBuy); ? ? ? ?EventModule.Instance().AddNetEvent((int)SERVER_CMD.ServerPlayerinfoRsp, OnPlayerInfo); ? ?} ? ?public void OnDispose() ? ?{ ? ? ? ?EventModule.Instance().RemoveNetEvent((int)SERVER_CMD.ServerLoginRsp, OnPlayerLogin); ? ? ? ?EventModule.Instance().RemoveNetEvent((int)SERVER_CMD.ServerCreateRsp, OnPlayerCreate); ? ? ? ?EventModule.Instance().RemoveNetEvent((int)SERVER_CMD.ServerShopbuyRsp, OnShopBuy); ? ? ? ?EventModule.Instance().RemoveNetEvent((int)SERVER_CMD.ServerPlayerinfoRsp, OnPlayerInfo); ? ?}

讓其他模塊通過這里進行注冊回調

? ?public UnityAction<int, string> OnLogin; //角色進入對UI回調 ? ?public UnityAction<int, string> OnCreate; //角色創(chuàng)建對UI回調 ? ?public UnityAction OnBuySuccess; //購買物品時回調 ? ?public UnityAction<int,string> OnBuyFail; //購買失敗的回調 ? ?public UnityAction OnPlayerInfoLoad; //角色信息加載完成的回調

以角色登錄舉例 一個發(fā)送一個接受邏輯。角色登錄成功會再向服務器發(fā)送一個角色信息的請求

? ?//發(fā)送登錄請求 ? ?public void SendPlayerLogin(string playerId, string password) ? ?{ ? ? ? ?Debug.LogFormat("Send Player Login Request:[id:{0} password:{1}]", playerId, password); ? ? ? ?PlayerLoginReq req = new PlayerLoginReq(); ? ? ? ?req.PlayerID = playerId; ? ? ? ?req.Password = password; ? ? ? ?Player.Instance().PlayerID = playerId; ? ? ? ?Network.Instance().SendMsg((int)CLIENT_CMD.ClientLoginReq, req); ? ?} ? ?//接受登錄響應 ? ?public void OnPlayerLogin(int cmd, IMessage msg) ? ?{ ? ? ? ?PlayerLoginRsp rsp = msg as PlayerLoginRsp; ? ? ? ?Debug.LogFormat("OnPlayerLogin:[Result:{0} Reason:{1}]", rsp.Result, rsp.Reason); ? ? ? ?if (this.OnLogin != null) ? ? ? ?{ ? ? ? ? ? ?OnLogin.Invoke(rsp.Result, rsp.Reason); ? ? ? ?} ? ?}

角色信息請求和響應

查看代碼




玩家實體唯一,用單例的方式表示

查看代碼




服務端

服務端的網絡層客戶端發(fā)來的網絡包后通過解析Proto協(xié)議,根據Proto頭進行不同處理

查看代碼






角色信息請求的處理邏輯

//客戶端拉取角色信息 bool PlayerMgr::playerInfo_request(uv_tcp_t* client,const PlayerInfoReq* req) { ? ?bool result = false; ? ?Player* player = nullptr; ? ?PlayerSaveData* playerData = new PlayerSaveData(); ? ?PlayerBagData* playerBag = new PlayerBagData(); ? ?PlayerInfoRsp rsp; ? ?fprintf(stdout, "playerInfo request\n"); ? ?// 1. 查看玩家是否已經在游戲中,如果不在游戲中則返回失敗 ? ?player = find_player(req->playerid()); ? ?if (player == nullptr) { ? ? ? ?rsp.set_result(-1); ? ? ? ?rsp.set_reason("player has not login"); ? ? ? ?player = nullptr; ? ? ? ?goto Exit1; ? ?} ? ?// 2. 嘗試從文件中加載玩家數據,如果未加載成功則返回失敗 ? ?if (!_load_player(req->playerid(), playerData)) { ? ? ? ?rsp.set_result(-2); ? ? ? ?rsp.set_reason("player id exist"); ? ? ? ?goto Exit1; ? ?} ? ?// 3、嘗試從文件中加載背包數據 ? ?if (g_itemMgr._load_player_Items(req->playerid(), playerBag)) ? ?{ ? ? ? ?rsp.set_allocated_playerbagdata(playerBag); ? ?} ? ?// 4. 應答客戶端登錄結果 ? ?rsp.set_allocated_playerdata(playerData); ? ?rsp.set_result(0); Exit1: ? ?{ ? ? ? ?string r = rsp.SerializeAsString(); ? ? ? ?int len = encode(s_send_buff, SERVER_PLAYERINFO_RSP, r.c_str(), (int)r.length()); ? ? ? ?sendData((uv_stream_t*)client, s_send_buff, len); ? ?} ? ?result = true; Exit0: ? ?return result;

此外創(chuàng)建的時候要將角色存儲下來
登錄的時候要將角色讀取出來存到角色容器

查看代碼







為了讓數據持久化,用文件方式存取數據

// 把玩家數據保存到文件中,成功返回true,失敗返回false bool PlayerMgr::_save_player(const Player* player) { ? ?// todo 把玩家數據序列化后存盤,參考save函數 ? ?int retCode = 0; ? ?PlayerSaveData playerData; ? ?playerData.set_password(player->Password); ? ?playerData.set_name(player->Name); ? ?playerData.set_playerid(player->PlayerID); ? ?playerData.set_money(player->Money); ? ?retCode = save(player->PlayerID.c_str(), playerData.SerializeAsString().c_str(), playerData.ByteSize()); ? ?if (retCode != 0) ? ? ? ?return false; ? ?else ? ? ? ?return true; }// 從文件中加載玩家數據,用PlayerSaveData的方式讀出 成功返回true,失敗返回false bool PlayerMgr::_load_player(string playerID, PlayerSaveData* playerData) { ? ?// todo 從文件中讀取數據,并反序列化到playerData中,參考load函數 ? ?int len = load(playerID.c_str(), s_send_buff, sizeof(s_send_buff)); ? ?if (len >= 0) { ? ? ? ?playerData->ParseFromArray(s_send_buff, len); ? ? ? ?return true; ? ?} ? ?return false; }

Save文件

查看代碼










Load文件

查看代碼










Player實體數據

struct Player { ? ?string PlayerID; ? ?string Password; ? ?string Name; ? ?int Money; };

背包與商城

配置表

客戶端和服務端都持有一個配置表數據,記錄關于存放在商城和背包的道具的靜態(tài)信息。雙方只需要傳遞道具的id就可以在各自的配置表中找出道具的具體信息
json配置表

客戶端

客戶端背包商城邏輯

客戶端和服務端執(zhí)行相應的讀取操作,存儲到相應的實體中去
客戶端利用字典的結構進行存儲

查看代碼






發(fā)送購買請求和接收購買請求

//發(fā)送角色購買請求 ? ?public void SendShopBuy(string playerId,int itemId,int count) ? ?{ ? ? ? ?Debug.LogFormat("Send Shop Buy Request:[id:{0} itemId:{1} count:{2}]", playerId, itemId, count); ? ? ? ?ShopBuyReq req = new ShopBuyReq(); ? ? ? ?req.PlayerID = playerId; ? ? ? ?req.ItemId = itemId; ? ? ? ?req.Count = count; ? ? ? ?Network.Instance().SendMsg((int)CLIENT_CMD.ClientShopbuyReq, req); ? ?} ? ?//接受購買請求響應 ? ?public void OnShopBuy(int cmd, IMessage msg) ? ?{ ? ? ? ?ShopBuyRsp rsp = msg as ShopBuyRsp; ? ? ? ?Debug.LogFormat("ShopBuyRsp:[Result:{0} Reason:{1}]", rsp.Result, rsp.Reason); ? ? ? ?if (rsp.Result == 0) ? ? ? ?{ ? ? ? ? ? ?OnBuySuccess.Invoke(); ? ? ? ?} ? ? ? ?else ? ? ? ?{ ? ? ? ? ? ?OnBuyFail.Invoke(rsp.Result, rsp.Reason); ? ? ? ? ? ?Debug.LogFormat("Buy Fail [Result:{0} Reason:{1}]", rsp.Result, rsp.Reason); ? ? ? ?} ? ?}

協(xié)議結構如下:

查看代碼






購買成功后一個是會修改角色的金錢數據和ui上的金幣數量,一個是修改背包的道具信息
ShopUI記錄了購買時點擊的商品id和數量,當購買成功后修改角色背包信息,同時對UIBag的信息進行了更新
添加Player中的道具

? ?public void AddBagItem(int itemId,int count) ? ?{ ? ? ? ?if (!bag.ContainsKey(itemId)) ? ? ? ?{ ? ? ? ? ? ?bag.Add(itemId, count); ? ? ? ?} ? ? ? ?else ? ? ? ?{ ? ? ? ? ? ?bag[itemId] += count; ? ? ? ?} ? ? ? ?if (OnBagChange != null) ? ? ? ?{ ? ? ? ? ? ?OnBagChange.Invoke(); ? ? ? ?} ? ?}

修改背包UI 重新刷新一遍

? ?void UpdateItem() ? ?{ ? ? ? ?ClearItems(); ? ? ? ?this.money.text = Player.Instance().Money.ToString(); //修改金幣數量 ? ? ? ?Dictionary<int, int> bag = Player.Instance().bag; ? ? ? ?foreach (int id in bag.Keys) ? ? ? ?{ ? ? ? ? ? ?Item item = ItemManager.Instance().GetItem(id); ? ? ? ? ? ?GameObject go = Instantiate<GameObject>(ItemPrefab, itemGrid.transform); ? ? ? ? ? ?Slot ui; ? ? ? ? ? ?if (go.TryGetComponent<Slot>(out ui)) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?if (ui is UIBagItem) ? ? ? ? ? ? ? ?{ ? ? ? ? ? ? ? ? ? ?UIBagItem bagItem = ui as UIBagItem; ? ? ? ? ? ? ? ? ? ?Sprite sprite; ? ? ? ? ? ? ? ? ? ?ItemManager.Instance().TryGetSprite(item.iconName, out sprite); ? ? ? ? ? ? ? ? ? ?//將item信息賦值給ui ? ? ? ? ? ? ? ? ? ?bagItem.SetInfo(item, sprite); ? ? ? ? ? ? ? ? ? ?bagItem.count.text = string.Format("*{0}", bag[id]); ? ? ? ? ? ? ? ? ? ?bagItem.onClick.AddListener(OnSlotClick); ? ? ? ? ? ? ? ?} ? ? ? ? ? ?} ? ? ? ?} ? ?}

服務端

服務端也需要從配置表讀取道具信息

查看代碼



本地的實體結構如下

struct PlayerItem { ? ?string PlayerID; ? ?map<int, int> Items; }; struct Item { ? ?int id; ? ?string name; ? ?string introduce; ? ?int price; ? ?string iconName; };

服務端維護了一個玩家背包的存儲數據
相應的存取操作

查看代碼





協(xié)議結構如下

message BagItem{ int32 ItemId=1; int32 Count=2; } message PlayerBagData{ repeated BagItem BagItem=2; }

接收到購買請求進行處理

bool ItemMgr::item_buy(uv_tcp_t* client, const ShopBuyReq* req) { ? ?bool result = false; ? ?Player* player = nullptr; ? ?PlayerSaveData playerData; ? ?ShopBuyRsp rsp; ? ?PlayerBagData playerBagData; ? ?PlayerItem* playerItem = new PlayerItem(); ? ?fprintf(stdout, "item buy request\n"); ? ?// 1. 查看玩家是否已經在游戲中,如果在游戲中登錄失敗 ? ?player = g_playerMgr.find_player(req->playerid()); ? ?if (player == nullptr) { ? ? ? ?rsp.set_result(-1); ? ? ? ?rsp.set_reason("player has not login"); ? ? ? ?goto Exit1; ? ?} ? ?//2、判斷商店是否有該商品 ? ?if (m_storeMap.count(req->itemid()) == 0) ? ?{ ? ? ? ?rsp.set_result(-2); ? ? ? ?rsp.set_reason("store has not this item"); ? ? ? ?goto Exit1; ? ?} ? ?//3、讀取當前玩家金錢數據 讀取商店物品價格數據 判斷是否足夠購買 ? ?if (player->Money < m_storeMap[req->itemid()]->price * req->count()) ? ?{ ? ? ? ?rsp.set_result(-4); ? ? ? ?rsp.set_reason("has not enough money"); ? ? ? ?goto Exit1; ? ?} ? ?player->Money -= m_storeMap[req->itemid()]->price * req->count(); ? ?// 4. 從文件中讀取玩家背包數據并展開 ? ?playerItem->PlayerID = req->playerid(); ? ?if (_load_player_Items(playerItem->PlayerID, &playerBagData)) { ? ? ? ?//如果存在玩家背包 用playerItem暫存 ? ? ? ?if (playerBagData.bagitem_size() > 0) ? ? ? ?{ ? ? ? ? ? ?for (int i = 0; i < playerBagData.bagitem_size(); i++) ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?playerItem->Items.insert(make_pair(playerBagData.bagitem()[i].itemid(), playerBagData.bagitem()[i].count())); ? ? ? ? ? ?} ? ? ? ?} ? ?} ? ?//找到該道具 直接添加數量 ? ?if (playerItem->Items.count(req->itemid()) == 1) ? ?{ ? ? ? ?playerItem->Items[req->itemid()] += req->count(); ? ?} ? ?//沒有找到 添加該道具 ? ?else ? ?{ ? ? ? ?playerItem->Items.insert(make_pair(req->itemid(), req->count())); ? ?} ? ?//5、 保存背包信息 ? ?if (!_save_player_Items(playerItem)) ? ?{ ? ? ? ?fprintf(stdout, "save playerItems error\n"); ? ? ? ?goto Exit0; ? ?} ? ?//6、保存玩家信息 ? ?if (!g_playerMgr._save_player(player)) { ? ? ? ?fprintf(stdout, "save playerInfo error\n"); ? ? ? ?goto Exit0; ? ?} ? ?// 7. 應答客戶端登錄結果 ? ?rsp.set_result(0); Exit1: ? ?{ ? ? ? ?fprintf(stdout, "buy success [item:%d count:%d moneyLeft:%d]\n", req->itemid(), req->count(), player->Money); ? ? ? ?string r = rsp.SerializeAsString(); ? ? ? ?int len = encode(s_send_buff, SERVER_SHOPBUY_RSP, r.c_str(), (int)r.length()); ? ? ? ?sendData((uv_stream_t*)client, s_send_buff, len); ? ?} ? ?result = true; Exit0: ? ?return result; }

來源鏈接:https://www.dianjilingqu.com/460927.html


unity基于網絡從登錄到背包與商店系統(tǒng)的簡單實例的評論 (共 條)

分享到微博請遵守國家法律
蓝山县| 阿拉尔市| 察雅县| 广水市| 平安县| 萨迦县| 桐梓县| 资中县| 苍山县| 平湖市| 鄯善县| 千阳县| 博罗县| 宁化县| 高尔夫| 拜泉县| 吴忠市| 清丰县| 盐山县| 洛南县| 黄梅县| 古蔺县| 乾安县| 楚雄市| 闵行区| 郧西县| 柞水县| 泾阳县| 汉川市| 泾川县| 西华县| 黎川县| 长宁区| 平定县| 藁城市| 德令哈市| 庆阳市| 河曲县| 香港| 华宁县| 秭归县|