Tetris 俄罗斯方块 设计与源码

记不得从哪个网站上看到的了(貌似gamedev.net),说Tetris(传说中的俄罗斯方块)应该是每个游戏初学者的首款作品。无论如何,它确实包含了很多游戏的基本元素,做一个优秀的Tetris也并不容易——当然,我写的这个就比较容易~

这个Tetris的算法并不算最好的,它只是我目前对游戏结构的理解的一种表现,并且引入了一些软件工程的理念——当然,仓促写作它的根本原因是2006年的情人节作为礼物送给我的女友。

 

源码:http://blog.matrix.org.cn/resources/fantasydog/Tetris.zip

打包好的可发布文件:http://blog.matrix.org.cn/resources/fantasydog/deployed.zip

 

1.      
平台

这个游戏是建立在j2me平台上的。当然,由于软件工程的理念的原因,大多数核心的类于平台无关,因此易于移植(当然只是易于,并没有人真正会去移植它吧)。

2.      
Engine

EngineSplashScreen都来自Jason Lam的书J2ME &
Gaming
http://www.jasonlam604.com/books.php#j2megaming

这是一本很好的入门书籍,当然,他提供的例子都是相当精炼有效的。

 

我把Engine做在了Canvas里:GameCanvas<|---Engine<|---TetrisCanvas

这样做违反了SRPSingle Responsibility
Principle [for a class]
),不过这样做可以减少不少的复杂度,继承的关系也很大程度的分离了CanvasEngineResponsibility,还是可以一用的(在这样简单的游戏里)。

3.      
结构

之前写过几个游戏,发现MVC模式似乎并不适合游戏,特别是2d的游戏,因为游戏中大多数元素的内在结构与行为与它的View息息相关——特别是碰撞测试之类。前面提到的那本书中所使用的模式也并不明朗,似乎并不是什么成型的模式,但比较适用于游戏:游戏的各个表现元素维护自己的状态和ViewEngine只负责安排什么时候画它,要画的时候把画笔给它自己画好了。于是有了下面三个主要的部件:

a.               
CanvasEngine):Engine的作用是Engine类提供的,Canvas主要负责设备信息的初始化(屏幕尺寸,根据游戏的要求计算基本的pixel——一个方块占多少个像素,等),各部件的运作顺序,一些信息的显示(当前分数等)。

b.               
Pattern:不是模式,而是图画的意思。对Tetris的元素进行分层,由远到近可分为背景、现有的图案(方块残渣?)和正在下落的方块。鉴于现有的图案在方块下落时(游戏的大部分时间里)是和背景一样不会动的,就把背景和现有的图案做在了一起,成为Pattern

²       
在绘图的时候,Pattern里做一个mutableimagePattern的内容发生变化了就更新一次这个image,每次做gameRender的时候直接把这个image画上去就ok了。如前所述,游戏大部分时间里是活动的方块在运动,而不是Pattern在变化,因此用个image可以提高不少效率。

²       
闪烁效果:由Canvas控制。调用Patternpaint函数中有个boolean变量告诉Pattern是否要闪烁。如果要,就对满行做闪烁绘制,否则画image。(怎么闪烁?每帧画不同的颜色嘛)

c.               
Brick:下落的方块,没得说,活动的元素,玩家操作的对象,主角,描绘在最表层。

4.      
算法

如前所述,这个程序的算法并不最好,但一定是相当节省内存的算法了。^_^

a.               
Pattern:如何做Pattern的数据结构呢?对于一个二维空间的画布,最基础的方法是做个二维数组,每个元素表示相应的位置上有没有方块。那用什么类型?boolean就足够了。

Boolean? 嘿嘿嘿…….

现在我要10*20的数组,每行10个,共二十行,那么,我就用一个20个的int数组来表示——不是么?一个int32位,足够表示32boolean的了。如此一来,要检测在i行的j位置上有没有方块,只要做:(lines[i]&1<<j )=0就可以了——计算机做位操作可是绝对快的。

i行的j位置上加入一个方块也就成了 line[i]|= 1<<j;

还有一个受益的是对满行的检测,当然也就不用再遍历这个行的每个位置——81的二进制数转化为十进制是多少?line[i]==FULL搞定

还有一个潜在的好处,如果第3行消失,第4行掉下,正好能落入第2行怎么办呢?似乎没有Tetris做这个,我也没有。不过要做也很方便:检测就用一句(line[i]&line[i+1])==0,落入的结果就是 line[i]|=line[j]——还是那句话,位操作是很快的。

 

最后,这个算法是我自己想出来的,以前有没有人做?不知道(不过应该有)。所以如果这里没提您的名字,见谅,因为我确实不知道

b.               
Brick:砖块,有7种造型,不包括其变化,均可以在一个4*4的区域里表示。承上算法,4*4=16<32,因此一个方块的形态可以用一个int来表示。

       至于方块的行为嘛,几乎都一样,不同的无外乎不同的形态。所以,方块所有的算法都可以放在Brick中,不同的造型就构造相应的子类,在子类中定义其形态和变形的形态。具体可参见源码——这里除了应用了软件工程的理念,就没什么别的技术含量了。

       当然做检测的算法很简单了(4个方块都检测一下,以确定该Brick是否可以移动或变形),可以改进,不过对于一个20帧的游戏来说,这点计算量实在算不了什么。

5.      
其他

MIDP相关内容参见其它书籍或API

源码中几乎没什么注释(基本不太需要多少注释),看官受累

本程序没什么技术价值或者商业价值,不过若是整体使用或转载请考虑附上我的名字(fantasydog),谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以在Gitee上找到一个使用Java实现的俄罗斯方块的开源项目。该项目的Gitee地址是\[Tetris: 【开箱即用】使用Java实现俄罗斯方块,开发工具idea - Gitee.com\](https://gitee.com/xiaoZcode/Tetris/tree/master)。这个项目是由一个叫做阿列克谢·帕基特诺夫(Alexey Pazhitnov)的俄罗斯人发明的。俄罗斯方块的原名是俄语Тетрис(英语是Tetris),这个名字来源于希腊语tetra,意思是“四”,而游戏的作者最喜欢网球(tennis)。于是,他把两个词tetra和tennis合而为一,命名为Tetris,这也就是俄罗斯方块名字的由来。在俄罗斯方块游戏中,玩家可以通过旋转方块、左右移动方块以及加速方块落下来进行操作。当方块移到区域最下方或着地到其他方块上无法移动时,方块就会固定在该处,而新的方块会从区域上方开始落下。当区域中某一列横向格子全部由方块填满时,该列会消失并成为玩家的得分。游戏会不断提示下一个要落下的方块,熟练的玩家会计算到下一个方块,评估如何进行。当固定的方块堆到区域最上方而无法消除层数时,游戏就会结束。一般来说,游戏还会随着进行而加速提高难度。预先设置的随机发生器会不断地输出单个方块到场地顶部。希望这个开源项目能够帮助到你。 #### 引用[.reference_title] - *1* *2* [Java实现俄罗斯方块游戏。(附完整源代码)](https://blog.csdn.net/Zp_insist/article/details/124740009)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Java实现俄罗斯方块源码](https://blog.csdn.net/codehxy/article/details/25532055)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值