WPF 万维网对战象棋 客户端+服务端(全套可执行代码在文章末尾)

一直以来想做一款游戏应用,但是又没有游戏的专业开发知识和技术,只能开发界面比较简单的游戏了,象棋游戏就是不错的选择。

首先看看界面如下。我们打开两个客户端

 

 

 在服务端通过登陆,会新建两个用户保存到服务端,然后客户端获取下在线的用户列表。

邀请对局:

 

进入游戏房间

 

 

 

 

1.如果搞定通信?

对于Socket不太熟练的我,选择了websocket,然后再.net core中有不错的选择那就是signalr core了,使用简单,而且对于客户端接入也方便,也可以全异步。

我们可以实现一个Server,使用.net core接入signalr,然后实现一个集线器。

Startup.cs中添加中间件和服务配置。

 

 

 在对应的ChatHub中进行相应的消息事件的注册声明。

private static List<Item> Items = new List<Item>();

        private static List<string> ChessGroups = new List<string>();
        public async Task<IEnumerable<User>> Login(User user)
        {
            //从在线集合中去除此人
            Items.RemoveAll(o => o.user.UserId == user.UserId);
            Items.Add(new Item()
            {
                Id = Context.ConnectionId,
                user = user
            });

            return Items.Select(o => o.user);
        }

        public async Task<IEnumerable<User>> RequestList()
        {
            return Items.Select(o => o.user);
        }

        public async Task<string> GameRequest(string source, string target)
        {
            //从在线集合中去除此人
            var temp = Items.FirstOrDefault(o => o.user.UserId == source);
            if (temp == null || temp.user.Status == Status.WORKING)
                return "状态异常";

            var user = Items.FirstOrDefault(o => o.user.UserId == target);
            if (user == null)
            {
                return "对方不在线!";
            }

            if (user.user.Status == Status.WORKING)
            {
                return "对方正在对局中!";
            }

            await Clients.Client(user.Id).SendAsync("GameRequest", source);

            return "SUCCESS";
        }

        public async Task<string> ReceiveRequest(string receiver, string beginner)
        {
            //如果接受则不能接受其他的
            //从在线集合中去除此人
            var temp = Items.FirstOrDefault(o => o.user.UserId == receiver);
            if (temp == null || temp.user.Status == Status.WORKING)
                return "状态异常";

            var user = Items.FirstOrDefault(o => o.user.UserId == beginner);
            if (user == null)
            {
                return "对方不在线!";
            }

            if (user.user.Status == Status.WORKING)
            {
                return "对方正在对局中!";
            }

            temp.user.Status = Status.WORKING;
            user.user.Status = Status.WORKING;

            var groupName = $"{receiver}-{beginner}-{DateTime.Now.ToLongTimeString()}";
            //双方状态正常则开始对局
            await Groups.AddToGroupAsync(temp.Id, groupName);
            await Groups.AddToGroupAsync(user.Id, groupName);
            await Clients.Group(groupName).SendAsync("BeginGame", beginner, receiver);
            ChessGroups.Add(groupName);

            return "SUCCESS";
        }

        public override Task OnDisconnectedAsync(Exception exception)
        {
            Items.RemoveAll(o => o.Id == Context.ConnectionId);
            return base.OnDisconnectedAsync(exception);
        }

        public async Task<string> Action(Point oldPoint, Point newPoint, string receiver)
        {
            var temp = Items.FirstOrDefault(o => o.user.UserId == receiver);
            if (temp == null || temp.user.Status != Status.WORKING)
                return "状态异常";

            await Clients.Client(temp.Id).SendAsync("ReceiveLocation", oldPoint, newPoint);
            return "SUCCESS";
        }

        public async Task GameOver()
        {
            var temp = Items.FirstOrDefault(o => o.Id == Context.ConnectionId);
            if (temp == null || temp.user.Status == Status.FREE)
                return;

            temp.user.Status = Status.FREE;

            foreach (var group in ChessGroups)
            {
                if (group.Contains(Context.ConnectionId))
                {
                    await Groups.RemoveFromGroupAsync(Context.ConnectionId, group);
                }
            }

            ChessGroups.RemoveAll(o => o.Contains(temp.Id));
        }

        public async Task Exit(string receiver) 
        {
            var temp = Items.FirstOrDefault(o => o.Id == Context.ConnectionId);
            if (temp == null || temp.user.Status == Status.FREE)
                return;

            var target = Items.FirstOrDefault(o => o.user.UserId == receiver);
            if (target == null || target.user.Status == Status.FREE)
                return;

            temp.user.Status = Status.FREE;
            target.user.Status = Status.FREE;

            foreach (var group in ChessGroups)
            {
                if (group.Contains(Context.ConnectionId)|| group.Contains(target.Id))
                {
                    await Groups.RemoveFromGroupAsync(Context.ConnectionId, group);
                    await Groups.RemoveFromGroupAsync(target.Id, group);
                }
            }

            await Clients.Client(target.Id).SendAsync("OtherExit");
        }

2.如何搞定客户端?

对于WPF我还是比较熟悉的,但是WPF的绘画和动画我就不太了解了,于是我使用了一个网上大神写的比较不错的棋盘用户控件,做了部分修改(主要是重开游戏会导致卡死的问题)

后来发现是界面某个依赖属性导致的

大神链接如下。我只是使用了其中的棋盘用户控件:

 https://www.cnblogs.com/Curry/archive/2009/05/06/1450383.html 

3.业务逻辑

使用MVVMLight自带的MVVM和消息机制,实现逻辑和界面分离,各模块调用通过消息实现。

接受对局等方法。

//开启接收游戏请求接口
                Const.Connection.On<string>(GameRequest, async (str) =>
                {
                    var result = MessageBox.Show("有人邀请你来一局,是否接受?", str, MessageBoxButton.YesNo, MessageBoxImage.Question);
                    if (result == MessageBoxResult.Yes)
                    {
                        var tempResult = await Const.Connection.InvokeAsync<string>(ReceiveRequest, Const.User.UserId, str);
                        if (tempResult != "SUCCESS")
                        {
                            MessageBox.Show(tempResult, "WARNING", MessageBoxButton.OK, MessageBoxImage.Warning);
                        }
                    }
                });

                Const.Connection.On<string, string>(BeginGame, (beginner, receiver) =>
                 {
                     ChessWindow window = new ChessWindow();
                     window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                     var vm = new ChessWindowViewModel(beginner == Const.User.UserId, beginner == Const.User.UserId ? receiver : beginner,window.chesscontrol.Chessboard);
                     window.DataContext = vm;
                     window.Show();
                 });

 

 

详细代码直接运行即可跑起来:https://github.com/BruceQiu1996/Chess

如果觉得可以希望给个Star!!!.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章