zoukankan      html  css  js  c++  java
  • .Net Core——用SignalR撸个游戏 老马

    之前开内部培训,说到实时web应用这一块讲到了SignalR,我说找时间用它做个游戏玩玩,后面时间紧张就一直没安排。这两天闲了又想起这个事,考虑后决定用2天时间写个斗D主,安排了前端同学写客户端,我写游戏逻辑和服务。

    这个项目难度并不高,但是游戏逻辑还是挺绕的,联调过程中也发现解决了很多小问题。来园子里整理一篇文章,记录一下。

    基础的介绍就免了,毕竟官网跟着走两圈啥都懂了。没基础的可以戳这里,是我之前写的一篇SignalR基础介绍,带有一个极简聊天室。

    tips:文章结尾有开源地址,游戏数据都是本地的,改下IP运行起来就可以玩了。

    直接上干货,首先是数据模型:

        /// <summary>
        /// 用户信息
        /// </summary>
        public class Customer
        {
            /// <summary>
            /// 唯一ID
            /// </summary>
            public string? ID { get; set; }
    
            /// <summary>
            /// 昵称
            /// </summary>
            public string? NickName { get; set; }
    
            /// <summary>
            /// 卡片
            /// </summary>
            public List<string> Card { get; set; }
        }
    
    
        /// <summary>
        /// 房间
        /// </summary>
        public class Room
        {
            /// <summary>
            /// 房间名
            /// </summary>
            public string Name { get; set; }
    
            /// <summary>
            /// 房主id
            /// </summary>
            public string Masterid { get; set; }
    
            /// <summary>
            /// 当前出牌人
            /// </summary>
            public int Curr { get; set; }
    
            /// <summary>
            /// 当前卡片
            /// </summary>
            public List<string> CurrCard { get; set; } = new List<string>();
    
            /// <summary>
            /// 当前卡片打出人
            /// </summary>
            public string ExistingCardClient { get; set; }
    
            /// <summary>
            /// 房间成员列表
            /// </summary>
            public List<Customer> Customers { get; set; } = new List<Customer>();
        }

    tips:只是单纯为了斗D主设计的,商用版肯定不能这么搞,参考请慎用。

    有了数据模型,自然少不了CRUD:

        /// <summary>
        /// 用户操作
        /// </summary>
        public static class CustomerAction
        {
            /// <summary>
            /// 用户列表
            /// </summary>
            private static List<Customer> cusList = new List<Customer>();
    
            /// <summary>
            /// 不存在则新增,存在则修改昵称
            /// </summary>
            /// <param name="customer"></param>
            public static void Create(Customer customer)
            {
                Customer curr = null;
    
                if (cusList.Count > 0)
                    curr = cusList.Where(x => x.ID == customer.ID).FirstOrDefault();
    
                if (curr is null)
                    cusList.Add(customer);
                else
                {
                    curr.NickName = customer.NickName;
    
                    Up4ID(curr);
                }
            }
    
            /// <summary>
            /// 用户列表
            /// </summary>
            /// <returns></returns>
            public static List<Customer> GetList()
            {
                return cusList;
            }
    
            /// <summary>
            /// 获取单个
            /// </summary>
            /// <param name="id"></param>
            /// <returns></returns>
            public static Customer GetOne(string id)
            {
                return cusList.Where(x => x.ID == id).FirstOrDefault();
            }
    
            /// <summary>
            /// 删除用户
            /// </summary>
            /// <param name="id"></param>
            public static void Delete(string id)
            {
                cusList.RemoveAll(x => x.ID == id);
            }
    
            /// <summary>
            /// 增加卡片
            /// </summary>
            /// <param name="id"></param>
            /// <param name="cards"></param>
            public static void InCard(string id, List<string> cards)
            {
                Customer customer = cusList.Where(x => x.ID == id).FirstOrDefault();
    
                if (customer.Card is null)
                    customer.Card = cards;
                else
                    customer.Card.AddRange(cards);
    
                Up4ID(customer);
            }
    
            /// <summary>
            /// 扣除卡片
            /// </summary>
            /// <param name="id"></param>
            /// <param name="cards"></param>
            /// <param name="group"></param>
            /// <returns></returns>
            public static bool OutCard(string id, List<string> cards, Room group)
            {
                Customer client = cusList.Where(x => x.ID == id).FirstOrDefault();
    
                if (client is null)
                    return false;
    
                //卡片不匹配直接失败
                if (client.Card.Where(x => cards.Contains(x)).ToList().Count != cards.Count)
                    return false;
    
                //不符合出牌规则直接失败
                if (!new Game.WithCard().Rule(group.CurrCard, cards, group.ExistingCardClient is null || group.ExistingCardClient == id))
                    return false;
    
                foreach (var item in cards)
                {
                    client.Card.Remove(item);
                }
    
                group.CurrCard = cards;
    
                group.ExistingCardClient = id;
    
                Up4ID(client);
    
                RoomAction.Up4Name(group);
    
                return true;
            }
    
            /// <summary>
            /// 更新(根据ID)
            /// </summary>
            /// <param name="customer"></param>
            /// <returns></returns>
            public static bool Up4ID(Customer customer)
            {
                if (cusList.Count == 0)
                    return false;
    
                cusList.RemoveAll(x => x.ID == customer.ID);
    
                cusList.Add(customer);
    
                return true;
            }
        }
    
    
        /// <summary>
        /// 房间操作
        /// </summary>
        public static class RoomAction
        {
            /// <summary>
            /// 房间列表
            /// </summary>
            private static List<Room> roomList = new List<Room>();
    
            /// <summary>
            /// 新增房间
            /// 如果房间已存在则不新增
            /// </summary>
            /// <param name="group"></param>
            public static void Create(Room group)
            {
                if (!roomList.Where(x => x.Name == group.Name).Any())
                    roomList.Add(group);
            }
    
            /// <summary>
            /// 获取列表
            /// </summary>
            /// <returns></returns>
            public static List<Room> GetList()
            {
                return roomList;
            }
    
            /// <summary>
            /// 获取单个
            /// </summary>
            /// <param name="masterid">房主id</param>
            /// <param name="roomName">房间名称</param>
            /// <returns></returns>
            public static Room GetOne(string masterid = null, string roomName = null)
            {
                if (roomList.Count == 0)
                    return null;
    
                if (masterid != null)
                    return roomList.Where(x => x.Masterid == masterid).FirstOrDefault();
    
                if (roomName != null)
                    return roomList.Where(x => x.Name == roomName).FirstOrDefault();
    
                return null;
            }
    
            /// <summary>
            /// 加入房间
            /// </summary>
            /// <param name="client"></param>
            /// <param name="roomName"></param>
            public static bool Join(Customer client, string roomName)
            {
                if (roomList.Count == 0)
                    return false;
    
                var room = roomList.Where(x => x.Name == roomName).FirstOrDefault();
    
                if (room is null)
                    return false;
    
                if (room.Customers.Count == 3)
                    return false;
    
                room.Customers.Add(client);
    
                Up4Name(room);
    
                return true;
            }
    
            /// <summary>
            /// 删除房间
            /// </summary>
            /// <param name="masterid">房主id</param>
            public static bool Delete(string masterid)
            {
                if (roomList.Count == 0)
                    return false;
    
                var room = roomList.Where(x => x.Masterid == masterid).FirstOrDefault();
    
                if (room == null)
                    return false;
    
                roomList.Remove(room);
    
                return true;
            }
    
            /// <summary>
            /// 更新(根据房名)
            /// </summary>
            /// <param name="room"></param>
            /// <returns></returns>
            public static bool Up4Name(Room room)
            {
                if (roomList.Count == 0)
                    return false;
    
                roomList.RemoveAll(x => x.Name == room.Name);
    
                roomList.Add(room);
    
                return true;
            }
    
            /// <summary>
            /// 更新当前出牌人
            /// </summary>
            /// <param name="roomName"></param>
            /// <param name="index">传入则强制修改,不传按规则走</param>
            public static Customer ChangeCurr(string roomName, int index = -1)
            {
                var room = roomList.Where(x => x.Name == roomName).FirstOrDefault();
    
                if (index != -1)
                    room.Curr = index;
                else
                    room.Curr = (room.Curr + 1) % 3;
    
                Up4Name(room);
    
                return room.Customers[room.Curr];
            }
        }

    因为所有数据都是通过静态属性保存的,所以大部分都是linq操作(原谅我linq水平有限)。

    接下来是游戏逻辑:

        /// <summary>
        /// 卡片相关
        /// </summary>
        public class WithCard
        {
            /// <summary>
            /// 黑桃-S、红桃-H、梅花-C、方块-D
            /// BG大王,SG小王,14-A,15-2
            /// </summary>
            readonly List<string> Cards = new List<string>()
            {
                "S-14","S-15","S-3","S-4","S-5","S-6","S-7","S-8","S-9","S-10","S-11","S-12","S-13",
                "H-14","H-15","H-3","H-4","H-5","H-6","H-7","H-8","H-9","H-10","H-11","H-12","H-13",
                "C-14","C-15","C-3","C-4","C-5","C-6","C-7","C-8","C-9","C-10","C-11","C-12","C-13",
                "D-14","D-15","D-3","D-4","D-5","D-6","D-7","D-8","D-9","D-10","D-11","D-12","D-13",
                "BG-99","SG-88"
            };
    
            /// <summary>
            /// 发牌
            /// </summary>
            public List<List<string>> DrawCard()
            {
                List<string> a = new List<string>();
                List<string> b = new List<string>();
                List<string> c = new List<string>();
    
                Random ran = new Random();
    
                //剩3张底牌
                for (int i = 0; i < 51; i++)
                {
                    //随机抽取一张牌
                    string item = Cards[ran.Next(Cards.Count)];
    
                    switch (i % 3)
                    {
                        case 0:
                            a.Add(item);
                            break;
                        case 1:
                            b.Add(item);
                            break;
                        case 2:
                            c.Add(item);
                            break;
                    }
    
                    Cards.Remove(item);
                }
    
                return new List<List<string>>()
                {
                    a,b,c,Cards
                };
            }
    
            /// <summary>
            /// 规则
            /// </summary>
            /// <param name="existingCard"></param>
            /// <param name="newCard"></param>
            /// <param name="isSelf"></param>
            /// <returns></returns>
            public bool Rule(List<string> existingCard, List<string> newCard, bool isSelf)
            {
                //现有牌号
                List<int> existingCardNo = existingCard.Select(x => Convert.ToInt32(x.Split('-')[1])).ToList().OrderBy(x => x).ToList();
    
                //新出牌号
                List<int> newCardNo = newCard.Select(x => Convert.ToInt32(x.Split('-')[1])).ToList().OrderBy(x => x).ToList();
    
                //上一手是王炸,禁止其他人出牌
                if (existingCardNo.All(x => x > 50) && existingCardNo.Count == 2)
                {
                    if (isSelf)
                        return true;
                    else
                        return false;
                }
    
                //王炸最大
                if (newCardNo.All(x => x > 50) && newCard.Count == 2)
                    return true;
    
                //单张
                if (newCardNo.Count == 1)
                {
                    if (existingCardNo.Count == 0)
                        return true;
    
                    if ((existingCardNo.Count == 1 && newCardNo[0] > existingCardNo[0]) || isSelf)
                        return true;
                }
    
                //对子/三只
                if (newCardNo.Count == 2 || newCardNo.Count == 3)
                {
                    if (existingCardNo.Count == 0 && newCardNo.All(x => x == newCardNo[0]))
                        return true;
    
                    if (newCardNo.All(x => x == newCardNo[0]) && (isSelf || newCardNo.Count == existingCardNo.Count && newCardNo[0] > existingCardNo[0]))
                        return true;
                }
    
                if (newCard.Count == 4)
                {
                    //
                    if (newCardNo.All(x => x == newCardNo[0]))
                    {
                        if (existingCardNo.Count == 0 || isSelf)
                            return true;
    
                        if (existingCardNo.All(x => x == existingCardNo[0]) && existingCardNo.Count == 4)
                        {
                            if (newCardNo[0] > existingCardNo[0])
                                return true;
                        }
    
                        return true;
                    }
    
                    //三带一
                    {
                        List<int> flagA = newCardNo.Distinct().ToList();
    
                        //超过2种牌直接失败
                        if (flagA.Count > 2)
                            return false;
    
                        //没有上一手牌,或者上一手是自己出的牌
                        if (existingCardNo.Count == 0 || isSelf)
                            return true;
    
                        int newCardFlag = 0;
    
                        if (newCardNo.Where(x => x == flagA[0]).ToList().Count() > 1)
                        {
                            newCardFlag = flagA[0];
                        }
                        else
                            newCardFlag = flagA[1];
    
                        List<int> flagB = existingCardNo.Distinct().ToList();
    
                        //上一手牌不是三带一
                        if (flagB.Count > 2)
                            return false;
    
                        int existingCardFlag = 0;
    
                        if (existingCardNo.Where(x => x == flagB[0]).ToList().Count() > 1)
                        {
                            existingCardFlag = flagB[0];
                        }
                        else
                            existingCardFlag = flagB[1];
    
                        if (newCardFlag > existingCardFlag)
                            return true;
                    }
                }
    
                if (newCard.Count >= 5)
                {
                    bool flag = true;
    
                    for (int i = 0; i < newCardNo.Count - 1; i++)
                    {
                        if (newCardNo[i] + 1 != newCardNo[i + 1])
                        {
                            flag = false;
                            break;
                        }
                    }
    
                    //顺子
                    if (flag)
                    {
                        if (existingCardNo.Count == 0 || (newCardNo[0] > existingCardNo[0] && newCardNo.Count == existingCardNo.Count) || isSelf)
                            return true;
                    }
                }
    
                return false;
            }
        }

    单张规则和普通斗D主一样(除了王以外2最大,其次是A),多张规则目前支持:王炸、对子、三只、顺子、三带一。目前只做到这里,各位同学可以拿回去自行扩展。

    上一些运行图。房主建房并加入:

    新玩家加入:

    房间人满以后房主开始游戏,随机分配地主:

    出牌特效:

    游戏结算:

    最后附上开源地址(客户端在web分支):https://gitee.com/muchengqingxin/card-game

    tips:前端同学在没有UI配合的情况下做到现在这样,必须给个赞。最后提醒大家,不要拿去商用。

    声明:未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则视为侵权。
    本文原创发表于博客园,作者为暮城倾心。欢迎转载。Donation(扫码支持作者)↓

    微信
    支付宝
  • 相关阅读:
    第五天
    第四天
    第三天
    四则运算2
    对于搜狗输入法
    用户及用户场景分析
    总结
    第一阶段总结
    第七天
    第六天
  • 原文地址:https://www.cnblogs.com/muchengqingxin/p/15612678.html
Copyright © 2011-2022 走看看