欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

俄罗斯方块

程序员文章站 2023-12-23 19:09:57
...

先看看效果:

俄罗斯方块

思路:整个游戏界面是一个画布,左边画游戏的地图和当前块,右边是游戏规则。游戏地图map[][]是一个二维int数组。主要是当前块的处理方式,我这里是使用一个四乘四的矩阵来表示的,1表示有格子,0表示空的。然后是边框使用3来说表示,位运算来判断是否与边界或下面的堆积块碰撞。(方块的三维数组可能不太好理解,本来是一个四维数组来的,但四维数组更不好理解,所以就缩减了一维,第一维表示方块的类型,第二维表示方块的变形,第三位有16个数,代表四乘四的矩阵,就是具体方块的形状的表示)

public class Main {
	public static void main(String[] args) {
		TetrisFrame tFrame = new TetrisFrame();
		tFrame.setVisible(true);
	}
}

import java.awt.Container;

import javax.swing.JFrame;

public class TetrisFrame extends JFrame{
	private static final long serialVersionUID = 1L;
	TetrisFrame() {
		super("TETRIS");
		setBounds(500, 80, 500, 580);
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		setResizable(false);
		Container container = getContentPane();
		
		//左边游戏显示
		TetrisPanel tPanel = new TetrisPanel();
		addKeyListener(tPanel.listener);
		container.add(tPanel);
	}
}

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

public class TetrisPanel extends JPanel {
	private static final long serialVersionUID = 1L;

	private int line = 35;
	private int row = 20;
	private int score;
	private int boxSize = 15;
	private int map[][];

	// 当前块的信息
	private int blockStyle;// 块的类型
	private int turnState;// 该类型的第几个
	private int x;// 当前块的左上角x坐标(第几列的位置)
	private int y;// 当前块的左上角y坐标(第几行的位置)

	// 定时器
	Timer timer;
	int delay = 200;// 初始化为0.2秒走一次

	// 监听器
	Listener listener = new Listener();

