俄罗斯方块

先看看效果:

思路:整个游戏界面是一个画布,左边画游戏的地图和当前块,右边是游戏规则。游戏地图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();
				}
			}
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值