java俄罗斯方块游戏
摘 要
在现今电子信息高速发展的时代,电子游戏已经深入人们的日常生活,成为老少皆宜的娱乐方式。但是游戏设计结合了日新月异的技术,在一个产品中整合了复杂的设计、艺术、声音和软件,所以并不是人人皆知。直到今天,在中国从事游戏设计的人仍然很少,但是游戏行业的发展之快,远超如家电、汽车等传统行业,也正因为如此,游戏人才的教育、培养远落后于产业的发展。
俄罗斯方块是个老幼皆宜的小游戏,它实现由四块正方形的色块组成,然后存储在一个数组的四个元素中,计算机随机产生不同七种类型的方块,根据计算机时钟控制它在一定的时间不停的产生,用户根据键盘的四个方向键控制翻转、向左、向右和向下操作,(控制键的实现是由键盘的方向键的事件处理实现)。然后程序根据这七种方块堆叠成各种不同的模型。
论文描述了游戏的历史,开发此游戏的环境,游戏开发的意义。遵循软件工程的知识,从软件问题定义开始,接着进行可行性研究、需求分析、概要设计、详细设计,最后对软件进行了测试,整个开发过程贯穿软件工程的知识体系。
此次设计在Microsoft Windows XP系统下,以Java为开发语言,在eclipse开发平台上进行游戏的设计与实践。
关键词:游戏设计;算法;数组;事件
引 言
游戏是人们活动中一项非常重要的内容,有人认为如果哪一天人类对所有的游戏都失去兴趣,恐怕世界的末日就要到了。电脑对游戏的贡献有目共睹,现在摸过电脑的人很少有没玩过电脑游戏的,喜欢游戏的人也很少有不玩电脑的。
俄罗斯方块是一款风靡全球的电视游戏机和掌上游戏机游戏,它曾经造成的轰动与造成的经济价值可以说是游戏史上的一件大事。这款游戏最初是由苏联的游戏制作人Alex Pajitnov制作的,它看似简单但却变化无穷,令人上瘾。相信大多数用户都还记得为它痴迷得茶不思饭不想的那个俄罗斯方块时代。究其历史,俄罗斯方块最早还是出现在PC机上,而我国的用户都是通过红白机了解、喜欢上它的。现在联众又将重新掀起这股让人沉迷的俄罗斯方块风潮。对一般用户来说,它的规则简单,容易上手,且游戏过程变化无穷,而在"联众俄罗斯方块"中,更有一些联众网络游戏所独有的魅力――有单机作战与两人在线对战两种模式,用户可任选一种进行游戏。网络模式还增加了积分制,使用户既能感受到游戏中的乐趣,也给用户提供了一个展现自己高超技艺的场所。
俄罗斯方块游戏可以说是随计算机的发展而发展,并不断推陈出新演变出各种类似游戏, 深受广大玩家喜爱。这个游戏有的简单, 有的复杂, 但其根本原理是一样的都是对运动的方块进行组合, 来训练玩家的反应能力。谈到游戏软件, 大多数人都认为其神妙莫测, 高不可及。而一般游戏软件也确实具有很高的技术难度, 随着开发工具及软件开发方法学的不断发展, 动手开发游戏也不是十分困难的。俄罗斯方块游戏是一种古老而又有趣的游戏, 游戏软件不计其数, 网上就有好多关于实现的复杂算法和设计, 其难度让一般初学者望而却步。本文利用数组作为方块的数据结构,提出一种用JAVA语言实现的简易方法, 对初学者可仿此开发类似游戏, 并了解游戏软件的设计与开发过程。
1.绪论
电子游戏,也就是运行在家用电脑、家用电子游戏机或是掌中宝游戏机及街机上的电子游戏程序。电子游戏是一种结合剧情故事、美术、音乐、动画、程序等技术于一身的互动型娱乐软件,涉及到多个行业。
从电子游戏的分类来看,有着多种分类方式。传统的游戏分类是按照游戏类型,将其分为即时战略游戏、第一人称射击游戏、角色扮演游戏、策略型游戏等类别。根据游戏运行平台的不同,可将电子游戏分为游戏机游戏、单机版PC 游戏、互动电视游戏、在线游戏和手机游戏。此外,韩国政府将电子游戏业分为家用游戏机游戏、单机版PC 游戏、网络游戏和街机游戏四大类。考虑到中韩游戏业比较接近,论文采用韩国的分类标准。“网络游戏”也就是人们一般所指的“在线游戏”,是指通过互联网进行的电脑游戏,通过人与人之间的互动达到交流、娱乐和休闲的目的。在互联网(局域网)技术出现之前,电子游戏都可以归于单机版游戏,即“人机对战”游戏,或最多是双人对战游戏。而随着互联网技术的出现,通过连接游戏服务器,上百、上千、乃至上万的游戏玩家同时连线娱乐成为了现实,这就大大增加了游戏的互动性、真实性,丰富了电子游戏的内涵。从网络游戏的分类来看,目前业界还没有一个比较统一规范的分类。随着计算机设备和网络技术的发展,电子游戏在全球得到了迅猛的发展,取得了巨大的成功,已成为当今世界上不可缺少的精神粮食。
2.可行性研究
通过本游戏的设计,综合自己在校期间所学的理论知识,设计开发俄罗斯方块游戏,使自己熟悉应用系统的开发过程,培养独立思考能力,检验学习效果和动手能力,初步掌握软件工程的系统理论,初步掌握MVC这种设计模式,进一步巩固和加强自身对j2se基础知识的理解,提高自己的编程水平,从而达到理论与实践相结合的目的。
基本要求:本游戏开发的总体任务是实现游戏的可操作性,以及界面的美观性。整个开发过程遵循软件工程规范,采用JAVA GUI编程来实现界面以及事件的控制,用户根据键盘的四个方向键控制翻转、向左、向右和向下操作,通过菜单栏中的相应菜单选项实现游戏的开始、结束、变换方块、积分以及等级的功能。
目标:通过本游戏的开发,主要实现游戏的可操作性以及美观性,同时使自己对JAVA语言的了解更进一层,为将来的实际工作打下坚实的基础。
条件、假定和限制:由于知识以及能力的限制,本游戏所实现的功能不够强大,可对本游戏进行改善,从而增强游戏的功能。
可行性研究的方法:通过研究分析俄罗斯方块所具备的能力及实现的方法、确定主体结构。利用现阶段我所能达到的能力,以最简洁、最容易的办法,边开发边测试边修改,实现一个初级游戏软件。
评价尺度:由于本软件是一个初级产品,对其要求不是太苛刻,所以能够达到俄罗斯游戏的一般功能即可。
技术可行性:开发本游戏的编程语言有多种,考虑到自身对语言的掌握程度,选择JAVA语言进行游戏的开发,采用JAVA GUI编程来实现界面以及事件的控制。
经济可行性:本游戏的开发旨在完成毕业设计,不注重直接的经济效益和其后的发展方向,只在注重自身水平和能力的提高,对自身的经济要求也不高,只要有一台能运行相应JAVA程序的电脑便可,所以不用考虑到经济问题。
社会可行性:本游戏的开发主要为了完成毕业设计,开发的主体是个人,不存在法律上的侵权行为,也不会为社会造成影响,这方面是完全可行的。
3.需求分析
对软件需求分析就是通过调查研究,建立系统的数据模型、功能模型、行为模型,用户和开发人员在“系统必须做什么”这个问题上实现相互理解,达到共识,从而形成双方认可的软件产品的需求规格说明书。这样有益于提高软件开发过程中的能见度,便于对软件开发过程中的控制与管理,便于采用工程方法开发软件,提高软件的质量,便于开发人员、维护人员、管理人员之间的交流、协作,并作为工作成果的原始依据,并且在向潜在用户传递软件功能、性能需求,使其能够判断该软件是否与自己的需求相关。
28种状态的方块随机产生,自由下落,落下时可由玩家用上、下、左、右控制键控制翻转和移动,以便以玩家所需要的形态和位置落下。如果落下时,方块的方格能填满某一行,则这一行可消去。消去一行后,游戏可给玩家加分,若由存在空格的方块填满整个窗口,则游戏失败。游戏功能需求如下:
游戏界面需求:设计良好的游戏界面可以让玩家充分感受到游戏带来的娱乐性,游戏的背景色是黑色,方块用蓝色颜色,在一定的区域内运动和变形,落下后的障碍物用黄色显示,这样看起来会有一定的美感。
游戏形状需求:用数组作为存储方块28种状态的数据结构,即长条形、Z字形、反Z形、田字形、7字形、反7形、T字型,各个方块要能实现它的变形,可设为顺时针或逆时针变形,一般为逆时针。
键盘处理事件需求:方块下落时,可通过键盘方向键(上、下、左、右键)对该方块进行向上(变形),向下(加速)、向左、向右移动。
鼠标处理事件需求:通过点击菜单栏中相应的菜单项,可以实现游戏的开始、结束,方块形状的变换,分数、等级的显示,以及游戏帮助等功能。
显示需求:当不同的方块填满一行时可以消行,剩余方块向下移动并统计分数。当达到一定分数的时候,会增加相应的等级。
操作系统:Microsoft Windows XP Professional Service Pack 2
内存:512M
硬盘:80G
CPU:赛扬2.8
交互工具:键盘/鼠标
显示器:VGA显示器
JDK版本:jdk1.6.0.02
Eclipse版本:eclipse-SDK-3.4-win32
本游戏通过键盘进行操作,在Windows的操作系统下,利用键盘的上、下、左、右键对方块进行移动变形,要使用键盘的接口事件。
面向对象的程序设计吸取了结构化程序设计的先进思想,并把它们同几个支持用户用新方法进行程序设计的有力概念结合在一起。
所有面向对象的程序设计语言一般都包含三个概念:封装、多态性和继承性。
这种方法要求语言必须具备抽象、封装、继承和多态性这几个关键要素。
面向对象的程序设计,是通过数据和代码建立分块的内存区域,以便提供对程序进行模块化的一种程序设计方法,这些模块可以被用作样板,在需要时再建立其副本。
C++和Java在面向对象这方面比VB要强,所以我排除了用VB做的可能性。但是C++为了与C语言兼容,其是包含了些面向过程的成分;Java除了C++中非面向过程的部分,其程序编写过程就是设计、实现类,定义其属性、行为的过程。还有Java特有的“沙箱”机制是其安全性的保障,同时它去除了C++中易造成的错误指针,增加了自动内存管理等措施,保证了Java程序运行的可靠性。
所以经过再三比较了三种语言后,决定采用Java语言编写俄罗斯方块。
4.系统流程结构设计
5. 详细设计
- 俄罗斯方块形状
方块总共有四种基本形,其它形状可由这四种基本形通过旋转得到,如下图:
在程序中,我们是可以用下面变量来描述它们,如下:
final int boxtypes[4][4][2]={
{{-1,0},{0,0},{1,0},{2,0}},
{{-1,0},{0,0},{1,0},{1,-1}},
{{-1,0},{0,0},{1,0},{0,-1}},
{{-1,0},{0,0},{1,0},{-1,-1}}
};/*四种基本方块的相对坐标*/
int box[4][2]; /*四个正方形的坐标(相对方块中心点)*/
int cx, cy; /*方块中心点在游戏空间中位置的坐标(相对游戏空间左上角点)*/
int type; /*方块类属(上图中四种分别为0,1,2,3)*/
随机生成新的方块:
void makenewblock()//随机生成新的方块数据
{
block_type = (int)(Math.random()*100)%4;//产生一个1-4的随机数
for(int i=0; i<4;i++)
block_box[i] = types[block_type][i];
block_cx=sp_WIDTH/2; block_cy=0;
}
- 俄罗斯方块的变换(关键算法,同学们自已考虑):移动、旋转
用户使用← → ↓箭头键来移动方块,移动方式有3种:左移一格、右移一格、下移一格, 对应的俄罗斯方块坐标变换公式如下:
左移一格:cx1=cx0-1, cy1=cy0 右移一格:cx1=cx0+1, cy1=cy0
下移一格:cx1=cx0, cy1=cy0+1
方块变换程序流程: 用变换公式计算变换后的方块中心坐标、各正方正形相对坐标,调用IsCanChangeTo(),判断是否能移到此位置,如能则更新方块坐标。如下右转90度(顺时针):
void turnright()/*右转动方块(顺时针)*/
{
int box[][] = new int[4][2]; /*四个正方形的坐标(相对方块中心点)
cx = block_cx; cy=block_cy; //中心位置不变
for (int i=0; i<4; i++) //计算变换后的各正方形坐标
{
box[i][0] = block_box[i][1]; //用公式x1=y0计算正方形的x 坐标
box[i][1] = -block_box[i][0]; //用公式y1=-x0计算正方形的y 坐标
}
if ( IsCanChangeTo( cx, cy , box ) ) {//如果能变换到些位置,则更新方块的坐标数据
block_cx = cx ; block_cy = cy; //中心位置不变
block_box = box ;
}
}
- 游戏空间
游戏空间可以看成由sp_WIDTH × sp_HIGHT个正方形小格子构成,每格子都有一个相对于左上角的坐标。可以用一个sp_WIDTH × sp_HIGHT的二维数组表示游戏空间。如下:
int gamespace[sp_WIDTH][sp_HIGHT];
某格子对应的数组元素的值为1,表示此格子已被方块填充,为0表示未被填充。
在游戏空间中,被方块填充了的格子为深灰色,未被填充的格子为白色(底色),灰色格子触及空间顶部时,游戏结束。即gamespace[0](二维数组第一排)中有元素的值为1时,游戏结束。
下面是判断游戏是否结束的程序:
boolean IsGameOver() /* true---结束 false-- 没有结束*/
{ boolean flag=false;
for(int i=0; i<sp_WIDTH; i++)
{
if (gamespace[0][i]==1) {flag=true; break;}
}
return flag;
}
- 判断俄罗斯方块是否能进行指定的变换(移动、旋转)
俄罗斯方块中心点在游戏空间中的坐标由方块结构体变量中的cx, cy指定,各小正方形在空间中的坐标等于小正方形相对坐标加上方块中心点坐标,即:
[cx + box[i].x , cy + box[i].y ]
能否进行下一步指定变换的判断方法是:执行指定的变换坐标计算程序(函数),返回(得到)变换后俄罗斯方块的信息体,判断变换后方块中各小正方形格(设坐标为[a, b])是否有超出边界,小正方形所在的位置是否已被填充。即:
0<= a <= sp_WIDTH b <= sp_HIGHT
且 gamespace[a][b] = = 0 成立
程序段如下:
boolean IsCanChangeTo(int cx, int cy , int box[][])//判断方块能否走到这位置
{
boolean IsCan =true ; /*标志变量,假设为能进行指定变换*/
int x, y;
for (int i=0; i<4; i++)
{
x = cx + box[i][0];
y = cy + box[i][1];
if ( x <0 || x >=sp_WIDTH || y>=sp_HIGHT|| (y>0 && gamespace[y][x]==1))
{ IsCan = false; break;} /*设置为不能进行指定变换*/
}
return IsCan;
}
- 判断方块是否已落到底, 停止下落
判断方块是否已落到底,就是判断方块中每个小正方形格的正下方位置是否已被填充或出下界。
如已到底,把方块所在的位置(格子)填充(对应gamespace元素值设为1),还要查看是否有某行已被全填充,把被全填充的行消掉,并给用户加分,程序片段如下:
boolean IsHitBottom( ) //判断当前方块是否已触底,并处理
{
boolean flag =false ; /*标志变量,假设为还没有触底*/
int i, x, y; /*方块中小正方形格的正下方格式的坐标*/
for (i=0; i<4; i++) /*逐个判断各小正方形格是否已触底*/
{
x= block_cx + block_box[i][0];
y= block_cy + block_box[i][1] + 1 ;
if ( y>=sp_HIGHT|| gamespace[y][x]==1)
{ flag = true; break; } /*设置为触底*/
}
if( flag )/*已触底*/
{
for (i=0; i<4; i++) /*逐个填充方块所占格子*/
{
x= block_cx + block_box[i][0] ;
y= block_cy + block_box[i][1] ;
if(y>=0) { gamespace[y][x]=1;}
}
for (i=0; i<4; i++) /*逐个检查方块所在行是否全填充*/
{
y= block_cy + block_box[i][1] ;
while(y>=0 && CheckAndCutLine(y))//检查此行是否全填充
m_score += 100; //加分
}
isplaying = ! IsGameOver();/*判断游戏是否结束*/
}
return flag;
}
boolean CheckAndCutLine(int Ln )/*检查某一行是否为全填充,如是,消掉并返回1*/
{
boolean IsFilled = true ;/*假设为全填充*/
for (int i=0; i<sp_WIDTH; i++) /*逐个判断各格是否有没填充的*/
{
if ( gamespace[Ln][i]==0){ IsFilled = false; break;} /*设置为没有全填充*/
}
if (IsFilled) //全填充时,消掉此行,把上面的格子值往下移一格
{
int j, k ;
for(j=Ln; j>0; j--)
for( k=0;k<sp_WIDTH; k++)//逐个把全填充行上的所有行向下移动一行
gamespace[j][k] = gamespace[j-1][k];
for( k=0;k<sp_WIDTH; k++) gamespace[0][k] = 0;//顶行
}
return IsFilled;
}