Java实现简易俄罗斯方块
作者:辞久
本文实例为大家分享了Java实现简易俄罗斯方块的具体代码,供大家参考,具体内容如下
一、将对象抽象为类
首先考虑俄罗斯方块游戏中含有哪些具体的对象,对象中含有哪些具体属性和方法,然后用代码来实现。
建立如下类:
Cell类:代表最小的方格单位,构成7种图形的最基本图形。
含有row(行号),col(列号),image(对应的图片)属性,
含有left(左移),right(右移),drop(下落)方法。
Tetromino类:代表由4个最小方格构成的7种图形的合集。
含有cells(四个方块)属性,
含有moveLeft(四格方块向左移动),moveRight(四格方块向右移动),softDrop(软下落),randomOne(随机生成一个四格方格)方法。
T类继承于Tetromino类:
I类继承于Tetromino类:
L类继承于Tetromino类:
S类继承于Tetromino类:
Z类继承于Tetromino类:
O类继承于Tetromino类:
J类继承于Tetromino类:
Tetris类:俄罗斯方块的主方法类,包括了游戏运行过程中所需要的众多方法。
含有currentOne(正在下落的四格方块),nextOne(即将下落的四格方块),Cell[][]wall(二维数组的表格,代表墙)属性。
二、类的实现
Notes:各类实现过程中要符合Javabean规范。
Cell类:
package com.tetris; import java.awt.image.BufferedImage; /* * 俄罗斯方块中的最小单位:方格 * 特征(属性): * row--行号 * col--列号 * image--对应的图片 * * 行为(方法) * left(); * right(); * drop(); */ public class Cell { private int row; //行 private int col; //列 private BufferedImage image; public Cell(int row, int col, BufferedImage image) { super(); this.row = row; this.col = col; this.image = image; } public Cell() { super(); // TODO Auto-generated constructor stub } 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 BufferedImage getImage() { return image; } public void setImage(BufferedImage image) { this.image = image; } @Override public String toString() { return "(" + row + ", " + col + ")"; } //向左移动 public void left(){ col--; } //向右移动 public void right(){ col++; } //向下移动 public void drop(){ row++; } }
Tetromino类:
package com.tetris; import java.util.Arrays; import javax.xml.transform.Templates; /* * 四格方块 * 属性: * ---cells,----四个方块 * * 行为: * moveLeft() * moveRight() * softDrop() */ public class Tetromino { protected Cell[] cells=new Cell[4]; //四格方块向左移动 //实际上:就是每个方块向左移动 public void moveLeft(){ for (int i = 0; i < cells.length; i++) { cells[i].left(); } } //四格方块向右移动 //实际上:就是每个方块向右移动 public void moveRight(){ for (int i = 0; i < cells.length; i++) { cells[i].right(); } } //四格方块向下移动 //实际上:就是每个方块向下移动 public void softDrop(){ for (int i = 0; i < cells.length; i++) { cells[i].drop(); } } @Override public String toString() { return "[" + Arrays.toString(cells) + "]"; } //随机生成一个四格方块 public static Tetromino randomOne(){ Tetromino t = null; int num=(int)(Math.random()*7); switch (num){ case 0:t=new T();break; case 1:t=new O();break; case 2:t=new I();break; case 3:t=new J();break; case 4:t=new L();break; case 5:t=new S();break; case 6:t=new Z();break; default: break; } return t; } }
T类继承于Tetromino类:
package com.tetris; public class T extends Tetromino { //提供构造器,进行初始化 //T型的四格方块的位置 public T(){ cells[0]=new Cell(0,4,Tetris.T); cells[1]=new Cell(0,3,Tetris.T); cells[2]=new Cell(0,5,Tetris.T); cells[3]=new Cell(1,4,Tetris.T); } }
I类继承于Tetromino类:
package com.tetris; public class I extends Tetromino { //提供构造器,进行初始化 //T型的四格方块的位置 public I(){ cells[0]=new Cell(0,4,Tetris.I); cells[1]=new Cell(0,3,Tetris.I); cells[2]=new Cell(0,5,Tetris.I); cells[3]=new Cell(0,6,Tetris.I); } }
L类继承于Tetromino类:
package com.tetris; public class L extends Tetromino { //提供构造器,进行初始化 //T型的四格方块的位置 public L(){ cells[0]=new Cell(0,4,Tetris.L); cells[1]=new Cell(0,3,Tetris.L); cells[2]=new Cell(0,5,Tetris.L); cells[3]=new Cell(1,5,Tetris.L); } }
S类继承于Tetromino类:
package com.tetris; public class S extends Tetromino { //提供构造器,进行初始化 //T型的四格方块的位置 public S(){ cells[0]=new Cell(1,4,Tetris.S); cells[1]=new Cell(0,3,Tetris.S); cells[2]=new Cell(0,4,Tetris.S); cells[3]=new Cell(1,5,Tetris.S); } }
Z类继承于Tetromino类:
package com.tetris; public class Z extends Tetromino { //提供构造器,进行初始化 //T型的四格方块的位置 public Z(){ cells[0]=new Cell(0,4,Tetris.Z); cells[1]=new Cell(0,5,Tetris.Z); cells[2]=new Cell(1,3,Tetris.Z); cells[3]=new Cell(1,4,Tetris.Z); } }
O类继承于Tetromino类:
package com.tetris; public class O extends Tetromino { //提供构造器,进行初始化 //T型的四格方块的位置 public O(){ cells[0]=new Cell(0,4,Tetris.O); cells[1]=new Cell(0,5,Tetris.O); cells[2]=new Cell(1,4,Tetris.O); cells[3]=new Cell(1,5,Tetris.O); } }
J类继承于Tetromino类:
package com.tetris; public class J extends Tetromino { //提供构造器,进行初始化 //T型的四格方块的位置 public J(){ cells[0]=new Cell(0,4,Tetris.J); cells[1]=new Cell(0,3,Tetris.J); cells[2]=new Cell(0,5,Tetris.J); cells[3]=new Cell(1,3,Tetris.J); } }
Tetris类:
//属性:正在下落的四格方块 private Tetromino currentOne=Tetromino.randomOne(); //属性:将要下落的四格方块 private Tetromino nextOne=Tetromino.randomOne(); //属性:墙,20行10列的表格 宽度为26 private Cell[][]wall=new Cell[20][10];
三、绘制俄罗斯方块图形
个人理解,这个过程就是显现出游戏界面的过程,当然啦,这一步主要是加载静态资源,诸如图片,音频和视频等。
1.加载静态资源
俄罗斯方块主要应用的静态资源是图片,所以我们用到的是IO类中的ImageIO类中的ImageIO.read方法,导入各类四格方块的图形图片以及背景图片,具体代码如下:
public static BufferedImage T; public static BufferedImage I; public static BufferedImage O; public static BufferedImage J; public static BufferedImage L; public static BufferedImage S; public static BufferedImage Z; public static BufferedImage background; static{ try { /* * getResouce(String url) * url:加载图片的路径 * 相对位置是同包下 */ T=ImageIO.read(Tetris.class.getResource("T.png")); I=ImageIO.read(Tetris.class.getResource("I.png")); O=ImageIO.read(Tetris.class.getResource("O.png")); J=ImageIO.read(Tetris.class.getResource("J.png")); L=ImageIO.read(Tetris.class.getResource("L.png")); S=ImageIO.read(Tetris.class.getResource("S.png")); Z=ImageIO.read(Tetris.class.getResource("Z.png")); background=ImageIO.read(Tetris.class.getResource("tetris.png")); } catch (Exception e) { e.printStackTrace(); } }
2.画游戏静态界面
在这一部分中需要绘制三部分,用到了三种方法,分别是paintCurrentOne(正在下落的四格方块),paintNextOne(等待进入的四格方块),paintWall(背景墙)。
绘制需要重写JPanel类中的paint(Graphics g)方法,具体代码实现如下:
public void paint(Graphics g){ //绘制背景 /* * g:画笔 * g.drawImage(image,x,y,null) * x:开始绘制的横坐标 * y:开始绘制的纵坐标 */ g.drawImage(background,0,0,null); //平移坐标轴 g.translate(15, 15); //绘制墙 paintWall(g); //绘制正在下落的四格方块 paintCurrentOne(g); //绘制下一个即将下落的四格方块 paintNextOne(g); } /* * 绘制下一个即将下落的四格方块 * 绘制到面板的右上角的相应区域 */ public void paintNextOne(Graphics g){ //获取nextOne对象的四个元素 Cell[] cells=nextOne.cells; for (Cell c:cells) { //获取每一个元素的行号和列号 int row=c.getRow(); int col=c.getCol(); //横坐标和纵坐标 int x=col*CELL_SIZE+260; int y=row*CELL_SIZE+26; g.drawImage(c.getImage(), x, y, null); } } /* * 绘制正在下落的四格方块 * 取出数组的元素 * 绘制数组的图片 * 横坐标x * 纵坐标y */ public void paintCurrentOne(Graphics g){ Cell[] cells=currentOne.cells; for (Cell c:cells) { int x=c.getCol()*CELL_SIZE; int y=c.getRow()*CELL_SIZE; g.drawImage(c.getImage(), x, y, null); } } /* * 墙是20行,10列的表格 * 是一个二维数组 * 用双层循环 * 绘制正方形 */ public void paintWall(Graphics a){ //外层循环控制行数 for (int i = 0; i < 20; i++) { //内层循环控制列数 for (int j = 0; j < 10; j++) { int x=j*CELL_SIZE; int y=i*CELL_SIZE; Cell cell=wall[i][j]; a.drawRect(x, y, CELL_SIZE, CELL_SIZE); if(wall[i][j]==null){ a.drawRect(x, y, CELL_SIZE, CELL_SIZE); }else{ a.drawImage(cell.getImage(),x,y,null); } } } }
实现效果如下:
3.让四格方块动起来
光有静态的画面是不能够称为游戏的,还有要动态效果和接收键盘指令并响应的能力。
(1)动态效果
俄罗斯方块中的动态效果主要指7种四格方块拥有自动下降,软下降,左移,右移,旋转的能力,分别使用canDrop(),softDropAction(),moveLeftAction(),moveRightAction(),spinCellAction()方法来实现,与此同时,还需根据游戏规则注意四格方块可能遇到触碰到左右边界,方块覆盖等错误,在此使用outOfBounds(),coincide()方法来避免。当不能下落时,需要将四格方块,嵌入到墙中,使用landToWall()方法。
具体代码实现如下:
/* * 使用left键控制向左的行为 */ public void moveLeftAction() { currentOne.moveLeft(); if(outOfBounds()||coincide()){ currentOne.moveRight(); } } /* * 使用right键控制向右的行为 */ public void moveRightAction() { currentOne.moveRight(); if(outOfBounds()||coincide()){ currentOne.moveLeft(); } } /* * 使用down键控制四格方块的下落 */ public void softDropAction() { if(canDrop()){ currentOne.softDrop(); }else{ landToWall(); currentOne=nextOne; nextOne=Tetromino.randomOne(); } } public boolean outOfBounds(){ Cell[] cells=currentOne.cells; for (Cell c : cells) { int col=c.getCol(); if(col<0||col>9){ return true; } } return false; } public boolean coincide(){ Cell[] cells=currentOne.cells; for (Cell c : cells) { int row=c.getRow(); int col=c.getCol(); if(wall[row][col]!=null){ return true; } } return false; } public boolean canDrop(){ Cell[] cells=currentOne.cells; for (Cell c: cells) { //获取每个元素的行号 /* * 判断: * 只要有一个元素的下一行上有方块 * 或者只要有一个元素到达最后一行,就不能下落了 */ int row=c.getRow(); int col=c.getCol(); if(row==19){ return false; } if(wall[row+1][col]!=null){ return false; } } return true; } /* * 当不能下落时,需要将四格方块,嵌入到墙中 * 也就是存储到二维数组中相应的位置上 */ public void landToWall(){ Cell[] cells=currentOne.cells; for (Cell c : cells) { //获取最终的行号和列号 int row=c.getRow(); int col=c.getCol(); wall[row][col]=c; } }
实现效果如下:
(2)接收键盘指令并响应
游戏和玩家紧密关联,所以接下来我们需要使玩家能够通过键盘控制四格方块移动。
因此,我们要开启键盘监听来达到玩家实时控制游戏的目的,并且通过不同的按键调用四格方块移动的不同方法。
具体代码如下:
//开启键盘监听事件
KeyListener l=new KeyAdapter() {
public void keyPressed(KeyEvent e){
//获取以下键子的代号
int code=e.getKeyCode();
switch (code) {
case KeyEvent.VK_DOWN:
softDropAction();break;
case KeyEvent.VK_LEFT:
moveLeftAction();break;
case KeyEvent.VK_RIGHT:
moveRightAction();break;
}
repaint();
}
};
this.addKeyListener(l);
this.requestFocus();
while(true){
/*
* 当程序运行到此,会进入睡眠状态
* 睡眠时间为300毫秒,单位为毫秒
* 300毫秒后会自动执行后续代码
*/
try {
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(canDrop()){
currentOne.softDrop();
}else{
landToWall();
//将下一个下落的四格方块赋值给正在下落的变量
currentOne=nextOne;
nextOne=Tetromino.randomOne();
}
/*
* 下落之后,要重新进行绘制,才会看到下落后的位置
* repaint方法也是Jpanel类中提供的
* 此方法调用了paint方法
*/
repaint();
}
}
实现效果如下:
更多关于俄罗斯方块的文章,请点击查看专题:《俄罗斯方块》
更多精彩游戏,请参考专题《java经典小游戏》
更多有趣的经典小游戏实现专题,分享给大家:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。