任务38:获胜判断,结束游戏与玩家结算数据保存
GameControllerComponentAwakeSystem修改Continue方法
增加游戏结束所有玩家摊牌逻辑与GameOver的调用
\Server\Hotfix\Landlords\System\GameControllerComponentSystem.cs
/// <summary> /// 判断出牌后游戏继续or结束 /// </summary> public static void Continue(this GameControllerComponent self, Gamer lastGamer) { Room room = self.GetParent<Room>(); OrderControllerComponent orderController = room.GetComponent<OrderControllerComponent>(); //是否结束,当前出牌者手牌数为0时游戏结束 bool isEnd = lastGamer.GetComponent<HandCardsComponent>().CardsCount == 0; if (isEnd) { //当前最大出牌者为赢家 Identity winnerIdentity = room.GetGamerFromUserID(orderController.Biggest).GetComponent<HandCardsComponent>().AccessIdentity; List<GamerScore> gamersScore = new List<GamerScore>(); //游戏结束所有玩家摊牌 foreach (var gamer in room.gamers) { //计算玩家积分 gamersScore.Add(new GamerScore() { UserID = gamer.UserID, Score = self.GetGamerScore(gamer, winnerIdentity) }); if (gamer.UserID != lastGamer.UserID) { //剩余玩家摊牌 Card[] _gamerCards = gamer.GetComponent<HandCardsComponent>().GetAll(); room.Broadcast(new Actor_GamerPlayCard_Ntt() { UserID = gamer.UserID, Cards = To.RepeatedField(_gamerCards) }); } } self.GameOver(gamersScore, winnerIdentity); } else { //轮到下位玩家出牌 orderController.Biggest = lastGamer.UserID; orderController.Turn(); room.Broadcast(new Actor_AuthorityPlayCard_Ntt() { UserID = orderController.CurrentAuthority, IsFirst = false }); } }
GameControllerComponentAwakeSystem添加游戏结束、计算积分、结算余额方法
\Server\Hotfix\Landlords\System\GameControllerComponentSystem.cs
- public static async void GameOver 游戏结束
-
public static long GetGamerScore 计算玩家积分
-
public static async Task<long> StatisticalIntegral 结算用户余额保存更新用户信息
-
/// <summary> /// 游戏结束 /// </summary> /// <param name="self"></param> public static async void GameOver(this GameControllerComponent self, List<GamerScore> gamersScore, Identity winnerIdentity) { Room room = self.GetParent<Room>(); Gamer[] gamers = room.gamers; //清理所有卡牌 self.BackToDeck(); room.GetComponent<DeskCardsCacheComponent>().Clear(); Dictionary<long, long> gamersMoney = new Dictionary<long, long>(); foreach (GamerScore gamerScore in gamersScore) { //结算玩家余额 Gamer gamer = room.GetGamerFromUserID(gamerScore.UserID); long gamerMoney = await self.StatisticalIntegral(gamer, gamerScore.Score); gamersMoney[gamer.UserID] = gamerMoney; } //广播游戏结束消息 room.Broadcast(new Actor_Gameover_Ntt() { Winner = (byte)winnerIdentity, BasePointPerMatch = self.BasePointPerMatch, Multiples = self.Multiples, GamersScore = To.RepeatedField(gamersScore) }); //清理玩家 foreach (var _gamer in gamers) { //踢出离线玩家 if (_gamer.isOffline) { //ActorMessageSender actorProxy = Game.Scene.GetComponent<ActorMessageSenderComponent>().Get(_gamer.Id); //await actorProxy.Call(new Actor_PlayerExitRoom_Req()); } //踢出余额不足玩家 else if (gamersMoney[_gamer.UserID] < self.MinThreshold) { //ActorMessageSender actorProxy = _gamer.GetComponent<UnitGateComponent>().GetActorMessageSender(); //actorProxy.Send(new Actor_GamerMoneyLess_Ntt() { UserID = _gamer.UserID }); } } } /// <summary> /// 计算玩家积分 /// </summary> public static long GetGamerScore(this GameControllerComponent self, Gamer gamer, Identity winnerIdentity) { HandCardsComponent handCards = gamer.GetComponent<HandCardsComponent>(); //积分计算公式:全场底分 * 全场倍率 * 身份倍率 long integration = self.BasePointPerMatch * self.Multiples * (int)handCards.AccessIdentity; //当玩家不是胜者,结算积分为负 if (handCards.AccessIdentity != winnerIdentity) integration = -integration; return integration; } /// <summary> /// 结算用户余额保存 /// </summary> public static async Task<long> StatisticalIntegral(this GameControllerComponent self, Gamer gamer, long sorce) { DBProxyComponent dbProxy = Game.Scene.GetComponent<DBProxyComponent>(); //结算用户余额 UserInfo userInfo = await dbProxy.Query<UserInfo>(gamer.UserID); userInfo.Money = userInfo.Money + sorce < 0 ? 0 : userInfo.Money + sorce; //更新用户信息 await dbProxy.Save(userInfo); return userInfo.Money; }
本节消息定义
\Proto\HotfixMessage.proto
-
message GamerScore { int64 UserID = 1; int64 Score = 2; } message Actor_Gameover_Ntt // IActorMessage { int32 RpcId = 90; int64 ActorId = 93; int32 Winner = 1; //byte int64 BasePointPerMatch = 2; int32 Multiples = 3; repeated GamerScore GamersScore = 4; } message Actor_GamerMoneyLess_Ntt // IActorMessage { int32 RpcId = 90; int64 ActorId = 93; int64 UserID = 1; }
下一节只需在前端让玩家显示牌局结束信息界面
- 如果无人继续新的牌局,在服务端清除玩家与房间数据,通知所有玩家前端退出房间
- 如果有人继续新的牌局,修改玩家匹配状态与更改房间状态为空闲房间,通知不继续玩家前端腿出房间
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)