Qt新手的真实——原地写一个项目有多痛苦(4 X 4 斗兽棋)

1. 前言&资源链接

        大家好,我是Akgry,阿克已经很长时间没有更新博客了,那么在这么长的一段时间里,阿克究竟干了什么,其实阿克一直在攻克Qt。如果有读者是阿克的朋友的话,那么你一定知道阿克是一个非常要强的男人(又菜又爱玩),阿克之前的几个Qt项目里,无一例外都是别人已经设计好的项目二次开发,虽然阿克弄得很通透,而且能自己敲出来,但始终觉得二手货,心理不舒服,精神洁癖了属于是。于是呢在两个月前的一个夜晚,阿克坐在宿舍的窗前,眺望着东北冷酷的春冬,决定徒手搞一个项目出来。殊不知,正是这个鲁莽的决定,让阿克吃尽了苦头......

资源链接:斗兽棋(客户端&服务端)    ps:阿克换仓库了,github有点难用,目前改用码云

2. 架构介绍 

        这个项目呢叫4X4斗兽棋,说来也挺有意思的,阿克我本来想得是随便写一个那种课设级别的项目,结果做完之后越看越难受,尤其是卡片移动的时候,那效果堪称PPT。所以在进一步学了Qt的动画和坐标图形项后,我重新设计了一下整个项目的架构。如下图所示:

由于时间原因,阿克基本忘了UML图怎么画了,所以这个架构乍一看可能有点牛头不对马嘴,不过请容我细细为你讲解。首先我定义了一个窗口类,继承自QWidget,在这个窗口类里有一个视图,然后我通过展示不同的场景实现切换效果,比如菜单和主界面就是用的欢迎场景,游戏界面用的就是游戏场景,当然有些变化是直接更改场景的属性,否则一个画面设置一个场景,那工作量就太大了。然后是场景切换、按钮点击这些动画,都是通过属性动画来实现的,包括中间的信号槽触发这些。如果说项目到这里就算框架完毕的话,那么接下来的工作才是重中之重。要知道在下棋的时候最关键的两个东西是什么,是棋盘和棋牌,所以我又着手设计了棋盘类和棋牌类,这中间涉及到了许多绘图方面的知识。最后就是管理类了,管理类的主要目的就是控制电脑下棋和网络对战,中间涉及到了大量的算法。

3. 项目介绍&bug

        之所以先介绍项目架构,是为了帮助读者明白这个项目中的不同东西是如何实现的,这样在观看项目效果的时候更加有针对性并且知道问题产生的原因。首先是游戏窗口类,这个类属于是整个项目的核心部分,主要负责场景、场景内图形项和一些必要的成员变量的初始化和变换,如下图所示,这就是窗口类的样子:

当点击了不同的按钮后,就会切换到对应的场景,继续该场景下的初始化工作和操作等,这也是阿克最开始做的内容,这里最危险的地方莫过于信号槽的连接,为何这样说,因为阿克为了偷懒,在连接信号槽的过程中使用了大量的lambda表达式,导致阿克在调试bug的时候叫苦不堪。而且由于程序为了迎合动画播放,使用了较多的QTimer延迟发射信号,这直接导致后续很多信号槽连接出现障碍,原因就是初始化变量的进程还被阻塞中,但是程序已经执行到连接信号槽的地方,这直接导致信号槽紊乱甚至程序崩溃,外加调试困难,这波混合双打之下直接导致阿克前期的开发工作举步维艰。好在阿克头够铁,硬是凭着人肉编译器把bug全都解决了。                                                       有了窗口类后,整个项目的架构算是基本定型了,剩余的工作都将在该架构的基础上进行开发,如果只是追求功能,那么剩下的工作简直可以用势如破竹来形容。但很显然,阿克不是这么随便的人,于是接下来阿克做的任务是设计棋盘类和卡牌类。其中棋盘类是很简单,我直接使用QPainter绘制了4X4的矩形方格线,然后还贴心地镶了一个金边,如下图所示:

原谅阿克找素材的能力,这个金边是阿克从一块金属皮上直接扣的图,有时候阿克真后悔自己不是美术生。其实设计棋盘类的时候也遇到了不少的问题,基本都是坐标系方面的,因为阿克着手项目开发的时候是一边看Qt的图形项资料,一边开发项目,基本是逮到能用的接口就用,然后三重坐标系(视图、场景、图形项)的坐标转换、初始化基本是一路试错闯过来的,不过这些问题跟开发卡牌类比起来就是小巫见大巫了。如果说阿克在整个项目上花费时间最久的部分,一个是管理器的开发,另一个就是卡牌类了。卡牌类遇到的第一个问题和棋盘类一样,都是坐标系方面的,毕竟两者都继承自QGraphicsItem,但卡牌类的开发比较幸运,因为阿克歪打正着刚好把坐标都用对了,当时阿克自己都觉得很纳闷,自己写的代码自己看不懂,但怎么偏偏就跑起来了。顺带吐槽一句,Qt图形项的坐标系有时候确实挺反人类的。卡牌类最初只是设计了样式、动画、事件重写,后续由于管理器的需要,又额外添加了一些内容。动画和样式算是小kiss,那都属于Qt入门的知识了,我觉得比较坑的是事件重写,其中需要注意的细节太多了,阿克大部分事件都浪费在分析事件特性上,而且最终也没有达到最初想要实现的效果,最后不得已采用了键鼠合并操作的方法实现卡牌移动。那么卡牌类到底是个什么效果,如下图所示:

可以看到这个卡牌阿克制作的还算挺精良吧,唯一的遗憾阿克实在不知道怎么做卡牌翻面的动画,因为这些东西涉及到了美术方面的几何知识,甚至可能需要用到3D效果,所以就放弃了。最终决定把卡牌的翻面效果改为闪烁。

4. 核心介绍

        现在介绍一下本次项目的核心部分,管理器,其实主要是人机对战部分的管理器,线上的管理器主要是针对线下管理器的一个多态处理。而且线上管理器我觉得反而比较简单,因为它不涉及机器人的博弈算法的设计,只需要通过TCP套接字向服务器传输数据即可。那么正如刚才所说,在没有合适的设计模式的情况下,阿克设计的管理器怎么样呢。烂,一个字烂!虽然功能完整,健壮性不错,但从代码的可读性和架构上看,实在是太糟糕了。算法的设计部分其实还好,但架构是真的很奇怪,阿克这里真的很难用语言描述这个架构是如何运行的,大概就是卡牌移动后会产生一个信号,管理器收到这个信号后根据步长属性分析这个操作是谁做的,然后将下一步棋的权力交给另一方进行下棋。最终也证明这是个相当失败得架构,在调试普通bug的时候遇到了相当大的困难,同时为了迎合权力转换期间渲染事件的正常结束,又再次使用了大量的QTimer延时发射信号,使得后续信号与槽得连接受到了不小的阻力,外加阿克还偏爱使用lambda表达式连接信号与槽,开发的难度可想而知。至于算法方面,阿克就不做过多介绍了,读者后续在仓库下载完代码后可以理解。当然核心部分还包括服务端搞协议解决粘包问题,但是很顺利并没有遇到什么太大的问题,基本任务就是处理客户端发来的语句,根据逻辑对客户端通信。理论上来说服务端用黑窗口输出就够了,但阿克最终还是决定稍微设计一下服务端。如下图所示:

5. 总结 

        项目总共有3000多行代码,可能没有介绍完全部功能,但这次事件也告诉大家,新手期间不要轻易尝试去从零开始手写一个项目,因为中间涉及到许多巧妙的架构和优化方法,这需要长期的工作经验来弥补。 感谢读者观看,关注博主,更多项目持续分享。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员Akgry

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值