	// 方块
	int shapes[][][] = new int[][][] {
			// I 
		{ { 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
			{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 },
			{ 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 },
			{ 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0 } },
			// S
			{ { 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 },
					{ 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0 } },
			// Z
			{ { 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
					{ 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 } },
			// J
			{ { 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0 },
					{ 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
			// O
			{ { 1, 1, 0, 0, 1, 1, 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 },
					{ 1, 1, 0, 0, 1, 1, 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 } },
			// L
			{ { 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, { 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
					{ 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
			// T
			{ { 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 },
					{ 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
					{ 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0 } } };

	TetrisPanel() {
		iniGame();
		nextBox();
		timer = new Timer(delay, listener);
		timer.start();
	}

	// 初始化游戏
	private void iniGame() {
		delay = 200;
		score = 0;
		if(timer != null){// 第一次初始化timer是空的
			timer.setDelay(delay);
			timer.restart();
		}
		map = new int[line+1][row+1];
		for (int i = 0; i < line; i++) {
			map[i][0] = 3;
			map[i][row-1] = 3;
		}
		for (int i = 0; i < row; i++) {
			map[line-1][i] = 3;
		}
	}

	// 产生下一个方块
	private void nextBox() {
		x = 8;
		y = 0;
		Random random = new Random(System.currentTimeMillis());
		blockStyle = random.nextInt(7);
		turnState = random.nextInt(4);
		repaint();
		
		//游戏结束处理
		//产生一个方块的时候判断是否与堆积块碰撞
		if(collide(x, y, blockStyle, turnState)==0 && timer.isRunning()){
			timer.stop();
			int i = JOptionPane.showConfirmDialog(null, "Game Over!真的菜,是否再战一局?","游戏结束",JOptionPane.YES_NO_OPTION);
			if(i==JOptionPane.YES_OPTION){
				iniGame();
			}else if(i==JOptionPane.NO_OPTION){
				System.exit(0);
			}
		}
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		g.fillRect(boxSize, boxSize, row*boxSize,line*boxSize);
		// 当前块
		for(int i=0;i<16;i++){
			if(shapes[blockStyle][turnState][i]==1){
				g.setColor(Color.white);
				g.fillRect((i%4+x+1)*boxSize, (i/4+y)*boxSize, boxSize, boxSize);
				g.setColor(Color.lightGray);
				g.drawRect((i%4+x+1)*boxSize, (i/4+y)*boxSize, boxSize, boxSize);
			}
		}
		// 堆积块+地图
		for (int i = 0; i < line; i++) {// 行
			for (int j = 0; j < row; j++) {// 列
				if(map[i][j]==1){
					//画块
					g.setColor(Color.gray);
					g.fillRect(j*boxSize+boxSize,i*boxSize+boxSize,boxSize,boxSize);
					//画块的分界线
					g.setColor(Color.lightGray);
					g.drawRect(j*boxSize+boxSize,i*boxSize+boxSize,boxSize,boxSize);
				}else if(map[i][j]==3){
					g.setColor(Color.darkGray);
					g.fillRect(j*boxSize+boxSize,i*boxSize+boxSize,boxSize,boxSize);
					g.setColor(Color.lightGray);
					g.drawRect(j*boxSize+boxSize,i*boxSize+boxSize,boxSize,boxSize);
				}
			}
		}
		Font font1 = new Font("方正舒体", Font.BOLD, 22);
		Font font2 = new Font("方正楷体", Font.BOLD, 20);
		g.setFont(font1);
		g.setColor(Color.black);
		g.drawString("当前得分:"+score, 330, 100);
		g.setFont(font2);
		g.drawString("游戏规则", 358, 180);
		g.drawString("方向键控制左右", 325, 210);
		g.drawString("方向键上控制变形", 325, 240);
		g.drawString("空格控制开始暂停", 325, 270);
		g.setFont(font1);
		g.drawString("作者 :逸川同学", 320, 380);
		g.drawString("QQ :1228127092", 315, 415);
	}
	
	//判断块是否有碰撞
	private int collide(int x,int y, int blockStyle, int turnState){
		for (int i = 0; i < 4; i++) {//行
			for (int j = 0; j < 4; j++) {//列
				// 到达边界,底部
				if((shapes[blockStyle][turnState][i*4+j] & map[i+y][j+x])==1) {
					return 0;
				}
			}
		}
		return 1;
	}

	// 将块添加到地图
	private void addMap(int x, int y) {
		for (int i = 0; i < 4; i++) {// 行
			for (int j = 0; j < 4; j++) {// 列
				if (shapes[blockStyle][turnState][i*4+j] == 1) {
					map[y+i][x+j] = 1;
				}
			}
		}
		delMap();
	}

	private void delMap() {
		for (int i = 1; i < line-1; i++) {
			int t = 1;
			for (int j = 1; j < row-1; j++) {
				t = t&map[i][j];
			}
			if(t == 1){
				for (int j = i; j > 0; j--) {
					for (int k = 1; k < row-1; k++) {
						map[j][k] = map[j-1][k]; 
					}
				}
				score+=10;
				delay-=10;
			}
		}
	}

	private void down() {
		if (collide(x,y+1, blockStyle, turnState)==0){
			addMap(x,y);
			nextBox();
		}else {
			y++;
		}
		repaint();
	}
	private void change() {
		if(collide(x, y, blockStyle, (turnState+1)%4)!=0){
			turnState = (turnState+1)%4;
		}
	}
	private void left() {
		if(x>0){
			x -= collide(x-1, y, blockStyle, turnState);
		}
		repaint();
	}
	private void right() {
		if(x<row-1){
			x += collide(x+1, y, blockStyle, turnState);
		}
		repaint();
	}

	class Listener extends KeyAdapter implements ActionListener {
		//定时器监听
		@Override
		public void actionPerformed(ActionEvent e) {
			down();
		}
		//键盘监听
		@Override
		public void keyPressed(KeyEvent e) {
			switch (e.getKeyCode()) {
			case KeyEvent.VK_UP:
				change();
				break;
			case KeyEvent.VK_LEFT:
				left();
				break;
			case KeyEvent.VK_RIGHT:
				right();
				break;
			case KeyEvent.VK_DOWN:
				down();
				break;
			case KeyEvent.VK_SPACE:
				if(timer.isRunning()){
					timer.stop();
				}else {
					timer.start();
				}
			}
		}
	}
}


上一篇:

下一篇: