一.通过分析游戏界面,抽象出几种类型:
1.Cell(格子类)
2.Tetromino(四格方块类):七种组合的父类
根据父类,定义七种子类:T、I、O、J、L、S、Z
3.Tetris(主类) extends JPanel
提供静态属性,加载静态资源
Cell
属性:row(行号),col(列号),Image(图片)
方法:softDrop(); //下落
moveLeft(); //向左移动
moveRight(); //向右移动
Tetromino
方法:softDrop(); //下落
moveLeft(); //向左移动
moveRight(); //向右移动
randomOne(); //随机生成四格方块
Tetris
方法:paint(Graphics g);//绘制方法
paintWall(g); //绘制墙
piantCurrentOne(g);//绘制正在下落的四格方块
paintNextOne(g); //绘制下一个四格方块
将七个子类封装到Tetromino,初始化四格方块的初始位置
以“L”型为例
初始位置:cell[0]=(0,4);
cell[1]=(0,3);
cell[2]=(0,5);
cell[3]=(1,3);
二.类的实现:
cell类:
package com.tetris;
import java.awt.image.BufferedImage;
/*俄罗斯方块的最小单位:方格
* 特征(属性):
* row--行号
* col--列号
* image--对应的图片
*
* 行为(方法):
* left()
* right()
* down()
*/
public class Cell {
private int row;
private int col;
private BufferedImage image;
public Cell () {}
public Cell(int row, int col, BufferedImage 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 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;
/*
* 四格方块
* 属性:
* ------cells----四个方块
* 行为:
* moveLeft()
* moveRight()
* softDrop()
*/
public class Tetromino {
protected Cell[] cells=new Cell[4];
public void moveLeft() {
for(int i=0;i<cells.length;i++) {
Cell cell=cells[i];
cell.left();
}
}
public void moveRight() {
for(Cell c:cells) {
c.right();
}
}
public void softDrop() {
for(Cell c:cells) {
c.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;
}
return t;
}
}
Tetris类:
/**属性:正在下落的四格方块*/
private Tetromino currentOne=Tetromino.randomOne();
/**属性:将要下落的四格方块*/
private Tetromino nextOne=Tetromino.randomOne();
/**属性:墙 20行10列的表格 宽度为26*/
private Cell[][] wall=new Cell[20][10];
三.绘制俄罗斯方块图形
加载静态资源:
private static final int CELL_SIZE=26;
public static BufferedImage T;
public static BufferedImage I;
public static BufferedImage O;
public static BufferedImage L;
public static BufferedImage S;
public static BufferedImage Z;
public static BufferedImage J;
public static BufferedImage Background;
static {
try {
/*getResource(String url)
* url:加载图片的路径
* 相对位置是同包下
*/
T=ImageIO.read(Tetris.class.getResource("T.png"));
O=ImageIO.read(Tetris.class.getResource("O.png"));
I=ImageIO.read(Tetris.class.getResource("I.png"));
J=ImageIO.read(Tetris.class.getResource("J.png"));
S=ImageIO.read(Tetris.class.getResource("S.png"));
L=ImageIO.read(Tetris.class.getResource("L.png"));
Z=ImageIO.read(Tetris.class.getResource("Z.png"));
Background=ImageIO.read(Tetris.class.getResource("tetris.png"));
}catch(Exception e) {
e.printStackTrace();
}
}
生成游戏界面:
public void paint(Graphics g) {
//绘制背景
/*
* g:画笔
* g.drawImage(image,x,y,null)
* image:绘制的图片
* x:开始绘制的横坐标
* y:开始绘制的纵坐标
*/
g.drawImage(Background, 0, 0, null);
//平移坐标轴
g.translate(15, 15);
//绘制墙
paintWall(g);
//绘制正在下落的四格方块
piantCurrentOne(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 piantCurrentOne(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];
if(cell==null) {
a.drawRect(x, y, CELL_SIZE, CELL_SIZE);
}else {
a.drawImage(cell.getImage(),x,y,null);
}
}
}
}
添加动态效果和接收键盘指令并响应的能力:
public void start() {
//开启键盘监听事件
KeyListener l=new KeyAdapter() {
/**
* keyPressed()是键盘按钮按下去调用的方法
*/
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) {
try {
/**
* 当程序运行到此,会进入睡眠状态
* 睡眠时间为300毫秒
* 300毫秒后,会自动执行后续代码
*/
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(canDrop()) {
currentOne.softDrop();
}else {
landToWall();
//将下一个下落的四格方块赋值给正在下落的变量
currentOne=nextOne;
nextOne=Tetromino.randomOne();
}
/**
* 下落之后,进行重新绘制,才会看到下落后的方块
* repaint方法 也是JPanel类中提供的
* 此方法中调用了paint方法
*/
repaint();
}
}
//使用向下键控制向下的行为
public void softDropAction() {
if(canDrop()) {
currentOne.softDrop();
}else {
landToWall();
currentOne=nextOne;
nextOne=Tetromino.randomOne();
}
}
//使用LEFT控制向左的行为
public void moveLeftAction() {
currentOne.moveLeft();
if(outOfBounds()||coincide()) {
currentOne.moveRight();
}
}
//使用向右键控制向右的行为
protected void moveRightAction() {
currentOne.moveRight();
if(outOfBounds()||coincide()) {
currentOne.moveLeft();
}
}
private 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;
}
private 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 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;
}
}