俄罗斯方块

本文详细介绍了如何使用Java实现经典游戏俄罗斯方块,包括图形界面初始化、方块形状构建、方块存储与下落的算法以及游戏核心组件如事件监听的实现。通过创建GameStart、Shapes和RussiaGame类,实现了方块的旋转、移动、消除行和游戏结束判断等功能,同时提供了图形界面交互和键盘监听。
摘要由CSDN通过智能技术生成

俄罗斯方块

俄罗斯方块

我们通过四个部分来完成这个项目

一、初始化图形界面

首先创建一个GameStart类来实现图形界面并串接起我们所有的部件

public class GameStart extends JFrame {	
		public GameStart() {
		init();
		}
		public static void main(String[] args) {	//主方法执行
		new GameStart();
		}
	

主要部分如下:

private void init() {

		setTitle("俄罗斯方块");
		RussiaGame rus = new RussiaGame();
		JMenuBar menu = new JMenuBar();

		setJMenuBar(menu);
		JMenu help = new JMenu("帮助");
		help.setActionCommand("help");
		JMenuItem about = help.add("关于");
		about.setActionCommand("about");
		about.addActionListener(new ActionListener() {

			//初始“ 关于框中的内容 ”
		public void actionPerformed(ActionEvent e) {
				StringBuilder sbd = new StringBuilder();	//对字符串的修改比string buffer 更快
				sbd.append("作者:刘昊鑫,陈东升");
				if (e.getActionCommand().equals("about"))	//当点击关于的子菜单时
					JOptionPane.showMessageDialog(null, sbd.toString());	//调用了j option pane 类中的方法生成消息对话框 ,null为正前方位置显示

			}
		});
		add(rus, java.awt.BorderLayout.CENTER); 	//大框架中添加组件
	    addKeyListener(rus); //键盘监听
		menu.add(help);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setUndecorated(false);	//不隐藏边框
		setSize(500, 500);
		setLocation(300,200); 
		setVisible(true);
  
		setResizable(false);

		}

	
		}

二、构建方块形状

方块组合形状通过三维数组表示,1表示该处有方块,0表示没有
创建shapes类实现
代码如下:

public class Shapes {

