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!!!.

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