俄罗斯方块单人游戏JAVA程序设计Word文档格式.docx
- 文档编号:5672101
- 上传时间:2023-05-05
- 格式:DOCX
- 页数:38
- 大小:658.78KB
俄罗斯方块单人游戏JAVA程序设计Word文档格式.docx
《俄罗斯方块单人游戏JAVA程序设计Word文档格式.docx》由会员分享,可在线阅读,更多相关《俄罗斯方块单人游戏JAVA程序设计Word文档格式.docx(38页珍藏版)》请在冰点文库上搜索。
(2)游戏方块预览功能。
在游戏过程中,当在游戏区域中出现一个游戏方块时,必须在游戏预览区域出现下一个游戏方块,这样有利于游戏者控制游戏的策划。
由于在此游戏中存在8中不同的游戏方块,所以在游戏方块预览中就需要显示随机生成游戏方块。
PreviewPanel类是游戏预览控制类,在painting(Graphicsg)方法中,将根据生成的随机数字显示不同的游戏方块。
(3)游戏方块控制功能。
给各种游戏方块设置一个基类,主要包括begin()(初始化显示)方法,down()(向下移动)方法,left()(向左移动)方法,right()(向右移动)方法,change()(变换角度)方法,downto()(一下到底)方法。
在各个游戏子类中,需要具体实现这些方法。
(4)游戏速度分数更新功能。
在游戏者进行游戏的过程中,需要按照异地昂的游戏规则给游戏规则给游戏者计算游戏分数,当游戏分数达到一定数量后,就需要给游戏者增加难度,即提高游戏中游戏方块的下落速度。
3.2功能设计
3.2.1方块的设计
俄罗斯方块游戏中,具体的游戏方块图形的设计是比较重要的一个方面。
因为俄罗斯方块游戏中主要的动作就是控制游戏方块的移动和翻转,以便于组成一行行连续的方块从而增加游的分数。
由于主要的游戏动作都集中在这个游戏方块上,因此游戏方块的设计就显得格外重要了。
为了增加程序的可扩展性,这里设计一个游戏方块的基类,各个具体的游戏方块都从这个基类开始继承。
这样,当需要增加游戏方块时就不用重新设计新的类,只需要从这个基类集成出一个类就可以了。
更具基类设计了8个派生游戏方块类,其结构如图:
3.2.2旋转方块的设计
旋转方块的出现是随机的,而随着游戏级别的提升,每一关出现的旋转方块的数量也会不同,对于七种方块来说,它们在任何一段时间内出现的概率都是一致的,再者,旋转方块需要两个定时器,定时下落和定时旋转。
旋转方块的这个性质要求它必须要两个线程才能控制,但是为了充分利用资源,我们可以利用方块控制线程去控制旋转方块定时下落,然后只需再创建一个线程控制它定时旋转即可。
确定了两个线程共同控制旋转方块,就会出现一个线程协调工作的问题。
如果一个新方块出现的时机正好也是旋转方块出现的时机,程序就会出现紊乱,所以必须保证,在同一时间,正常方块和旋转方块只能出现一个。
因为两个线程需要共同控制旋转方块,所以不能用wait()和notify()这两个方法去协调线程,而应当利用其它条件去协调两个线程。
首先,游戏开始后,旋转方块控制线程可以随机休眠一定时间(这个休眠时间应该是随着游戏级别的提升而缩短的)。
休眠时间结束后,循环检测正常方块是否已经落下,当检测到方块落下后,马上得到一个新方块,然后开启一个循环,在方块没有落下之前让它按一定的时间频率旋转,成为一个旋转方块。
对于方块控制线程,在方块落下时应该休眠一定数量的时间,以让旋转方块控制线程有得到旋转方块的机会,如果超出这个休眠时间,旋转方块控制线程还没有得到新方块,则可以认为旋转方块控制线程还处在休眠中,方块控制线程得到一个新方块。
.3.2.3方块的翻转与移动
方块的翻转与移动比较容易实现,方块移动只需要改变方块的横坐标或纵坐标,然后重新绘制方块即可。
方块翻转也只需要改变方块数据第二维turnstate的值,然后重新绘制方块即可。
但是,这里边也会出现一个问题,这何种时候,方块不能再翻转和移动?
3.2.4方块的移动
很显然,当方块移动到地图的左右边界处,或者落下去后,不能再继续移动;
另一种情况就是,当方块要移动的方向被其他方块挡住时,方块不能再移动。
确定方块移动的规则后,接下来就是如何将这种规则用算法表示的问题了。
比如,当方块移动的左边界处时,方块不能再继续往左移动了,这个时候,肯定有一个条件成立,那就是方块的横坐标必定是小于或者等于零的。
如果方块的横坐标等于0,方块就不能再移动,那么方块数组的第一列至少有一个值为1,这种情况比较简单,但是,如果方块数组的第一列全为0时,也就是说,当方块数组有1的那列碰到边界时,方块才不能移动,这个时候,首次出现1的那列的横坐标为0,而方块数组的横坐标肯定已经小于0了。
3.2.5满行消除
JAVA图形类中提供了一个方法,copyArea(intx,inty,intwidth,intheight,intdx,intdy),这个方法的作用是将组建的某一区域复制到由dx和dy指定的水平距离和垂直距离所在的区域。
利用这个方法,可以消除满行。
3.2.6翻转越界纠正
由上述判定表可以看出,只要方块翻转后所处的空间足够,方块就能够翻转,但是,如果方块翻转后所处的空间不足够,而在它的另一边却有足够的空间呢?
比如,一个方块在它左边正好差一个格子的空间才能够翻转,但是它的右边恰好有一个格子的空间,这种情况,如果方块不能够翻转,就不方便用户操作,如果能够翻转,就会发生越界,将已经存在的方块挤占掉。
要想实现翻转又不发生越界,那么,就应该在方块翻转后把它往右边移动一个格子,然后再绘制方块,这样,方块就不会挤占掉其它已经固定住的方块了。
同样,方块在边界处时,翻转后不仅可能翻出地图外,还可能发生数组越界,当然,只需要将地图数组定义得大一些,就能够避免数组越界错误,对于方块越界,如果在它的另一边有足够空间,那么,就应该把方块往另一个方向移动适当的单位,纠正方块越界错误。
数据流图
4、系统测试
4.1系统主界面
游戏主界面
5
主代码:
packagecom.tarena.tetris;
importjava.awt.image.BufferedImage;
//格子
publicclassCell{
privateintrow;
//格子的行
privateintcol;
//格子的列
privateBufferedImageimage;
//格子的贴图
publicCell(introw,intcol,BufferedImageimage){
super();
this.row=row;
this.col=col;
this.image=image;
}
publicintgetRow(){
returnrow;
publicvoidsetRow(introw){
publicintgetCol(){
returncol;
publicvoidsetCol(intcol){
publicBufferedImagegetImage(){
returnimage;
publicvoidsetImage(BufferedImageimage){
publicvoiddrop(){
row++;
publicvoidmoveRight(){
col++;
publicvoidmoveLeft(){
col--;
@Override//重写
publicStringtoString(){
//TODOAuto-generatedmethodstub
System.out.println(row+"
"
+col);
returnrow+"
+col;
}}
------------------------------------------------------------------------
importjava.awt.Color;
importjava.awt.Font;
importjava.awt.Graphics;
importjava.awt.event.KeyAdapter;
importjava.awt.event.KeyEvent;
importjava.util.Arrays;
importjava.util.Timer;
importjava.util.TimerTask;
importjavax.imageio.ImageIO;
importjavax.swing.JFrame;
importjavax.swing.JPanel;
//俄罗斯方块
publicclassTetrisextendsJPanel{
privateintscore;
//分数
privateintlines;
//销毁行数
privateCell[][]wall;
//背景墙
privateTetrominotetromino;
//正在下落的四格方块
privateTetrominonextOne;
//下一个四格方块
//背景图片
privatestaticBufferedImagebackground;
privatestaticBufferedImageoverImage;
publicstaticBufferedImageT;
publicstaticBufferedImageS;
publicstaticBufferedImageI;
publicstaticBufferedImageL;
publicstaticBufferedImageJ;
publicstaticBufferedImageO;
publicstaticBufferedImageZ;
privatestaticfinalintROWS=20;
//背景墙的行数
privatestaticfinalintCOLS=10;
//背景墙的列数
privatestaticfinalintCELL_SIZE=26;
privatestaticint[]scoreTable={0,1,10,50,100};
//01234
publicstaticfinalintFONT_COLOR=0x667799;
publicstaticfinalintFONT_SIZE=30;
privateTimertimer;
//定时器
privatebooleanpause;
//是否为暂停状态
privatebooleangameOver;
//是否游戏结束状态
privatelonginterval=600;
//间隔时间
//将图片素材,复制到com.tarena.tetris包中
//使用静态代码块加载静态的图片
static{
try{
//Tetris.class的同时一个包中找到"
tetris.png"
background=ImageIO.read(Tetris.class.getResource("
));
overImage=ImageIO.read(Tetris.class.getResource("
GAMEOVER.png"
T=ImageIO.read(Tetris.class.getResource("
T.png"
I=ImageIO.read(Tetris.class.getResource("
I.png"
S=ImageIO.read(Tetris.class.getResource("
S.png"
Z=ImageIO.read(Tetris.class.getResource("
Z.png"
J=ImageIO.read(Tetris.class.getResource("
J.png"
L=ImageIO.read(Tetris.class.getResource("
L.png"
O=ImageIO.read(Tetris.class.getResource("
O.png"
}catch(Exceptione){
e.printStackTrace();
}
//JPanelpaint()paint画重写paint()修改原有的绘制方法
@Override
publicvoidpaint(Graphicsg){
//画背景,画墙,画正在下落的方块,画下一个方块...
g.drawImage(background,0,0,null);
g.translate(0,0);
//坐标系平移
paintWall(g);
//画墙
paintTetromino(g);
//绘制正在下落的方块
paintNextOne(g);
//绘制下一个要下落的方块
paintScore(g);
//绘制分数
if(gameOver){
g.drawImage(overImage,0,0,null);
//在Tetris添加启动方法action()
publicvoidaction(){
wall=newCell[ROWS][COLS];
startAction();
//wall[2][2]=newCell(2,2,T);
tetromino=Tetromino.randomOne();
nextOne=Tetromino.randomOne();
//处理键盘按下事件,在按下按键时候执行下落方法
KeyAdapterl=newKeyAdapter(){
//key按键Pressed按下了
publicvoidkeyPressed(KeyEvente){
intkey=e.getKeyCode();
//得到键的Unicode
if(key==KeyEvent.VK_Q){//Q表示退出
System.exit(0);
//结束Java进程
}
if(gameOver){
if(key==KeyEvent.VK_S){//S表示开始
startAction();
repaint();
}
return;
if(pause){//pause=true
if(key==KeyEvent.VK_C){//C表示继续
continueAction();
switch(key){
caseKeyEvent.VK_DOWN:
//tetromino.softDrop();
softDropAction();
break;
caseKeyEvent.VK_RIGHT:
//tetromino.moveRight();
moveRightAction();
caseKeyEvent.VK_LEFT:
//tetromino.moveLeft();
moveLeftAction();
caseKeyEvent.VK_SPACE:
hardDropAction();
caseKeyEvent.VK_UP:
rotateRightAction();
caseKeyEvent.VK_P:
//按键盘上的P表示暂停
pauseAction();
repaint();
//再画一次
}
};
//下落流程:
监听键盘事件->
如果下箭头按下->
//执行下落算法tetromino.softDrop()->
//修改每个格子对象的数据->
调用repaint()->
//尽快调用paint()->
paint方法会根据当前的数据
//重新绘制界面->
看到移动以后的方块了
//绑定事件到当前面板
this.requestFocus();
this.addKeyListener(l);
//绘制正在下落的方块
publicvoidpaintTetromino(Graphicsg){
if(tetromino==null){
return;
//将每个格子的row,col换算为x,y,然后贴图
Cell[]cells=tetromino.cells;
for(inti=0;
i<
cells.length;
i++){
//i=0123
Cellcell=cells[i];
//cell每个格子
intx=cell.getCol()*CELL_SIZE;
inty=cell.getRow()*CELL_SIZE;
g.drawImage(cell.getImage(),x,y,null);
//绘制下一个要下落的方块
privatevoidpaintNextOne(Graphicsg){
if(nextOne==null){
Cell[]cells=nextOne.cells;
//i=0123
//cell每个格子
intx=(cell.getCol()+10)*CELL_SIZE;
inty=(cell.getRow()+1)*CELL_SIZE;
//画墙
privatevoidpaintWall(Graphicsg){
for(introw=0;
row<
wall.length;
row++){
Cell[]line=wall[row];
//line代表墙上的每一行
for(intcol=0;
col<
line.length;
col++){
Cellcell=line[col];
//cell代表墙上每个格子
intx=col*CELL_SIZE;
inty=row*CELL_SIZE;
if(cell==null){
g.drawRect(x,y,CELL_SIZE,CELL_SIZE);
}else{
g.drawImage(cell.getImage(),x,y,null);
//g.drawString(row+"
+col,x,y+CELL_SIZE);
//检查当前正在下落的方块是否出界
privatebooleanoutOfBounds(){
intcol=cell.getCol();
if(col<
0||col>
=COLS){
returntrue;
returnfalse;
//检查正在下落的方块是否与墙上的砖块重叠
privatebooleancoincide(){
introw=cell.getRow();
//如果墙的row,col位置有格子,就重叠了
if(row>
=0&
&
row<
ROWS&
col>
col<
=COLS&
wall[row][col]!
=null){
//重叠
//向右移动流程控制
publicvoidmoveRightAction(){
//尝试先向右移
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 俄罗斯方块 单人游戏 JAVA 程序设计