	 /**
	  * 初始化形状
	  */
	 public static final int [][][]SHAPES=
	 {
	 /*************T******************/	 
	 {{0,0,0,0,0},
	  {0,0,0,0,0}	,
	  {0,1,1,1,0},	
	  {0,0,1,0,0},
	  {0,0,0,0,0}
	 },
	 /***********反L****/
	 {{0,0,0,0,0},
	 {0,0,1,0,0},
     {0,0,1,0,0},	 
     {0,1,1,0,0},
	 {0,0,0,0,0}
	 },
	  /************口***************add*/
	 {{0,0,0,0,0},
	  {0,0,0,0,0}	,
	  {0,1,1,0,0},
	  {0,1,1,0,0},
	  {0,0,0,0,0},
	 },
	  /************L****************/
	 {{0,0,0,0,0},
	 {0,1,0,0,0},
	 {0,1,0,0,0},	 
	 {0,1,1,0,0},
	 {0,0,0,0,0}
	 },	
	
	 /*************Z****************/
	 {{0,0,0,0,0},
     {0,0,0,0,0},
	 {0,1,1,0,0},	 
	 {0,0,1,1,0},
	 {0,0,0,0,0}
	 },	
		 
	 /*************1****************/
	 {{0,1,0,0,0},
	 {0,1,0,0,0}	,
	 {0,1,0,0,0},	 
	 {0,1,0,0,0},
	 {0,0,0,0,0}
     },
	 /*************反Z****************/
	 {{0,0,0,0,0},
	 {0,0,0,0,0},
	 {0,0,1,1,0},	 
	 {0,1,1,0,0},
	 {0,0,0,0,0}
	 },
	 {{0,0,0,0,0},
	 {0,0,0,0,0}	,
	 {0,0,0,0,0},	 
	 {1,1,1,1,0},
	 {0,0,0,0,0}
	 }	 
	 };
	 

三、方块的存储与下落

1、存方块

/**
	 * 存方块
	 * 方块数组
	 * @param shapeMap
	 */
	public static final void wirte(int [][] shapeMap,int row,int column){
		try {
			File fl=new File("shape.txt");
			if(!fl.exists()){
				return ;
			}
			BufferedWriter bft=new BufferedWriter(new FileWriter(fl));
			
			//用字节缓冲流写入构建游戏时的方块边界
			  for(int i=0;i<row;i++){
			    	for(int j=0;j<column;j++){
			    		bft.append(shapeMap[i][j]+"");
			    	}
			    	bft.append("\n");
			    }
			  bft.flush();	//刷新缓存
			  bft.close();
		} catch (Exception e) {
		}
		
		
	}

2、写方块

/**
	 * 写方块
	 * @return
	 * 方块数组
	 */
	public static final int [][]read(int row,int column) {
      		int [][]shapeMap=new int[row][column];
      		try {
      			
      			File fl=new File("shape.txt");
      			if(!fl.exists()){
      				fl.mkdir();
      			}
      		   BufferedReader bfd=new BufferedReader(new FileReader(fl));
      		   String read=null;
      		   int index=0;
      		   while((read=bfd.readLine())!=null){
      			  char[]ary= read.toCharArray();		//将fl中的数据传到字符数组中储存
      			   for(int i=0,size=ary.length;i<size;i++){
      				   char ch=ary[i];
      				   shapeMap[index][i]=Integer.parseInt(ch+"");	//将string解析为整数存入shape map数组
      			   }
      			   index++;
      		   }
      		   bfd.close();
      		}
      		catch (Exception e) {
			}
		return shapeMap;
	}
	
	
	

注意这里的shape.text就是游戏中方块活动的边界
在这里插入图片描述

同下
在这里插入图片描述

四、游戏组件

(1) 核心算法的实现

1、首先创建一个RussiaGame类,定义我们需要的量

public class RussiaGame extends JPanel implements Serializable, KeyListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/**
	 * 数组的行数和列数 初始话界面的大小为 22行 12列
	 */
	private static final int ROW_SIZE = 22, COLUMN_SIZE = 12;
	/**
	 * 界面宽度
	 */
	private static final int WIDTH_SIZE = 344;

	/**
	 * 界面高度
	 */
	private static final int HEIGHT_SIZE = 375;
	/**
	 * 储存格子的数组
	 */
	private static int[][] shapeMap = new int[ROW_SIZE][COLUMN_SIZE];

	int[][] random;// 用来装载随机形状的二维数组
	/**
	 * 用来记载移动的坐标
	 */
	private int move_x = 5, move_y = -2;
	/**
	 * 方块大小
	 */
	private static final int SQUARE_SIZE = 20;
	/**
	 * 方块矩阵的大小
	 */
	private static final int MATRIX_SIZE = 5;

	/**
	 * 分数
	 */
	private int scores = 0;

	/**
	 * 判断游戏是否结束的标志
	 */
	private boolean canPlay = true;
	/**
	 * 休眠时间
	 */
	private int SLEEP_TIME = 500;
	/**
	 * 暂停游戏
	 */
	private boolean SLEEPGAME = true;
	/**
	 * ENTER 建的值用来标记暂停事件
	 */
	static final int VK_ENTER = 10;
	/**
	 * 下一个方块
	 * 
	 */

