一、程序功能介绍本程序实现了俄罗斯方块游戏的基本功能,游戏中玩家可以做的操作有:1.中间一个方块不变其他三个以90度为单位向右旋转方每一格块,此程序会判断方块有没有空间让他实现旋转,即判断是否越界,若越界则不可以实现旋转。
2.以格子为单位左右移动方块,下方向让方块加速落下,空格键则急速下落。
3.方块移到区域最下方或是着地到其他方块上无法移动时,就会固定在该处,而新的随机图形会出现在区域上方开始落下。
4.当区域中某一列横向格子全部由方块填满,则该列会自动消除并成为玩家的得分。
同时删除的列数越多,得分指数上升。
5.当固定的方块堆到区域最上方,则游戏结束。
(此功能尚未实现)6.此程序还不完善,开始,暂停,重来,结束都没有实现,有待改进。
二、课程设计过程1、总体概述:设计一个简单的游戏,能够将Java的面向对象程序思想应用到课程设计中,用到Java 中常用的组件以及相应的布局方式。
完成设计、编程、测试等过程,给出设计思路、设计说明书、主要的代码的说明、源代码以及可运行的游戏程序。
2、各个子类的定义:1.定义俄罗斯方块类,通过可视化界面设定一个游戏界面窗口,用一个10*20表示游戏区域。
public class TetrisGame extends JPanelJFrame jf=new JFrame("俄罗斯方块");jf.setSize(540,600);jf.setVisible(true);public static final int ROWS=20;public static final int COLS=10;2.定义7种俄罗斯方块的基本类型,分别以S、Z、L、J、I、O、T这7个字母的形状来命名。
先定义四方格主类:public class Tetromino;再定义它的7个子类:S、Z、L、J、I、O、Tprivate static class S extends Tetromino;private static class Z extends Tetromino;private static class L extends Tetromino;private static class J extends Tetromino;private static class I extends Tetromino;private static class O extends Tetromino;private static class T extends Tetromino;3.通过switch语句,随机输出方块到游戏区域顶部。
public static Tetromino randomOne();4.用键盘监听来实现下落、移动、旋转变形。
键盘监听:public void keyPressed(KeyEvent e);软着陆:protected void softDropAction();硬着陆:protected void hardDropAction();左移:protected void moveLeftAction();右移:protected void moverightAction();右旋:public void rotateRight();repaint();重绘java里repaint()是重绘component的方法;component中己有的图形发生变化后不会立刻显示,须使用repaint方法。
component简而言之,组件就是对象。
C++Builder中叫组件,Delphi中叫部件,而在Visual BASIC中叫控件。
组件是对数据和方法的简单封装。
C++ Builder中,一个组件就是一个从TComponent派生出来的特定对象组件可以有自己的属性和方法。
判断是否越界:private boolean canMoveR();//是否碰墙,是否有其他图形private boolean outOfBoundsTB();//private boolean baoHanR();//判断右侧墙上是否有内容private boolean baoHanL();//判断左侧墙上是否有内容private boolean outOfBoundsR();private boolean outOfBoundsL();5.绘制图像public void paint(Graphics g);private void paintScore(Graphics g);private void paintNextOne(Graphics g);private void paintWall(Graphics g);private void paintTetromino(Graphics g);6.每次摆放如果将场地的一行或多行完全填满,则组成这些行的所有小正方形将被消除,并且以此来换取积分。
判断是否行满:private boolean fullCells(int row);消行:private void destroyLines();3、导入各种包:1、java.awt.Font:Font类表示字体,可以使用它以可见方式呈现文本。
字体提供将字符序列映射到字形序列所需要的信息,以便在Graphics对象和Component对象上呈现字形序列。
2、java.awt.Graphics:是一个用来绘制2D图像必须导入的java包,提供对图形图像的像素,颜色的绘制。
3、java.awt.Image:提供创建和修改图像的各种类。
使用流框架来处理图像,该框架涉及图像生产者、可选的图像过滤器和图像使用者。
此框架使得在获取和生成图像的同时逐步呈现该图像成为可能。
而且,该框架允许应用程序丢弃图像使用的存储空间并随时重新生成它。
此包提供了多种图像生产者、使用者和过滤器,可以根据图像处理的需要来配置它们。
4、java.awt.event.KeyAdapter:接收键盘事件的摘要适配器类。
方法在这类。
这类方便创建侦听器对象的存在。
扩展这个类来创建一个键盘事件听众和覆盖感兴趣的事件的方法。
(如果你实施KeyListener接口,你必须定义所有的方法,它。
这个抽象类定义了无效的方法所有,所以你只能定义为事件你关心的方法。
)创建一个使用扩展类的听众对象然后登记与组件使用组件的addkeylistener方法当一个键被按下,释放,或类型,方法在听者相关对象时,键盘事件通过它。
5、java.awt.event.KeyEvent:提供处理由AWT组件所激发的各类事件的接口和类。
有关AWT事件模型的细节,请参见java.awt.AWTEvent类。
事件由事件源所激发。
向事件源注册的事件侦听器可接收有关特定事件类型的通知。
此包定义了事件和事件侦听器,以及事件侦听器适配器,它是让事件侦听器的编写过程更为轻松的便捷类。
6、java.awt.event.KeyListener:用于接收键盘事件(击键)的侦听器接口。
旨在处理键盘事件的类要么实现此接口(及其包含的所有方法),要么扩展抽象KeyAdapter类(仅重写有用的方法)。
然后使用组件的addKeyListener方法将从该类所创建的侦听器对象向该组件注册。
按下、释放或键入键时生成键盘事件。
然后调用侦听器对象中的相关方法并将该KeyEvent传递给它。
7、java.awt.event.KeyListener:java.util.Arrays类包含一个静态的工厂,允许数组被视为列表。
以下是关于数组的要点:这个类包含了各种方法来操作数组(比如排序和搜索)。
在这个类中的方法抛出NullPointerException如果指定数组引用为null。
8、javax.imageio.ImageIO:此包包含一些基本类和接口,有的用来描述图像文件内容(包括元数据和缩略图)(IIOImage)有的用来控制图像读取过程(ImageReader、ImageReadParam和ImageTypeSpecifier)和控制图像写入过程(ImageWriter和ImageWriteParam);还有的用来执行格式之间的代码转换(ImageTranscoder)和报告错误(IIOException)。
9、javax.swing.JFrame:java的GUI程序的基本思路是以JFrame为基础,它是屏幕上window的对象,能够最大化、最小化、关闭。
10、javax.swing.JPanel:JPanel类是一个通用的轻量级容器。
11、java.util.Random:Random是数的随机生成器。
4、程序功能设计:功能模块图:如图1:图1功能模块图main 框架墙下一个图形计分监听器判断越界判断到底N 判断消行左移右移变形软下降硬下降消行重画墙计分重画墙YN三、程序运行的结果分析1、初始界面如图2:有一个方块下来且右上方矩形中显示下一个方块图2初始状态图2、当底部有一行方块填充,进行计算行数并加分及消除该行,结果如图3图3计分消行图四、课程设计总结这次JAVA课程设计我选择了做俄罗斯方块这个小游戏,刚开始很迷茫,不知道该怎么做,多次想要换题,但是由于很早玩过这个游戏所以对于它产生了兴趣,想要知道它到底是怎么做成的。
之后经过网上查询以及请教学霸等方法,终于慢慢的开始打代码,在学习过程中,我学到了一些关于做游戏的相关知识,比如说怎么设置界面,设置面板,画游戏界面等,也在过程中发现了自己的不足之处。
运行程序的时候出现了几个问题:1、不知道该用哪些函数2、一段一段代码总有好多漏洞,要判断好多东西,比如它是否到达底部的墙上,墙上是否有方块,到底怎样使它自动下降等。
经过这次课程设计,我对java这门课程更加了解了,学习也有了方向感,明白了基础知识很重要,但实践也很重要。
强大的理论功底和动手能力结合才是一个工程师必备的,理论与实践结合才是完美的。
我们应该抓住每次实验的机会,实打实的学些东西,还有在学校提供的学习平台里面好好学习。
当然,这些也离不开我们老师的悉心指导,所以我们更应该不负老师所望,今后我们强化自己的知识的认识,在这里想跟老师说一声,非常感谢。
五、程序设计的完整代码及注解package newTetris;import java.awt.Color;import java.awt.Font;import java.awt.Graphics;import java.awt.Image;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import java.awt.event.KeyListener;import java.util.Arrays;import javax.imageio.ImageIO;import javax.swing.JFrame;import javax.swing.JPanel;public class TetrisGame extends JPanel{public static final int ROWS=20;public static final int COLS=10;public static final int CELL_SIZE=26;//格子的大小private int score;//计分private int lines=0;//计消除行Tetromino t=Tetromino.randomOne();Tetromino next=Tetromino.randomOne();//下一张图private Cell[][]wall=new Cell[20][10];//墙public static Image background;//声明变量public static Image I;public static Image T;public static Image S;public static Image Z;public static Image L;public static Image J;public static Image O;static{try{background=ImageIO.read(TetrisGame.class.getResource("tetris.png"));I=ImageIO.read(TetrisGame.class.getResource("I.png"));T=ImageIO.read(TetrisGame.class.getResource("T.png"));S=ImageIO.read(TetrisGame.class.getResource("S.png"));Z=ImageIO.read(TetrisGame.class.getResource("Z.png"));L=ImageIO.read(TetrisGame.class.getResource("L.png"));J=ImageIO.read(TetrisGame.class.getResource("J.png"));O=ImageIO.read(TetrisGame.class.getResource("O.png"));}catch(Exception e){e.printStackTrace();}}public static void main(String[]args){JFrame jf=new JFrame("俄罗斯方块");TetrisGame tetris=new TetrisGame();jf.add(tetris);jf.setSize(540,590);jf.setLocationRelativeTo(null);//居中jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);jf.setVisible(true);tetris.action();}private void action(){KeyListener kL=new KeyAdapter(){public void keyPressed(KeyEvent e){int key=e.getKeyCode();switch(key){case KeyEvent.VK_DOWN:softDropAction();break;case KeyEvent.VK_RIGHT:moveRightAction();break;case KeyEvent.VK_LEFT:moveLeftAction();break;case KeyEvent.VK_UP:rotateRightAction();break;case KeyEvent.VK_SPACE:hardDropAction();break;}repaint();}};this.addKeyListener(kL);//添加到jpanelthis.requestFocus();while(true){softDropAction();repaint();try{Thread.sleep(700);}catch(InterruptedException e1){//TODO自动生成的catch块e1.printStackTrace();}}}protected void hardDropAction(){while(canDrop()){if(canDrop()){Cell[]cells=t.cells;for(int i=0;i<cells.length;i++){cells[i].drop();//一直下落,直到不能下落,写到墙上}}}landWall();//着陆到墙上destroyLines();t=next;//下一张图替换当前next=Tetromino.randomOne();}protected void rotateRightAction(){t.rotateRight();//如果越界,则转回if(outOfBoundsTB()||outOfBoundsL()||baoHanL()||outOfBoundsR()||baoHanR()) t.rotateLeft();}protected void moveLeftAction(){if(canMoveL()){Cell[]cells=t.cells;for(int i=0;i<cells.length;i++){cells[i].moveLeft();}}else{}}protected void moveRightAction(){if(canMoveR()){Cell[]cells=t.cells;for(int i=0;i<cells.length;i++){cells[i].moveRight();}}else{}}protected void softDropAction(){if(canDrop()){//判断有无靠边和落底Cell[]cells=t.cells;for(int i=0;i<cells.length;i++){cells[i].drop();}}else{landWall();//画到墙上去destroyLines();t=next;//下一张图替换当前next=Tetromino.randomOne();//下一张重新生成}}private void destroyLines(){for(int row=0;row<20;row++){if(fullCells(row)){deleteLine(row);//消行lines++;score+=10;}}}private void deleteLine(int row){//消行for(int i=row;i>=1;i--){System.arraycopy(wall[i-1],0,wall[i],0,10);}Arrays.fill(wall[0],null);}private boolean fullCells(int row){Cell[]line=wall[row];for(Cell c:line){if(c==null){return false;}}return true;}private void landWall(){//图形的四个格子填充墙对应位置Cell[]cells=t.cells;for(int i=0;i<cells.length;i++){Cell c=cells[i];int row=c.getRow();int col=c.getCol();wall[row][col]=c;}}//判断能否继续,是否有其他图形private boolean canDrop(){Cell[]cells=t.cells;for(int i=0;i<cells.length;i++){Cell c=cells[i];if(c.getRow()==19)return false;}for(Cell c:cells){//如果碰到东西就不可落int row=c.getRow()+1;int col=c.getCol();if(wall[row][col]!=null)return false;}return true;}//是否碰墙,是否有其他图形private boolean canMoveR(){if(outOfBoundsR()||baoHanR()){return false;}return true;}private boolean canMoveL(){if(outOfBoundsL()||baoHanL()){return false;}return true;}//判断右侧墙上是否有内容private boolean baoHanR(){Cell[]cells=t.cells;for(Cell c:cells){int col=c.getCol();if(row>=0&&row<=20&&col>=0&&col<=10&&wall[row][col+1]!=null){ return true;}}return false;}//判断左侧墙上是否有内容private boolean baoHanL(){Cell[]cells=t.cells;for(Cell c:cells){int row=c.getRow();int col=c.getCol();if(row>=0&&row<=20&&col>=0&&col<=10&&wall[row][col-1]!=null){ return true;}}return false;}private boolean outOfBoundsTB(){Cell[]cells=t.cells;for(Cell c:cells){int row=c.getRow();if(row>=19||row<=0){return true;}}return false;}private boolean outOfBoundsL(){Cell[]cells=t.cells;for(Cell c:cells){int col=c.getCol();//int row= c.getRow();if(col<1){return true;}}return false;}private boolean outOfBoundsR(){Cell[]cells=t.cells;for(Cell c:cells){//int row= c.getRow();if(col>8){return true;}}return false;}public void paint(Graphics g){g.drawImage(background,0,0,null);g.translate(15,15);//坐标系平移paintWall(g);//画墙paintTetromino(g);//下落的图paintNextOne(g);//右边那个paintScore(g);//计分计行g.translate(-15,-15);//画笔恢复原位}private void paintScore(Graphics g){int x=289;int y=160;g.setColor(Color.BLUE);Font font=new Font("楷体",Font.BOLD,30);g.setFont(font);String str="SCORE:"+score;g.drawString(str,x,y);//绘制字符串y+=56;str="LINES:"+lines;g.drawString(str,x,y);//行数}private void paintNextOne(Graphics g){if(next!=null){Cell[]cells=next.cells;for(int i=0;i<cells.length;i++){Cell cell=cells[i];int x=(cell.getCol()+10)*CELL_SIZE;int y=(cell.getRow()+1)*CELL_SIZE;g.drawImage(cell.getImage(),x,y,null);}}}private void paintWall(Graphics g){for(int row=0;row<wall.length;row++){Cell[]line=wall[row];for(int col=0;col<10;col++){Cell cell=line[col];int x=col*CELL_SIZE;int y=row*CELL_SIZE;if(cell==null){//判断墙是否有内容g.drawRect(x,y,CELL_SIZE,CELL_SIZE);}else{g.drawImage(cell.getImage(),x-1,y-1,null);}}}}private void paintTetromino(Graphics g){Cell[]cells=t.cells;for(int i=0;i<cells.length;i++){Cell c=cells[i];int x=c.getCol()*CELL_SIZE;int y=c.getRow()*CELL_SIZE;g.drawImage(c.getImage(),x,y,null);}}}package newTetris;import java.awt.Image;public class Cell{int row;//行int col;//列Image image;//这个格子上有的图形public Cell(int row,int col,Image image){super();this.row=row;this.col=col;this.image=image;}public int getRow(){return row;}public void setRow(int row){this.row=row;}public int getCol(){return col;}public void setCol(int col){this.col=col;}public Image getImage(){return image;}public void setImage(Image image){this.image=image;}//调试格子处于第几行第几列public String toString(){return"第"+row+"行"+"第"+col+"列";}public void drop(){row++;}public void moveLeft(){col--;}public void moveRight(){col++;}}package newTetris;import java.util.Random;public class Tetromino{Cell[]cells=new Cell[4];State[]states;//四个方块int index=1000;private static class T extends Tetromino{public T(){cells[0]=new Cell(0,4,TetrisGame.T);cells[1]=new Cell(0,3,TetrisGame.T);cells[2]=new Cell(0,5,TetrisGame.T);cells[3]=new Cell(1,4,TetrisGame.T);states=new State[4];states[0]=new State(0,0,0,-1,0,1,1,0);states[1]=new State(0,0,-1,0,1,0,0,-1);states[2]=new State(0,0,0,1,0,-1,-1,0);states[3]=new State(0,0,1,0,-1,0,0,1);}}private static class I extends Tetromino{public I(){cells[0]=new Cell(0,4,TetrisGame.I);cells[1]=new Cell(0,3,TetrisGame.I);cells[2]=new Cell(0,5,TetrisGame.I);cells[3]=new Cell(0,6,TetrisGame.I);states=new State[]{new State(0,0,0,1,0,-1,0,-2), new State(0,0,-1,0,1,0,2,0)};}}private static class S extends Tetromino{public S(){cells[0]=new Cell(0,4,TetrisGame.S);cells[1]=new Cell(0,5,TetrisGame.S);cells[2]=new Cell(1,3,TetrisGame.S);cells[3]=new Cell(1,4,TetrisGame.S);states=new State[]{new State(0,0,0,1,1,-1,1,0),new State(0,0,-1,0,1,1,0,1)};}}private static class L extends Tetromino{public L(){cells[0]=new Cell(0,4,TetrisGame.L);cells[1]=new Cell(0,3,TetrisGame.L);cells[2]=new Cell(0,5,TetrisGame.L);cells[3]=new Cell(1,3,TetrisGame.L);states=new State[]{new State(0,0,0,-1,0,1,1,-1),new State(0,0,-1,0,1,0,-1,-1),new State(0,0,0,1,0,-1,-1,1),new State(0,0,1,0,-1,0,1,1)};}}private static class J extends Tetromino{public J(){cells[0]=new Cell(0,4,TetrisGame.J);cells[1]=new Cell(0,3,TetrisGame.J);cells[2]=new Cell(0,5,TetrisGame.J);cells[3]=new Cell(1,5,TetrisGame.J);states=new State[]{new State(0,0,0,-1,0,1,1,1),new State(0,0,-1,0,1,0,1,-1),new State(0,0,0,1,0,-1,-1,-1),new State(0,0,1,0,-1,0,-1,1)};}}private static class O extends Tetromino{ public O(){cells[0]=new Cell(0,4,TetrisGame.O);cells[1]=new Cell(0,5,TetrisGame.O);cells[2]=new Cell(1,4,TetrisGame.O);cells[3]=new Cell(1,5,TetrisGame.O);states=new State[]{new State(0,0,0,1,1,0,1,1),new State(0,0,0,1,1,0,1,1)};}}private static class Z extends Tetromino{ public Z(){cells[0]=new Cell(1,4,TetrisGame.Z);cells[1]=new Cell(0,3,TetrisGame.Z);cells[2]=new Cell(0,4,TetrisGame.Z);cells[3]=new Cell(1,5,TetrisGame.Z);states=new State[]{new State(0,0,-1,-1,-1,0,0,1),new State(0,0,-1,1,0,1,1,0)};}}public static Tetromino randomOne(){Random r=new Random();int type=r.nextInt(7);switch(type){case0:return new T();case1:return new I();case2:return new S();case3:return new J();case4:return new L();case5:return new O();case6:return new Z();}return null;}//右旋转方法public void rotateRight(){index++;State s=states[index%states.length];//s是旋转状态数量Cell c=cells[0];int row=c.getRow();int col=c.getCol();//设置其他三格子位置cells[1].setRow(row+s.row1);cells[1].setCol(col+s.col1);cells[2].setRow(row+s.row2);cells[2].setCol(col+s.col2);cells[3].setRow(row+s.row3);cells[3].setCol(col+s.col3);}public void rotateLeft(){index--;State s=states[index%states.length];Cell c=cells[0];int row=c.getRow();int col=c.getCol();//设置其他三格子位置cells[1].setRow(row+s.row1);cells[1].setCol(col+s.col1);cells[2].setRow(row+s.row2);cells[2].setCol(col+s.col2);cells[3].setRow(row+s.row3);cells[3].setCol(col+s.col3);}class State{int row0,col0,row1,col1,row2,col2,row3,col3;public State(int row0,int col0,int row1,int col1,int row2, int col2,int row3,int col3){super();this.row0=row0;this.col0=col0;this.row1=row1;this.col1=col1;this.row2=row2;this.col2=col2;this.row3=row3;this.col3=col3;}}}。