本人开发环境,MyEclipse8.5,安装JDK版本为1.7:键盘监听器不能相应。
但如果使用MyEclipse自带的JDK的话,键盘监听事件会有响应,但是需要重新加载JDK,请求大神指点原因!!!程序入口在类Tetris中,键盘监听事件也在此类中
#类Cell
package com.MyTetris;
import java.awt.image.BufferedImage;
public class Cell {
private int row;
private int col;
private BufferedImage image; // 贴图
/**
* 构造器
*
* @param row
* @param col
* @param image
*/
public Cell(int row, int col, BufferedImage image) {
super(); // 调用Object构造器
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;
}
/**
* 重写toString方法,方便调试
*/
public String toString() {
return row + "," + col;
}
public void moveRigth() {
col++;
}
public void moveLeft() {
col--;
}
public void softDrop() {
row++;
}
}
#类Tetromino
package com.MyTetris;
import java.util.Arrays;
import java.util.Random;
public abstract class Tetromino extends Object {
protected Cell[] cells = new Cell[4];
protected Stage[] stages; // 不同的方块旋转所用的数据不一样
protected int index = 10000; // 取第几组数据旋转,index指下标
/**
* 用于存储方块旋转时的数据
*
* @author Administrator
*
*/
protected class Stage {
int row0, col0;
int row1, col1;
int row2, col2;
int row3, col3;
public Stage(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;
}
}
/**
* 随机生成7种方块之一,是公共方法 。 工厂方法:用于生产(创建)一个对象的方法,封装了复杂的创建过程,方便使用 用在创建对象过程复杂的情况
*/
public static Tetromino randomOne() {
Random random = new Random();
int type = random.nextInt(7); // 随机生成[0,7)
switch (type) {
case 0:
return new T();
case 1:
return new I();
case 2:
return new S();
case 3:
return new O();
case 4:
return new J();
case 5:
return new L();
case 6:
return new Z();
}
return null; // 必须写,不然编译时报错:编译时不看对象,只看引用类型
}
/**
* 测试方法,用来测试随机生成方法
*/
public String toString() {
return Arrays.toString(cells);
}
/**
* 当前对象的4格方块整体向左移动
*/
public void moveLeft() {
cells[0].moveLeft();
cells[1].moveLeft();
cells[2].moveLeft();
cells[3].moveLeft();
}
public void moveRigth() {
for (int i = 0; i < cells.length; i++) {
cells[i].moveRigth();
}
}
public void softDrop() {
this.cells[0].softDrop();
this.cells[1].softDrop();
this.cells[2].softDrop();
this.cells[3].softDrop();
}
/**
* 向右旋转算法
*/
public void rotateRigth() {
// 1、计算index++
// 2、获取Sn(4组数据0,1,2,3)
// 3、获取当前轴
// 4、格子0是轴,不变
// 5、格子1的行列变成:轴+Sn[1]
// 6、格子2的行列变成:轴+Sn[2]
// 7、格子3的行列变成:轴+Sn[3]
index++;
Stage s = stages[index % stages.length];
Cell o = cells[0];
int row = o.getRow();
int col = o.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--;
Stage s = stages[index % stages.length];
Cell o = cells[0];
int row = o.getRow();
int col = o.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 T extends Tetromino {
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);
stages = new Stage[4];
stages[0] = new Stage(0, 0, 0, -1, 0, 1, 1, 0); // s0
stages[1] = new Stage(0, 0, -1, 0, 1, 0, 0, -1); // s1
stages[2] = new Stage(0, 0, 0, 1, 0, -1, -1, 0); // s2
stages[3] = new Stage(0, 0, 1, 0, -1, 0, 0, 1); // s3
}
}
class I extends Tetromino {
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);
stages = new Stage[2];
stages[0] = new Stage(0, 0, 0, -1, 0, 1, 0, 2);
stages[1] = new Stage(0, 0, -1, 0, 1, 0, 2, 0);
}
}
class S extends Tetromino {
public S() {
cells[0] = new Cell(0, 4, Tetris.S);
cells[1] = new Cell(0, 5, Tetris.S);
cells[2] = new Cell(1, 3, Tetris.S);
cells[3] = new Cell(1, 4, Tetris.S);
stages = new Stage[2];
stages[0] = new Stage(0, 0, 0, 1, 1, -1, 1, 0);
stages[1] = new Stage(0, 0, 1, 0, -1, -1, 0, -1);
}
}
class J extends Tetromino {
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, 5, Tetris.J);
stages = new Stage[4];
stages[0] = new Stage(0, 0, 0, -1, 0, 1, 1, 1);
stages[1] = new Stage(0, 0, -1, 0, 1, 0, 1, -1);
stages[2] = new Stage(0, 0, 0, 1, 0, -1, -1, -1);
stages[3] = new Stage(00, 0, 1, 0, -1, 0, -1, 1);
}
}
class L extends Tetromino {
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, 3, Tetris.L);
stages = new Stage[4];
stages[0] = new Stage(0, 0, 0, -1, 0, 1, -1, 1);
stages[1] = new Stage(0, 0, -1, 0, 1, 0, 1, 1);
stages[2] = new Stage(0, 0, 0, 1, 0, -1, 1, -1);
stages[3] = new Stage(0, 0, 1, 0, -1, 0, -1, -1);
}
}
class O extends Tetromino {
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);
stages = new Stage[2];
stages[0] = new Stage(0, 0, 0, 1, 1, 0, 1, 1);
stages[1] = new Stage(0, 0, 0, 1, 1, 0, 1, 1);
}
}
class Z extends Tetromino {
public Z() {
cells[0] = new Cell(1, 4, Tetris.Z);
cells[1] = new Cell(0, 3, Tetris.Z);
cells[2] = new Cell(0, 4, Tetris.Z);
cells[3] = new Cell(1, 5, Tetris.Z);
stages = new Stage[2];
stages[0] = new Stage(0, 0, -1, -1, -1, 0, 0, 1);
stages[1] = new Stage(0, 0, -1, 1, 0, 1, 1, 0);
}
}
#类Tetris
package com.MyTetris;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.Timer;
import java.util.TimerTask;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Tetris extends JPanel {
public static final int ROWS = 20;
public static final int COLS = 10;
/** 墙 */
private Cell[][] wall = new Cell[ROWS][COLS];
/** 正在下落的方块 */
private Tetromino tetromino;
/** 下一个进场的方块 */
private Tetromino nextOne;
/** 消失的行数 */
private int lines;
/** 得分 */
private int score;
/** 定时器 */
private Timer timer;
/** 得分表,对应销毁行数得分 */
private int[] souseTable = new int[] { 0, 10, 100, 1000, 10000 };
/**
* 在Tetris中添加背景图片引用
*/
private static BufferedImage backGround;
private static BufferedImage gameOver;
public static BufferedImage T;
public static BufferedImage I;
public static BufferedImage S;
public static BufferedImage J;
public static BufferedImage L;
public static BufferedImage Z;
public static BufferedImage O;
// 静态代码块
static {
try {
// 图片加载,注意:Tetris类必须与tetris.png(图片)在一个包中,图片名字不能错
backGround = ImageIO.read(Tetris.class.getResource("tetris.png"));
gameOver = ImageIO.read(Tetris.class.getResource("game-over.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"));
J = ImageIO.read(Tetris.class.getResource("J.png"));
L = ImageIO.read(Tetris.class.getResource("L.png"));
O = ImageIO.read(Tetris.class.getResource("O.png"));
Z = ImageIO.read(Tetris.class.getResource("Z.png"));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 重写paint方法
*/
@Override
public void paint(Graphics g) {
// background:图片对象;0, 0:图片位置,与画板顶角位置相同,图片有多大,展示多大
// 绘制图片背景
g.drawImage(backGround, 0, 0, null);
g.translate(15, 15); // 整体向下漂移
paintWall(g); // 画墙
paintTetromino(g); // 画正在下落的格子
paintNextOne(g); // 画下一个出场的格子
paintScore(g);
}
/**
* 画分数
*
* @param g
*/
public void paintScore(Graphics g) {
int x = 294;
int y = 160;
// 设置分数和销毁行数的字体颜色
g.setColor(new Color(0xD667799));
Font font = new Font(Font.MONOSPACED, Font.BOLD, 28);
g.setFont(font);
g.drawString("SCORE:" + score, x, y);
y += 56;
g.drawString("LINES:" + lines, x, y);
}
/**
* 封装绘制正在下落的格子的算法
*/
public void paintTetromino(Graphics g) {
if (tetromino == null) {
return;
}
Cell[] cells = tetromino.cells;
for (int i = 0; i < cells.length; i++) {
// cells指下落的所有格子
// 将正在下落的某一个格子的引用赋值给cell
Cell cell = cells[i];
int x = cell.getCol() * CELL_SIZE;
int y = cell.getRow() * CELL_SIZE;
g.drawImage(cell.getImage(), x, y, null);
}
}
/**
* 绘制下一个要出场的格子的算法
*/
public void paintNextOne(Graphics g) {
if (nextOne == null) {
return;
}
Cell[] cells = nextOne.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 static final int CELL_SIZE = 26;
private void paintWall(Graphics g) {
for (int row = 0; row < wall.length; row++) {
for (int col = 0; col < wall[row].length; col++) {
Cell cell = wall[row][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, y, null);
}
}
}
}
/**
* @param args
*/
public static void main(String[] args) {
System.out.println("1111");
JFrame frame = new JFrame("Tetris");
Tetris tetris = new Tetris(); // Tetris继承了JPanel,所以Tetris就是面板
frame.add(tetris);
frame.setSize(541, 588);
frame.setLocationRelativeTo(null);
/**
* 设置默认关闭操作 operation操作
*/
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true); // 尽快调用paint()方法
tetris.action();
}
/**
* 添加软件启动(action)方法
*/
public void action() {
// wall[1][8] = new Cell(0, 0, T);
// wall[8][2] = new Cell(0, 0, J);
// Tetromino引用了randomOne创建的对象
tetromino = Tetromino.randomOne();
nextOne = Tetromino.randomOne();
this.repaint(); // 重新绘制界面,尽快自动自动调用paint()方法
KeyListener l = new KeyAdapter() {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_RIGHT:
// tetromino.moveRigth();
System.out.println("按下->键");
Tetris.this.moveRigthAction();
break;
case KeyEvent.VK_LEFT:
// tetromino.moveLeft();
moveLeftAction();
break;
case KeyEvent.VK_DOWN:
// tetromino.softDrop();
softDropAction();
break;
case KeyEvent.VK_SPACE:
hardDropAction();
break;
case KeyEvent.VK_UP:
// tetromino.rotateRigth();
rotateRigthAction();
}
repaint();
}
};
this.addKeyListener(l);
this.setFocusable(true);
// 添加定时任务,让方块定时下落
timer = new Timer();
TimerTask task = new TimerTask() {
@Override
public void run() {
softDropAction();
repaint();
}
};
timer.schedule(task, 1000, 1000);
}
/**
* 变形方法
*/
public void rotateRigthAction() {
tetromino.rotateRigth();
if (outOfBounds() || coincide()) {
tetromino.rotateLeft();
}
}
/**
* 正在下落的4格方块右移
*/
public void moveRigthAction() {
// 正在下落的方块右移
tetromino.moveRigth();
// 判断是否出界;coincide:重合;检查4格方块是否与墙上方块是否重合
if (outOfBounds() || coincide()) {
// 如果出界,立刻左移
tetromino.moveLeft();
}
}
/**
* 正在下落的4格方块左移
*/
public void moveLeftAction() {
tetromino.moveLeft();
if (outOfBounds() || coincide()) {
tetromino.moveRigth();
}
}
/**
* 检查正在下落的格子是否出界
*
* @return
*/
public boolean outOfBounds() {
// 正在下落的4个格子中任意一个格子出界,就是出界
Cell[] cells = tetromino.cells;
for (int i = 0; i < cells.length; i++) {
Cell cell = cells[i];
int row = cell.getRow();
int col = cell.getCol();
if (row < 0 || row >= ROWS || col < 0 || col >= COLS) {
return true;
}
}
return false;
}
/**
* 判断格子是否重合
*
* @return
*/
public boolean coincide() {
Cell[] cells = tetromino.cells;
for (int i = 0; i < cells.length; i++) {
Cell cell = cells[i];
int row = cell.getRow();
int col = cell.getCol();
if (wall[row][col] != null) {
return true;
}
}
return false;
}
/**
* 下落方法,直接下落到底部,并且进入到墙内
*/
public void hardDropAction() {
while (canDrop()) {
tetromino.softDrop();
}
landIntoWall();
int lines = destroyLines();
this.lines += lines;
this.score += souseTable[lines];
if (!isGameOver()) {
tetromino = nextOne;
nextOne = tetromino.randomOne();
}
}
/**
* 下落方法,一格一格的下落
*/
public void softDropAction() {
// 1、如果4格方块能下落,就下落
// 2、如果不能下落,就着陆到墙里面
// 3、检查行是否满,销毁已经慢的行
// 4、检查游戏是否结束,如果没有结束,就产生下一个方块
if (canDrop()) {
tetromino.softDrop();
} else {
this.landIntoWall();
int lines = destroyLines();
// 计算销毁的行数
this.lines = this.lines + lines;
// 计算得分
this.score = this.score + souseTable[lines];
if (!isGameOver()) {
tetromino = nextOne;
nextOne = tetromino.randomOne();
}
}
}
/**
* 检查方块是否能够下落
*/
private boolean canDrop() {
// 1、4格方块的任意一个格子的行达到19,就不能下落
// 2、4格方块的任意一个格子,对应墙上的下方出现格子,则不能下落
// 3、先判断第一 种情况,不然会出现下标越界的错误
Cell[] cells = tetromino.cells;
for (int i = 0; i < cells.length; i++) {
Cell cell = cells[i];
int row = cell.getRow();
if (row == ROWS - 1) {
return false;
}
}
// 判断格子下方的墙上是否有格子
for (int i = 0; i < cells.length; i++) {
Cell cell = cells[i];
int row = cell.getRow();
int col = cell.getCol();
if (wall[row + 1][col] != null) {
return false;
}
}
return true;
}
/**
* 着陆到墙里面
*/
private void landIntoWall() {
// 获取每个格子的行、列,根据每个格子的位置,将格子订到墙上
Cell[] cells = tetromino.cells;
for (Cell cell : cells) {
int row = cell.getRow();
int col = cell.getCol();
wall[row][col] = cell;
}
}
/**
* 销毁已经满的行,返回销毁行数
*/
private int destroyLines() {
// 从0~19逐行查找,如果找到满行,就删除这行
int lines = 0;
for (int row = 0; row < ROWS; row++) {
if (isFullCells(row)) {
deleteRow(row);
lines++;
}
}
return lines;
}
/**
* 检查row行的格子是否是满的
*
* @param row
* @return
*/
private boolean isFullCells(int row) {
Cell[] line = wall[row];
/**
* for(int i=0;i<line.length;i++){ Cell cell = line[i]; }
*/
for (Cell cell : line) {
if (cell == null) {
return false;
}
}
return true;
}
/**
* 删除row行格子
*
* @param row
*/
private void deleteRow(int row) {
for (int i = row; i >= 1; i--) {
// 复制:从wall[i-1] -> wall[i]
System.arraycopy(wall[i - 1], 0, wall[i], 0, COLS);
}
Arrays.fill(wall[0], null);
}
/**
* 检查游戏是否结束
*/
private boolean isGameOver() {
// 如果下一个方块没有出场位置了,则游戏结束:就是下一个出场的方块每个格子行列对应的墙上位置如果有方块,就游戏结束
Cell[] cells = nextOne.cells;
for (int i = 0; i < cells.length; i++) {
Cell cell = cells[i];
int row = cell.getRow();
int col = cell.getCol();
if (wall[row][col] != null) {
return true;
}
}
return false;
}
}