	static int[][] next;
	/**
	 * 用来装载当期方块和下一个方块
	 */
	private LinkedList<int[][]> shapeList = new LinkedList<int[][]>();

2、获取墙壁大小

/**传入墙壁大小
	 * 
	 * 
	 */
	private void initShape() {
		shapeMap = FileHelpers.read(ROW_SIZE, COLUMN_SIZE);
	}

3、判断方块能否旋转

/**
	 * 判断是否能旋转 如果下一个图形所在的坐标没有越界和没有
	 * 
	 * @return true转换 false 不转换
	 */
	private boolean canTurnChange(int[][] newRandom) {
		boolean canTurn = true;
		if (move_y > 0)
			for (int i = MATRIX_SIZE - 1; i >= 0; i--) {
				for (int j = 0; j < MATRIX_SIZE; j++) {
					if (newRandom[i][j] == 1) {
						if (shapeMap[move_y + i][move_x + j] == 1
								|| shapeMap[move_y + i][move_x + j] == 2) {
							canTurn = false;
							break;
						}

					}
				}
			}
		if (move_x == -1 || move_y == 18 || move_x == 8) {
			canTurn = false;
		}
		if (random == Shapes.SHAPES[5] || random == Shapes.SHAPES[7]) {
			if (move_y >= -1 && shapeMap[move_y + 1][move_x + 3] == 1) {
				canTurn = false;
			}

			if (move_x == 0 || move_x == 3 || move_y == 3) {
				canTurn = false;
			}
		}
		return canTurn;
	}

4、消行


	/**
	 * 消行
	 * 
	 * @return
	 */
	private int[][] delteLine() {
		int count = 0;
		for (int i = ROW_SIZE - 2; i >= 1; i--) {
			if (canDelete(shapeMap[i])) {
				scores += 10;
				for (int j = 1; j <= 10; j++) {
					shapeMap[i][j] = 0;
					count++;
				}
			}
			if (count >= 1) {
				int[] temp = shapeMap[i];
				shapeMap[i] = shapeMap[i - 1];
				shapeMap[i - 1] = temp;
			}
		}
		return shapeMap;
	}

	protected boolean canDelete(int[] line) {

		for (int i = 1, size = 10; i <= size; i++) {
			if (line[i] == 0) {
				return false;
			}
		}
		return true;
	}

5、重新开始的实现


	/**
	 * 重新开始游戏
	 */
	private void restart() {

		for (int i = 0; i <= 20; i++) {
			for (int j = 1; j <= 10; j++) {
				shapeMap[i][j] = 0;
			}
		}
		canPlay = true;

	}

6、判断游戏是否结束


	/**
	 * 判断游戏是否结束
	 * 
	 * @return
	 */
	private boolean gameOver() {
		int[] top = shapeMap[1];// 获得顶部
		for (int i = 1; i < COLUMN_SIZE - 1; i++) {
			if (top[i] == 1) {
				return true;
			}
		}

		return false;
	}

7、方块是否能下落

/**
	 * 方块能是否能下落
	 * 
	 * @return
	 */
	private boolean canDown() {
		boolean canDown = true;
		int x = move_x == -1 ? move_x + 2 : move_x + 1;
		int len = shapeLength();
		if (move_y >= 0 && move_x < 12)
			for (int i = MATRIX_SIZE - 1; i >= 0; i--) {
				for (int j = 0; j < MATRIX_SIZE; j++) {
					if (random[i][j] == 1) {
						if (shapeMap[move_y + i + 1][move_x + j] == 1) {
							canDown = false;
							break;
						}

					}
				}
			}

		if (move_y >= 0 && x < 12 && shapeMap[move_y + len][x] == 2) {
			canDown = false;
		}

		return canDown;

	}

8、获取方块长度


	/**
	 * 获得方块的长度
	 */
	private int shapeLength() {
		for (int leng = 5; leng >= 1; leng--) {
			int[] number = random[leng - 1];
			for (int index = 0; index < 5; index++) {
				if (number[index] == 1) {
					return leng;
				}
			}
		}

		return -1;

	}

9、画方块及组件

