第一次发表博客有点紧张啦!那么今天我们就来讨论一下面向对象中对推箱子小游戏的一个思考。
以下来源于自己的一个作业,可能想法和分析不够完善,如果您有其他想法,欢迎批评交流。
在推箱子的小游戏中,我设置了两个类Board类和Object类。Board类用提供生成游戏界面和进行游戏的方法,而Object类则是地图上的不同物品。
在写这个游戏的时候,我发现这个游戏清晰的由两部分组成,第一是由棋盘,第二是由物品(包括人,箱子,墙,空白),而棋盘上包含了这些东西。因此,我可以暂且设计两个类Board和Object。再考虑棋盘,游戏中只需要一个棋盘就行了,每局地图的不同我们可以用指针指向不同的物品来形成。然后考虑Object类,看能否派生出子类。由于该游戏只需要控制人的移动(箱子的移动是由于人的移动产生的),所以我们只需要一个移动以及判断移动的函数。再加上这些Object除了名字以外并没有区别,所以并不需要派生出子类,我们仅仅需要在类中添加一个flag标记Object的种类即可。然后考虑如何进行移动,由于棋盘上Object的种类和数量是既定的,所以我们只需要固定数量的对象,然后每次改变棋盘每个位置指向的对象即可。
然后我们再来找Object有没有其他共性。我们可以发现,由于空白(space)和目的地都是可以走人(以及箱子的),则我们可以再用一个bool变量state标记来区别他们,将目的地看成是一个特殊的space(或者是object,后面你会发现为什么这样说)。若为true,则它为目的地。到了这一步以后,我们很自然的发现,我们同样可以用state来区分箱子是否已经在目的地里了,因此判断方法变得更为简洁。
在前面说到了,我们可以交换两个pointer指向的对象来实现移动,那么如果人与目的地发生交换或者箱子与目的地发生交换时,指针指向改变,那不是目的地的位置也移动了吗?和前面提到的一样,由于棋盘上的object是既定的,那么state标记为true的object的数量也是固定的,我们可以每次成功移动都先交换object的state,在进行指针的交换,那么目的地的位置就是固定的。到了这里,你会发现目的地其实就是state为true的object(因为墙不发生移动,所以不参与到state的交换),我们每次交换state的过程也就是保证目的地固定的过程(即棋盘上某点指向的对象的state总为true)。
思考完怎么移动后,我们来考虑移动的规则(因为你只有知道方式,才能去思考该方式对应的规则)。人的每次移动,无非就是三种情况:遇到space(空白),wall(墙)和box(箱子)(按照上述的思路,我们已经认为目的地是特殊的Object,所以不考虑在内),遇到空白很简单,直接按上述移动方式交换;遇到墙不移动;遇到箱子时,因为箱子可以移动(但不可以自发移动),那么此时我们可以将箱子视为人再用人的判断规则去判断(唯一的区别就是如果此时前面也为箱子那么不移动)。我们先判断箱子,若箱子可移动则说明人也可移动,那么先移动箱子再移动人。
解决了移动方法和移动规则后,只剩下判断是否胜利或者是否失败。这就很简单了:若每个箱子都在目的地上(及每个箱子的state均为true)则胜利;若任意一个箱子的任意两边都是墙,则肯定失败。
下面附上代码。