软件092、093实训题目:俄罗斯方块游戏设计(Java版)开发工具要求:Jcreate3.5或以上参考:java帮助文档,tutorial文档知识:程序主框架,事件发生与处理模型,时间日期类及时间格式化输出、图形绘制接口(类)及各类绘图成员函数、窗体的重绘机制、进程及线程的初步概念。要求:完成以下游戏内容,满分为85分,若加以扩展,满分为100分。一、设计要点:1.游戏数据与界面显示相分离,用游戏结构数据描述游戏的状态,玩家操作或游戏自行走一步,程序中都通过修改游戏数据来体现,即每走一步,程序会修改当前的游戏数据,判断游戏是否结束了,也是通过对游戏数据的分析来作出结论。游戏界面是根据当时游戏数据来绘制的,当数据改变时,要清除原图形并重绘。总之,游戏的逻辑设计是针对游戏数据,而不是游戏界面。界面只是间接地向玩家显示结果。2.因此,在设计函数时,大致分二类:与玩家操作事件有关的数据处理函数,与界面效果有关的图形绘制函数。游戏运行过程由窗体监听到的键盘事件控制。3.在游戏程序中,我们可以将它看成3个对象,分别是程序窗体主类对象、方块数据管理对象、控制游戏自动下落的定时器线程对象。窗体界面主类对象:负责绘制游戏图象、包含游戏设置的各种控件(如:设置速度的文本框、显示得分的标签、开始及暂停按钮),负责游戏的各种属性数据的读入及显示输出,最重要的是:它还是一个键盘事件处理类,监听玩家的键盘操作,处理键盘事件,在键盘事件处理函数中调用游戏数据管理对象的方法,控制游戏的运行。我们还把游戏数据管理对象、控制游戏自动下落的定时器线程对象作为它的成员变量。游戏数据管理对象:主要管理着两方面数据:方块的坐标数据和游戏空间数据。用成员数组变量描述游戏空间状态,根据游戏空间状态判断游戏是否结束。用它的成员变量保存方块的形状数据及坐标数据,定义当方块走动方块数据变化的处理方法。此外,还把各种游戏属性数据作为其成员变量。控制游戏自动下落的定时器线程对象:是一个线程类派生对象,独立运行,每隔一段时间控制方块下落下格。classRussionBlockGame{finalintsp_WIDTH=20;//游戏空间宽(单位:小正方格)finalintsp_HIGHT=20;//游戏空间高(单位:小正方格)finalinttypes[][][]={{{-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}}};/*四种基本方块的相对坐标*///游戏核心数据intblock_box[][]=newint[4][2];/*四个正方形的坐标(相对方块中心点)*/intblock_cx,block_cy;/*方块中心点在游戏空间中的坐标(相对游戏空间左上角点)*/intblock_type;/*方块类属(上图中四种分别为0,1,2,3)*/intgamespace[][]=newint[sp_HIGHT][sp_WIDTH];/*空间数据*///游戏的其它属性intm_score=0;/*游戏得分*/intm_speed=500;/*控制游戏,单位:1/1000秒/步*/booleanisplaying=false;/*是否在游戏中*/publicRussionBlockGame()//构造函数{…………}voidmakenewblock(){}//随机生成新的方块数据voidmovedown(){}/*下移动方块*/voidmoveleft(){}/*左移动方块*/voidmoveright(){}/*右移动方块*/voidturnleft(){}/*左转动方块*/voidturnright(){}/*右转动方块*/booleanIsCanChangeTo(intcx,intcy,intbox[][])//判断方块能否走到这位置booleanIsHitBottom()//判断当前方块是否已触底,并处理booleanCheckAndCutLine(intLn)/*查某行是否为全填充,如是,消掉并返回true*/booleanIsGameOver(){}/*true---结束false--没有结束*/}classGameWinextendsJFrame{Clolorspacecolor;//游戏空间背景色//为增强程序的灵活性,游戏空间坐标、方块尺寸等,可以定义为常变量finalintORINA_X=100//游戏空间左上角的屏幕坐标X(单位:象素)finalintORINA_Y=50//游戏空间左上角的屏幕坐标Y(单位:象素)finalintBOXSIZE=20//小正方格大小尺寸(单位:象素)……………….}publicclassTimerRunerimplementsRunnable{………publicvoidrun(){………..}}二、详细设计1.俄罗斯方块形状方块总共有四种基本形,其它形状可由这四种基本形通过旋转得到,如下图:在程序中,我们是可以用下面变量来描述它们,如下:finalintboxtypes[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}}};/*四种基本方块的相对坐标*/intbox[4][2];/*四个正方形的坐标(相对方块中心点)*/intcx,cy;/*方块中心点在游戏空间中位置的坐标(相对游戏空间左上角点)*/inttype;/*方块类属(上图中四种分别为0,1,2,3)*/随机生成新的方块:voidmakenewblock()//随机生成新的方块数据{block_type=(int)(Math.random()*100)%4;//产生一个1-4的随机数for(inti=0;i4;i++)block_box[i]=types[block_type][i];block_cx=sp_WIDTH/2;block_cy=0;}2.俄罗斯方块的变换(关键算法,同学们自已考虑):移动、旋转用户使用←→↓箭头键来移动方块,移动方式有3种:左移一格、右移一格、下移一格,对应的俄罗斯方块坐标变换公式如下:左移一格:cx1=cx0-1,cy1=cy0右移一格:cx1=cx0+1,cy1=cy0下移一格:cx1=cx0,cy1=cy0+1用户使用a、d键来旋转方块,旋转方式有两种:左转(a键)和右转(d键)左转90度(逆时针):每个正方形的坐标变换公式为:y1=x0,x1=-y0.右转90度(顺时针):每个正方形的坐标变换公式为:y1=-x0,x1=y0.方块变换程序流程:用变换公式计算变换后的方块中心坐标、各正方正形相对坐标,调用IsCanChangeTo(),判断是否能移到此位置,如能则更新方块坐标。如下右转90度(顺时针):voidturnright()/*右转动方块(顺时针)*/{//保存变换后坐标的变量intbox[][]=newint[4][2];/*四个正方形的坐标(相对方块中心点)*/intcx,cy;/*方块中心点在游戏空间中的坐标(相对游戏空间左上角点)*/cx=block_cx;cy=block_cy;//中心位置不变for(inti=0;i4;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;}}3.游戏空间游戏空间可以看成由sp_WIDTH×sp_HIGHT个正方形小格子构成,每格子都有一个相对于左上角的坐标。可以用一个sp_WIDTH×sp_HIGHT的二维数组表示游戏空间。如下:intgamespace[sp_WIDTH][sp_HIGHT];某格子对应的数组元素的值为1,表示此格子已被方块填充,为0表示未被填充。在游戏空间中,被方块填充了的格子为深灰色,未被填充的格子为白色(底色),灰色格子触及空间顶部时,游戏结束。即gamespace[0](二维数组第一排)中有元素的值为1时,游戏结束。下面是判断游戏是否结束的程序:booleanIsGameOver()/*true---结束false--没有结束*/{booleanflag=false;for(inti=0;isp_WIDTH;i++){if(gamespace[0][i]==1){flag=true;break;}}returnflag;}4.判断俄罗斯方块是否能进行指定的变换(移动、旋转)俄罗斯方块中心点在游戏空间中的坐标由方块结构体变量中的cx,cy指定,各小正方形在空间中的坐标等于小正方形相对坐标加上方块中心点坐标,即:[cx+box[i].x,cy+box[i].y]能否进行下一步指定变换的判断方法是:执行指定的变换坐标计算程序(函数),返回(得到)变换后俄罗斯方块的信息体,判断变换后方块中各小正方形格(设坐标为[a,b])是否有超出边界,小正方形所在的位置是否已被填充。即:0<=a<=sp_WIDTHb<=sp_HIGHT且gamespace[a][b]==0成立程序段如下:booleanIsCanChangeTo(intcx,intcy,intbox[][])//判断方块能否走到这位置{booleanIsCan=true;/*标志变量,假设为能进行指定变换*/intx,y;for(inti=0;i4;i++){x=cx+box[i][0];y=cy+box[i][1];if(x0||x=sp_WIDTH||y=sp_HIGHT||(y0&&gamespace[y][x]==1)){IsCan=false;break;}/*设置为不能进行指定变换*/}returnIsCan;}5.判断方块是否已落到底,停止下落判断方块是否已落到底,就是判断方块中每个小正方形格的正下方位置是否已被填充或出下界。如已到底,把方块所在的位置(格子)填充(对应gamespace元素值设为1),还要查看是否有某行已被全填充,把被全填充的行消掉,并给用户加分,程序片段如下:booleanIsHitBottom()//判断当前方块是否已触底,并处理{booleanflag=false;/*标志变量,假设为还没有触底*/inti,x,y;/*方块中小正方形格的正下方格式的坐标*/for(i=0;i4;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;i4;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;i4;i++)/*逐个检查方块所在行是否全填充*/{y=block_cy+block_box[i][1];while(y=0&&CheckAndCutLine(y))//检查此行是否全填充m_score+=100;//加分}isplaying=!IsGameOver();/*判断游戏是否结束*/}returnflag;}booleanCheckAndCutLine(intLn)/*检查某一行是否为全