	/**
	 * 画当前方块
	 * 
	 * @param gs
	 */
	private void paintCurr(java.awt.Graphics gs, int[][] randoms) {
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++) {
				if (randoms[i][j] == 1) {
					gs.setColor(Color.yellow);
					gs.fill3DRect(j * SQUARE_SIZE + move_x * SQUARE_SIZE, i
							* SQUARE_SIZE + move_y * SQUARE_SIZE, SQUARE_SIZE,
							SQUARE_SIZE, true);

				}
			}
		}
	}

	private void paintNext(java.awt.Graphics gs) {
		for (int i = 0; i < 4; i++) {
			for (int j = 0; j < 4; j++) {
				if (next[i][j] == 1) {
					gs.setColor(Color.YELLOW);
					gs.fill3DRect(j * SQUARE_SIZE + 250, i * SQUARE_SIZE,
							SQUARE_SIZE, SQUARE_SIZE,true);


				}
			}
		}
	}

	@Override
	// 画组件的方法
	protected void paintComponent(java.awt.Graphics g) {
		super.paintComponent(g);
		Image bc = new ImageIcon("222.jpg").getImage();
		g.drawImage(bc, 0, 0, getWidth(), getHeight(), this);
		g.setColor(Color.red);
		g.drawString("分数" + scores, 250, 150);
		g.drawString("F5 清屏重新开始  ", 250, 190);
		g.drawString("ENTER 暂停\\开始游戏", 250, 230);
		g.drawString("ESC 退出并保存", 250, 270);

		Color green = new Color(140, 140, 140);
		g.setColor(green);

		paintNext(g);
		// 绘制当前方块
		paintCurr(g, random);
		// 画已经落下的方块
		for (int j = 0; j < ROW_SIZE; j++) {
			for (int i = 0; i < COLUMN_SIZE; i++) {
				if (shapeMap[j][i] == 1) {
					g.setColor(green);
					g.fill3DRect(i * SQUARE_SIZE, j * SQUARE_SIZE, SQUARE_SIZE,
							SQUARE_SIZE, true);
				}
				if (shapeMap[j][i] == 2) {
					g.setColor(Color.black);
					g.drawRect(i * SQUARE_SIZE, j * SQUARE_SIZE, SQUARE_SIZE,
							SQUARE_SIZE);

				}

			}
		}

	};

10、画墙壁

/**
	 * 画墙壁的方法
	 */
	private void clearMap() {
		shapeMap = new int[ROW_SIZE][COLUMN_SIZE];

		for (int i = 0; i < ROW_SIZE; i++) {
			shapeMap[i][0] = 2;
			shapeMap[i][COLUMN_SIZE - 1] = 2;
		}
		// 画底部的格子
		for (int j = 0; j < COLUMN_SIZE; j++) {
			shapeMap[ROW_SIZE - 1][j] = 2;
		}
	}

	private void turnLef() {
		System.out.println(SQUARE_SIZE*(move_x+3));
		if (move_y>=0&&canLeft()) {
			move_x--;
			shapeMap = delteLine();
			repaint();
		}

	}

11、生成随机形状

	/**
	 * 生成随机形状
	 * 
	 * @return
	 */
	private void randomShape() {
		Random ran = new Random();
		if (shapeList.size() == 2) {
			shapeList.removeFirst();
			shapeList.addLast(Shapes.SHAPES[ran.nextInt(8)]);
		} else {

			shapeList.addFirst(Shapes.SHAPES[ran.nextInt(8)]);
			shapeList.addLast(Shapes.SHAPES[ran.nextInt(8)]);
		}
		random = shapeList.getFirst();
		next = shapeList.getLast();

	}

	

12、判断左右移动

/**
	 * 判断是否能左移
	 * 
	 * @return
	 */
	private boolean canLeft() {
		boolean canLeft = true;
		if(move_y>=0)
		for (int i = MATRIX_SIZE - 1; i >= 0; i--) {
			for (int j = 0; j < MATRIX_SIZE; j++) {
				if (random[i][j] == 1) {
					if (shapeMap[move_y + i][move_x + j - 1] == 1
							|| shapeMap[move_y + i][move_x + j - 1] == 2) {
						canLeft = false;
						break;
					}
				}
			}
		}

		return canLeft;
	}
