【游戏框架系列】2048

文章详细阐述了2048游戏的实现方式,包括使用4x4数组作为数据结构存储游戏状态,通过算法处理上下左右移动,判断合并,以及对不能合并的方块进行移动。此外,还介绍了游戏中的动画实现,利用额外的GUI对象来模拟方块移动的动画效果,并讨论了在编程过程中遇到的Lua、Direct2D和Win32API的相关问题。
摘要由CSDN通过智能技术生成

现在来讲下2048是怎样实现的。

首先,我们看界面,它就是个4x4的方块,显而易见,用4x4数组或1x16数组就能搞定。那么数组里面存什么呢?我们分析2048中的数值:空方格、2的幂次数值方块,就两种。解决方案是只要存int——空方格对应0;2的幂就对应它的幂。所以:空=0,2=1,以此类推,2048=11。因此数据结构非常简单,随便用伪代码表示:[2048-Table] = array(4x4)。

知道了数据结构,那么接下来就是算法,这是难的部分。

算法需要解决一些问题:

处理每次的上下左右动作。这个是核心功能,有几个方面。一、判断是否要合并;二、不合并的话就将方块向前推到边上,直到推不动为止;三、随机位置增加新方块。
确定当前是否为死局。这个简单,只要遍历4x4数组,看是否存在相邻的连续数值的方块。
下面解决主要问题。

一、判断是否要合并

假如当前按下Left键,方块向左移动,假如某行是“2-2-4-4”,那么结果是“4-8-0-0”,因为只需要合并相邻的方块;若是“2-2-2-2”,结果是“4-4-0-0”,不会是“8-0-0-0”,这是由算法决定的。

那么问题变简单了,正如memcpy所做的,如果memcpy(src,dst),其中src和dst有交界部分。若src在dst前面,那么应该从后向前复制,反之是从前向后。

同理,方向为Left时,对于“2-2-4-4”,是从左向右遍历,先确定“2-2”,将其换为4,变成“4-0-4-4”,然后处理右边两个4。此时,左起第一个4其实已经合并过了,将其排除,所以当前只要处理“0-4-4”,那么再将当中的4移至最左,成为“4-0-4”,再处理第二个4,由于第一个4尚未合并过,因此两个4再进行合并,成为8。最后结果“4-8-0-0”。

整理一个过程:Left,2-2-4-4,加[]表示已合并过,无需再次合并。2-2-4-4 => [4]-0-4-4 => [4]-4-0-4 => [4]-[8]-0-0。

二、对不能合并的方块进行移动

如“2-4-6-0”,方向Right,从右向左遍历。过程为:2-4-6-0 => 2-4-0-6 => 2-0-4-6 => 0-2-4-6。解释略。

三、随机增加新方块

增加新方块,添加2和4的概率比为9比1,用随机数实现。

然后需要寻找空位添加,这简单,遍历4x4数组,找到数值为0的将其位置记录,接着随机抽位子。


2048的动画实现机制
花了一天实现了方块的移动,也有难度。

项目相关:布局只支持新增GUI对象,不支持删除,因此需要一开始就创建好。

思路:原4x4中每个方块对应一个GUI对象(记作origin),另外再新建4x4的GUI对象(记作anime),用于实现动画。

例:当前2-2-4-4,方向Right,结果为0-0-4-8。设计动画,假设[n]代表从左起第n个位置。

方块移动:[1,2,3,4] => [3,3,4,4]。那么当第一个2(位置为[1])进行移动时,这时应该将origin方块隐藏,将替身anime方块代替origin位置并显现,随后播放动画,将anime的位置从[1]逐渐移动到[3],移动完毕后,主角origin上场,替身anime下场。

总结一下:当origin需要移动时,召唤替身anime到指定位置,替身移动,最后替身消失,origin在替身消失的地方出现。替身移动其实就是插值思想。

另外,为防止动画没有播放完程序仍接受游戏指令导致逻辑乱套,因此在动画播放期间用户输入无效,不然动画就会出问题。

总结一下编写简单的游戏框架并用其实现2048整个过程中的问题。

Lua的坑。由于对它不熟悉,走了些弯路。Lua中统一用double保存整型与浮点,所以输出整数就要进行转换。再者就是类的问题,目前的问题是切换场景后,文本框的内容没有重置。
D2D的坑。D2D的文档比较少,学着费劲。要注意RenderTarget无效问题,无效后必须马上重新创建,连带之前的画刷、图片、文字等对象要全部重建。
Win32的坑。这已经见怪不怪了,一个字,略。
那么整体的思路是:

交互层,将Win32消息进行封装,对每个消息调用Lua进行处理。这里比较重要的是窗口改变大小问题,将大小改变时,UI也要跟着改变、跟着放缩,不过UI的问题我全部用Lua脚本去做,省去不少麻烦。
逻辑层,主要是Lua脚本的模块化构建。我的思路:根为场景(Scene),场景下有GDI对象(GdiObject),每个GDI对象可以包含其他GDI对象,组成树结构。场景切换时,GDI树销毁并创建新的。还有一个就是布局(Layout),这里的思路比较经典,掌握基本的递归方法就可以写成。布局里有绝对布局、线性布局、表格布局,都比较简单,这些布局会自动调整成员的大小。
渲染层,不多说,能用现成的就用。像画纯色矩形算简单,涉及富文本就复杂了,因此我暂时不考虑富文本情况,画画基本的几何图形就足够。这方面不算重要的内容。
阶段性目标

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值