前言
好友没有写博客啦。没啥可说的,就是因为懒。今后几篇为大家带来一个俄罗斯方块游戏的实现,网上有很多类似博客,大致原理一致,我自己想的思路也没有多大的偏差。不过我稍微加了一些联机元素在里面。先放一张效果图吧,我不会做界面,就酱紫了,不改了。
主要功能
- 单机版的俄罗斯方块游戏体验:即俄罗斯方块游戏的基础实现,方块定义,方块旋转等
- 联机两人(或多人)一起玩游戏,增加竞技乐趣
- 类似游戏大厅的功能,玩家可选择房间进入
- 消息推送功能,联机必备
- 方块界面由canvas实现
开发准备
首先我们要开发一个联机游戏,那么消息推送是必不可少的,由于我只会一丢丢的WebSocket,那我只好用它了。另外这次还是使用了 tio 框架。tio-http-server tio-ws-server 都有用到。第二,就是俄罗斯方块的游戏分析。其实游戏名称里的”方块“就能给我们带来思路。整个游戏界面就是一个布满200(10 * 20)个坐标点的一个数组。下面画一个图,方便大家了解。
开发参考图:
上图中分别用不同的坐标组合表示出相应的形状。那么我们的方块还有旋转功能,这就要考虑到旋转方向的问题,根据旋转方向和当前状态是否可以旋转来进行旋转操作。
请看下图:
我以这种类型的方块为例子讲解一下旋转过程。首先,我定义了一个规则,就是一个方块由四个坐标点组成,然后他们的排序规则为从上到下,从左到右。如上图中标注出的序号。那么当我们对该方块做”右转“操作时候。最关键的,我们要找到第一个点在哪里,那么后续就好说了。看一下右转的代码:
case UP:
//第一个点不变
// points[0] = points[0];
//第二个点在第一个点下面
points[1] = points[0].down();
//第三个点在第一个点右边
points[2] = points[1].right();
//第四个点在二个点下面
points[3] = points[1].down();
blockStatus = BlockStatus.RIGHT;
break;
所以,旋转代码就变得很简单了,先确定第一个点,然后根据图形规则,分别找到其他的点。上述代码中的down,right等方法,其实就是一个 x+-1 或者 y+-1的操作。其他旋转同理,不过要注意好中心点的位置,否则会出现转了几圈之后,方块不走直线的情况。
方块构造好并且可以旋转之后,下面要做的就是细活了。第一:方块什么时候停止,第二:方块什么时候消除,消除之后怎么处理其他方块。第三:方块什么时候不能旋转。
方块和地图的关系
下面我一一解答上节遗留的问题。
方块停止的条件:1.碰到地图最下边缘 2.方块碰到其他的方块。 第一个很好理解,方块到底下了,就要停下。(一个方块中四个点任意一个点碰到地图底部都会停下)
//一个点的Y值 = 地图界限值
private static boolean onBottom(Point point){
return point.getY() == GameMap.MAX_RANGE_HEIGHT - 1;
}
第二个,方块碰到其他的方块,就是说,比如游戏中已经积累了很多方块,那么新的方块要落到其他方块之上,所以判断一下方块下一步的移动轨迹是否与已经停止的方块的点有重合,如果有重合,那么方块不能继续移动。不管是向下、向左、向右、旋转,都用此方法判断。
方块消除的条件:这个就很简单了,当达到满行之后进行消除。如下图所示:
黄色区域需要消除掉,然后处理加分逻辑。消除掉之后呢,需要将其他的点(Y值 < 当前消除行的Y值)的Y值 + 相对应的行数。为什么说是相对应的行数呢?因为有的点下方只消除了一行,有的点下方消除了两行或者多行,那么根据行数来改变点的Y值。上图中,黄色行以上的点的Y值都需要加1.
方块的操作
方块有上(变形)下(加速)左(左移)右(右移)四种操作。变形和左右移就是一些点的坐标替换。变形已经在上文中讲过了,左右移和加速其实道理一样。就是一个块中的所有点的X+-1或者Y+1.
操作响应
操作之后,用户要有回馈,否则,服务器数据变化了,用户得不到回馈,就会出现类似网游中的卡顿现象,或者其他bug,体验非常不好。响应流程后续在讲。
游戏的运行
通过ScheduledExecutorService 的 scheduleWithFixedDelay 方法达到周期刷新游戏界面的效果,同样,服务端每刷新一次,如果用户不做任何操作的话,方块会自动向下移动一格。然后推送到用户端。
总结
其实俄罗斯方块的实现原理并不难,只是需要考虑的细节比较多,而且根据我的代码运行情况,还时不时出现bug。。。我猜测和多线程有关。唉,多线程,并发,异步等是我的弱项,我还得在研究研究。不知道这么讲解大家能否看得懂呢?不懂的或者有其他疑问的可以留言。拜拜~~