/**
	 * 判断是否能右移
	 * 
	 * @return
	 */
	private boolean canRight() {
		boolean canRight = true;
		if(move_y>=0)
		for (int i = MATRIX_SIZE - 1; i >= 0; i--) {
			for (int j = 0; j < MATRIX_SIZE; j++) {
				if (random[i][j] == 1) {
					if (shapeMap[move_y + i][move_x + j + 1] == 1
							|| shapeMap[move_y + i][move_x + j + 1] == 2) {
						canRight = false;
						break;
					}

				}
			}
		}

		return canRight;
	}

	private void turnRight() {
		if (move_y>=0&&canRight()) {
			move_x++;
			shapeMap = delteLine();
			repaint();
		}

	}

	private void turnUp() {

		int[][] newRandom = xuanzhuan();
		if (canTurnChange(newRandom)) {
			if (random == Shapes.SHAPES[5]) {
				newRandom = Shapes.SHAPES[7];

			} else if (random == Shapes.SHAPES[7]) {

				newRandom = Shapes.SHAPES[5];
			}

			random = newRandom;
		}

		shapeMap = delteLine();
		repaint();
	}

	private void turnDown() {
		if (canDown())
			move_y++;
		shapeMap = delteLine();
		repaint();

	}

14、方块的旋转

/**
	 * 旋转矩阵
	 * 
	 * @return
	 */
	public int[][] xuanzhuan() {
		int[][] newRandom = new int[random.length][random[0].length];
		if (random == Shapes.SHAPES[2]) {
			return random;
		}
		for (int i = 0; i < random.length; i++) {
			for (int j = 0; j < random[0].length; j++) {
				newRandom[j][random[0].length - i - 1] = random[i][j];
			}
		}

		return newRandom;
	}

(2)事件的监听和实现

为便于常量的使用,我们在其内部再定义一个GameLitsner类

class GameLitsner implements ActionListener {
	
		
		public void actionPerformed(ActionEvent e) {
			if (SLEEPGAME)
				if (gameOver() == false) {
					if (canDown()) {
						move_y++;
						shapeMap = delteLine();
						repaint();
					} else {
						shapeMap = delteLine();
						addPoint();
						move_x = 5;
						move_y = -5;
						randomShape();
						repaint();

					}
				}

				else
					canPlay = false;

		}

	}

	/**
	 * 得分
	 */
	private void addPoint() {
		int len = shapeLength();
		int index = len == 3 ? 3 : 4;
		for (int i = 0; i < 5; i++, index--) {
			for (int j = 0; j < 5; j++) {
				if (random[i][j] == 1 && move_y + len - index >= 0) {
					shapeMap[move_y + len - index][move_x + j] = 1;
				}
			}
		}

	}

	
	/**
	 * 
	 */
	public void keyPressed(KeyEvent key) {

		if (canPlay && SLEEPGAME)
			switch (key.getKeyCode()) {
			// 改变形状
			case KeyEvent.VK_UP:
			case KeyEvent.VK_W:
				turnUp();
				break;
			// 下落
			case KeyEvent.VK_DOWN:
			case KeyEvent.VK_S:
				turnDown();
				break;
			// 左移
			case KeyEvent.VK_LEFT:
			case KeyEvent.VK_A:
				turnLef();
				break;
			// 右移
			case KeyEvent.VK_RIGHT:
			case KeyEvent.VK_D:
				turnRight();
				break;
			case KeyEvent.VK_ESCAPE:
				int isSave = JOptionPane.showConfirmDialog(null, "是否保存游戏");
				if (isSave == 0) {
					FileHelpers.wirte(shapeMap, ROW_SIZE, COLUMN_SIZE);
				} else {
					clearMap();
					FileHelpers.wirte(shapeMap, ROW_SIZE, COLUMN_SIZE);
				}
				System.exit(1000);

				break;

			}
		if (key.getKeyCode() == KeyEvent.VK_F5) {

			restart();

		}
		if (key.getKeyCode() == VK_ENTER) {
			SLEEPGAME = SLEEPGAME == true ? false : true;

		} else if (canPlay == false) {
			JOptionPane.showMessageDialog(null, "Game Over!");
			scores = 0;
		}
	}

	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}

}

效果如下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值