在GitHub上看到react-tetris版本的俄罗斯方块,长这样的:
好炫,我也要做一个,心里产生了这样的想法。然后就有了经典俄罗斯方块(Android版)。 项目地址:https://github.com/1qu212/Tetris。
界面使用GridView的想法来自Android使用GridView实现简单的俄罗斯方块。
左侧界面和右侧下一个方块片使用的是GridView;每一个方格是使用selector做的;分数、等级、最高分的数字显示使用了特定字体;按键则使用了selector;游戏结束的动画使用了react-tetris中的图片,使用美图秀秀裁成需要的四张图片,合成了一个帧动画==利用canvas.drawBitmap(mBitmap, src, dst, null)自定义view达到动画效果==。
使用数组来代表方块片的每一个值(明或暗),方块片类Piece提供了长度为16的数组代表一个4x4的方块片,也提供了长度为8的数组代表一个4x2的方块片。
方块片旋转后的形状是有限的,这样也就可以使用有限的数组来代表方块片。Piece提供了一个随机的初始状态及代表该状态下方块片的数组(方块片的初始状态必然是能代表4x2方块片的一种状态)。
Piece提供了获取下一个状态数组、上一个状态数组的方法,这为后面方块片旋转做的工作;提供了方块片在界面中刚下落时方块片左下角在界面中的位置;以及提供一个验证是否超出列范围的方法isCollision。
可以使用PieceFatory类来随机生成方块片。
会进行一些赋值,界面显示,会从SharedPreferences中获取一些需要展示的数据。
自动下落使用了一个Timer定时器执行定时任务来完成,这个定时任务就是与down按钮一样发送DOWN指令。
按钮点击事件就是通过发送各自的指令交给handler处理。
我采用了HandlerThread+Handler的方案,这样单子线程处理,在未执行完一个指令之前不会执行下一个指令。使用子线程的原因,一是需要处理计算,更重要的是后面处理消除行动画以及重玩动画需要Thread.sleep()。当然后面界面的显示以及右侧下一个方块片的显示,都是发送指令到UI线程中的Handler处理。
左侧界面也是一个数组,方块片也是一个数组,把方块片的数组元素赋值给界面数组中对应位置上代表空白的数组元素,然后更新界面显示。
向上就是改变方块片的状态,调用Piece提供的方法;向左就是方块片左下角在界面中的列数减一;向右就是方块片左下角在界面中的列数加一。执行指令后可能方块片可能会与界面相撞,如果相撞则恢复原来位置;如果不相撞,则更新界面显示。
界面空白处有方块片的四个亮方块,则代表不相撞; 在界面最上面的相撞情况比较复杂,交给方块片来处理,如果方块片亮方块在超出了界面的列范围,则代表相撞。
如果界面亮方块处,也有方块片的亮方块,则代表相撞; 除以上情况,其他情况也代表相撞。
另外,如果界面亮方块处相撞的行数小于等于方块片在界面中初始化时的行数,则代表游戏结束,这里==游戏结束时返回不相撞==是为了防止游戏结束还在检测是否触底,以及其带来的右侧方块片的刷新。
有三种情况都会发送DOWN指令,一自由下落,二按向下按钮下落,三按掉落按钮下落。按掉落按钮会使用一个Timer定时器来快速定时发送DOWN指令。
当下落时相撞,则代表着触底。触底后需要处理消除满行,以及更新分数,更新下一个方块片。
如果一行中有列数个亮方块,则这行满了,需要消除。这里消除动画采用了将这一行忽明忽暗显示。每多消除一个满行,每行消除增加的分数会多20。一次消除任务执行后,每行消除增加的分数又变回100。
右侧方块片是使用的4x2的数组,每当“下一个”更新的时候,会把其4x4数组的形式赋值给显示在左侧界面中的方块片。
这几个指令发出后,上下左右掉落几个按钮会在disenable和enable状态间切换,以及定时器的暂停、新建的切换。
以下几种情况都需要发送这几个指令: 点击暂停按钮后; 点击重玩按钮后; 处理方块片触底时。
点击重玩按钮会发送RESTART指令,定时器会暂停,左侧界面会从下至上变亮,再从上至下变暗,然后初始化一些数据并新建定时器。
游戏结束,暂停计时器,展示一个帧动画,然后使用SharedPreferences保存一些游戏数据。