zoukankan      html  css  js  c++  java
  • 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!!!.

  • 相关阅读:
    PHP的命令行脚本调用
    JAVA使用jar命令制作可执行GUI程序
    PHP的代理模式
    PHP中的__clone()
    PHP使用反射动态加载第三方类
    NAT小记
    JAVA睡眠理发师代码记录
    PHP通过反射获得类源码
    PHP中单引号双引号的区别
    [转载]PHP导出数据库数据字典脚本
  • 原文地址:https://www.cnblogs.com/qwqwQAQ/p/14281665.html
Copyright © 2011-2022 走看看