java俄罗斯方块简单实现,新手适合学习

备注,程序采用了 substance.jar ,若缺少可以去掉main方法前面的代码。

一、方块类

import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;


public class BlockGrid16 {
	
	/*所有方块网格类型*/
	public static final int[][] MODELS = {
		{0x0063,0x0264,0x0063,0x0264}, //Z
		{0x006c,0x0462,0x006c,0x0462}, //反Z
		{0x0446,0x002e,0x0622,0x00e8}, //L
		{0x0226,0x0047,0x0644,0x0071}, //反L
		{0x0027,0x0464,0x0072,0x0131}, //T
		{0x0066,0x0066,0x0066,0x0066}, //田
		{0x000f,0x4444,0x000f,0x4444}, //l
	};
	/*随机数生成器*/
	public static final Random random = new Random();
	/*每一维大小*/
	public static final int dimension = 4;
	/*方块类型*/
	public int type;
	/*方块状态*/
	public int status;
	/*方块速度等级*/
	public int level;
	/*网格模型*/
	public boolean[][] model;
	/*当前所在画布*/
	public Canvas canvas;
	/*网格模型左上角在画布坐标系中的行位置*/
	public int row;
	/*网格模型左上角在画布坐标系中的列位置*/
	public int column;
	/*计时器*/
	public Timer t;
	/*构造方法*/
	public BlockGrid16(Canvas canvas,int level) {
		this.type = random.nextInt(MODELS.length);
		this.status = random.nextInt(MODELS[0].length);
		this.level = level;
		this.canvas = canvas;
		this.row = -999;
		this.column = 4;
		buildModel(MODELS[type][status]);
	}
	/*带参数构造方法*/
	public BlockGrid16(int type,int status,int level,Canvas canvas,int row,int column) {
		this(canvas,level);
		this.type = type;
		this.status = status;
		this.row = row;
		this.column = column;
	}
	
	public void init(){
		row = -3;
		column = 4;
		/*判断游戏是否结束*/
		if (isTouchBottom(row, column)) {
			canvas.isEnd = true;
		}
	}
	/*更新方块模型在画布上的位置*/
	public void update(){ 
		for (int i=0;i<dimension;i++) {
			for (int j=0;j<dimension;j++) {
				if ( canvas.isValidPlace(row + i, column + j) && model[i][j]) {
					canvas.map[row+i][column+j] = true;
				}
			}
		}
	}
	
	/*方块移动*/
	public void moveTo(int r,int c) { 
		/* 判断移动的可能性 */
		if (!moveable(r,c))
			return;
		
		/*擦除方块模型移动前的位置*/
		erase();
		/*调整方块模型位置*/
		row = r;
		column = c;
		/*更新*/
		update();
		
		/*如果已经到达底部,延时1000-level*50 毫秒更换当前方块模型*/
		if (isTouchBottom(row,column)) {
			canvas.haveFullLine();
			t = new Timer();
			t.schedule(new TimerTask(){
				public void run() {
					if(t != null){
						canvas.currBlock = canvas.nextBlock;
						canvas.currBlock.init();
						canvas.nextBlock = new BlockGrid16(canvas,level);
						t = null;
						canvas.repaint();
					}
				}
			}, 1000-level*50);
		}
	}
	
	/*向左移动*/
	public void moveLeft() {
		moveTo(row,column-1);
	}
	
	/*向右移动*/
	public void moveRight() {
		moveTo(row, column+1);
	}
	
	/*向下移动*/
	public void moveDown() {
		if (t != null && isTouchBottom(row,column)) {
			canvas.haveFullLine();
			canvas.currBlock = canvas.nextBlock;
			canvas.currBlock.init();
			canvas.nextBlock = new BlockGrid16(canvas,level);
			canvas.repaint();
			t = null;
		}
		moveTo(row+1, column);
	}
	
	/*移动到底部*/
	public void moveBottom() {
		for (int i=-3;i<Canvas.ROW;i++) {
			if (moveable(i, column) && isTouchBottom(i, column)) {
				t = new Timer();
				moveTo(i, column);
				canvas.haveFullLine();
				canvas.currBlock = canvas.nextBlock;
				canvas.currBlock.init();
				canvas.nextBlock = new BlockGrid16(canvas,level);
				canvas.repaint();
				t = null;
				break;
			}
		}
	}
	/*是否可以移动到指定位置*/
	public boolean moveable(int row,int column) {
		/*擦除当前要移动方块模型所占位置,以免影响判断*/
		erase();
		
		/*判断方块模型每一个单元格将要移动到的位置是否已经被占有*/
		for (int i=0;i<dimension;i++) {
			for (int j=0;j<dimension;j++) {
				/*只需判断方块模型中被占有的单元格*/
				if (model[i][j]) {
					/*判断合法性*/
					if (i + row >= Canvas.ROW || j + column <0 || j + column >= Canvas.COLUMN){
						update();
						return false;
					}
					/*判断将要移动的位置上是否已经被占用*/
					if (canvas.isValidPlace(i+row, j+column) && canvas.map[i+row][j+column]) {
						update();
						return false;
					}
				}
			}
		}
		/*恢复方块模型*/
		update();
		return true;
	}
	
	/*判断方块模型是否到底部*/
	public boolean isTouchBottom(int row,int column) {
		erase();
		for (int i=0;i<dimension;i++) {
			for (int j=0;j<dimension;j++) {
				if (model[i][j]) {
					int nextR = i + 1 + row;
					int nextC = j + column;
					/*若已经到底部*/
					if (nextR == Canvas.ROW) {
						update();
						return true;
					}
					/*判断当前单元格下方的单元格是否已经被占用*/
					if (canvas.isValidPlace(nextR, nextC)) {
						if (canvas.map[nextR][nextC]) {
							update();
							return true;
						}
					}
				}
			}
		}
		update();
		return false;
	}
	
	/*变形*/
	public void rorate() {
		int newStatus = (status + 1)%MODELS[type].length;
		if (!rorateable(MODELS[type][newStatus])) {
			return;
		}else {
			status ++;
		}
		/*擦除原先*/
		erase();
		/*旋转*/
		buildModel(MODELS[type][newStatus]);
		/*更新*/
		update();
	}
	
	//TODO 检查是否可以变形
	public boolean rorateable(int keyCode) {
		erase();
		
		/*初始化临时模型*/
		boolean[][] tempModel = new boolean[dimension][dimension];
		int bitKey = 0x8000;
		for (int i = 0;i<dimension;i++) {
			for (int j = 0;j<dimension;j++) {
				tempModel[i][j] = !((bitKey & keyCode) == 0);
				bitKey = bitKey >> 1;
			}
		}
		
		for (int i=0;i<dimension;i++) {
			for (int j=0;j<dimension;j++) {
				if (tempModel[i][j]) {
					if ( row + i >= Canvas.ROW || column+j < 0 || column +j >=Canvas.COLUMN ) {
						update();
						return false;
					}
				}
			}
		}
		
		update();
		return true;
		
	}
	
	
	/*擦除方块*/ 
	public void erase() {
		for (int i=0;i<dimension;i++) {
			for (int j=0;j<dimension;j++) {
				if ( canvas.isValidPlace(row + i, column + j) && model[i][j]) {
					canvas.map[row+i][column+j] = false;
				}
			}
		}
	}
	/*构建网格模型*/
	public void buildModel(int modelCode) {
		int bitKey = 0x8000;
		model = new boolean[dimension][dimension];
		for (int i = 0;i<dimension;i++) {
			for (int j = 0;j<dimension;j++) {
				model[i][j] = !((bitKey & modelCode) == 0);
				bitKey = bitKey >> 1;
			}
		}
	}
}

二、画布类

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Timer;
import java.util.TimerTask;

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


public class Canvas extends JPanel implements KeyListener{
	private static final long serialVersionUID = -1354251777507926593L;
	
	/*游戏参数*/
	public static final int COLUMN = 10;
	public static final int ROW = 18;
	public static final int SIZE = 24;
	public static final Color backgroundColor = new Color(0xf1,0xf1,0xf1);
	public static final Color blockColor = Color.YELLOW;
	public static final Color cblockColor = Color.ORANGE;
	public static final int[] PADDING = {10,20,10,20};
	public static final int WIDTH = PADDING[1] + PADDING[3] + SIZE*COLUMN;
	public static final int HEIGHT= PADDING[0] + PADDING[2] + SIZE*ROW;
	public final int borderWidth = 1;
	public int oneLineScore = 100;
	
	public int level; //游戏当前等级
	public int score; //游戏当前分数
	
	/*游戏对象*/
	public BlockGrid16 currBlock; //当前操作的方块网格
	public BlockGrid16 nextBlock; //下一个将要操作的方块网格
	public boolean[][] map; //游戏图  18X10 网格
	public Timer downTimer; //下落计数器
	
	/*游戏标志*/
	public boolean isEnd = true; /*游戏是否结束*/
	public boolean isPause = false; /*游戏是否暂停*/

	/*主窗口对象*/
	public GameApplication app;
	
	/*线程*/
	public ChangeBlockThread cbThread; /*切换方块线程*/
	
	public Canvas(GameApplication app) {
		this.app = app;
		setPreferredSize(null);         /*设置面板大小*/
		map = new boolean[ROW][COLUMN]; /*初始化地图数组*/
		setBackground(backgroundColor); /*设置背景颜色*/
		addKeyListener(this); /*注册键盘监听*/
		cbThread = new ChangeBlockThread();
	}
	
	public void gameInit(int level) { 
		/*标志初始化*/
		isEnd = false;
		isPause = false;
		/*地图初始化*/
		map = new boolean[ROW][COLUMN];
		/*当前操作方块初始化*/
		currBlock = new BlockGrid16(this,level);
		currBlock.init();
		/*下一个操作方块初始化*/
		nextBlock = new BlockGrid16(this,level);
		/*等级*/
		this.level = level;
		/*分数*/
		this.score = 0;
		/*重绘*/
		repaint();
	}
	
	/*判断指定位置是否为合法位置*/
	public boolean isValidPlace(int row,int column) {
		if ( row < 0 || row >= ROW || column < 0 || column >= COLUMN)
			return false;
		return true;
	}
	
	/*检查是否底部为满行*/
	public void haveFullLine() {
		for (int i=0;i<ROW;i++) {
			boolean isFullLine = true;
			for (int j=0;j<COLUMN;j++) {
				if (!map[i][j]) {
					isFullLine = false;
					break;
				}
			}
			if (isFullLine) {
				clearLine(i);
				i -- ;
			}
		}
	}
	
	/*删除指定行*/
	public void clearLine(int row) {
		for (int i=row;i>0;i--) {
			for (int j=0;j<COLUMN;j++) {
				map[i][j] = map[i-1][j];
			}
		}
		score += oneLineScore;
	}
	
	@Override
	public void setPreferredSize(Dimension arg0) {
		super.setPreferredSize(new Dimension(WIDTH,HEIGHT));
	}
	
	@Override
	public void paint(Graphics g) {
		super.paint(g);
		/*画游戏边界*/
		g.drawLine(PADDING[3], PADDING[0], PADDING[3]+SIZE*COLUMN, PADDING[0]);
		g.drawLine(PADDING[3], PADDING[0] + SIZE*ROW, PADDING[3]+SIZE*COLUMN, PADDING[0]+ SIZE*ROW);
		g.drawLine(PADDING[3], PADDING[0], PADDING[3], PADDING[0] + ROW*SIZE);
		g.drawLine(PADDING[3]+SIZE*COLUMN, PADDING[0], PADDING[3]+SIZE*COLUMN, PADDING[0] + ROW*SIZE);
		
		/*更新当前操作方块位置*/
		if(currBlock != null)
			currBlock.update();
		
		/*画方块*/
		if(map != null)
			for ( int i=0;i<ROW;i++) {
				for ( int j=0;j<COLUMN;j++){
					if (map[i][j]) { 
						/*画矩形*/
						g.drawRect(PADDING[3] + j*SIZE, PADDING[0] + i*SIZE, SIZE, SIZE);
						/*选择颜色变填充矩形*/
						Color oldColor = g.getColor();
						g.setColor(Color.PINK);
						g.fillRect(PADDING[3] + j*SIZE + borderWidth, PADDING[0] + i*SIZE + borderWidth, SIZE -borderWidth , SIZE -borderWidth);
						/*还原颜色*/
						g.setColor(oldColor);
					}
				}
			}
	}

	/*键盘监听*/
	@Override
	public void keyPressed(KeyEvent e) {
		int key = e.getKeyCode();
		if ( (key >=37 && key <= 40 || key == 32) && !isEnd) {
			if (key == 37) {
				currBlock.moveLeft();
			} else if (key == 39) {
				currBlock.moveRight();
			} else if (key == 40) {
				currBlock.moveDown();
			} else if (key == 32) {
				currBlock.moveBottom();
			} else if (key == 38) {
				currBlock.rorate();
			}
			System.out.println(score);
			repaint();
		}else if ( key == 80) { //P
			
		}else if ( key == 78) { //N
			if (downTimer != null) {
				downTimer.cancel();
				downTimer = null;
			}
			if (isEnd != true)
				if( JOptionPane.showConfirmDialog(this, "您确定要重新开始吗?", "新的游戏", 
					JOptionPane.YES_NO_OPTION) == 0) {	
					gameInit(app.gameLevel);
					downTimer = new Timer();
					downTimer.schedule(new TimerTask(){
						public void run() {
							currBlock.moveDown();
							repaint();
						}
					}, 0, 1000-level*50);
					return;
				}
			gameInit(app.gameLevel);
			downTimer = new Timer();
			downTimer.schedule(new TimerTask(){
				public void run() {
					currBlock.moveDown();
					repaint();
				}
			}, 0, 1000-level*50);
		}else if ( key == 82) { //R
			
		}else if ( key == 79) { //O
			
		}
		
		//上:38
		//下:40
		//左:37
		//右:39
		//P:80
		//N:78
		//R:82
		//O:79
		
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}
	
	
	/*方块下落控制的线程*/
	class ChangeBlockThread extends Thread{
		
		public long delay = 1000;
		
		@Override
		public void run() {
			try {
				Thread.sleep(delay);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
	
	
}

三、主界面类

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;


public class GameApplication extends JFrame implements ActionListener{
	private static final long serialVersionUID = -1653174441012031192L;

	   private Canvas canvas;
	
	public int gameLevel = 10;
	/*工具栏*/    
	private JToolBar toolbar;   
	
	/*构造方法*/
	public GameApplication() {
		init();
	}
	
	/*界面初始化函数*/
	private void init() {
		setTitle("俄罗斯方块                     by:luiyikeke");
		add(createOrGetCanvas());
		add(createOrGetToolBar(),BorderLayout.NORTH);
		pack();
		setLocationRelativeTo(null);
		canvas.requestFocus();
		setResizable(false);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	/*创建画布面板,位于分割面板的左部*/
	private Canvas createOrGetCanvas(){
		if(canvas == null){
			canvas = new Canvas(this);
		}
		return canvas;
	}
	
	/*创建工具栏*/
	private JToolBar createOrGetToolBar() {
		if ( toolbar == null) {
			toolbar = new JToolBar();
			toolbar.add(createButtonWithAction("重新开始(N)"));
			toolbar.add(createButtonWithAction("暂停(P)"));
			toolbar.add(createButtonWithAction("排行榜(R)"));
			toolbar.add(createButtonWithAction("设置(O)"));
		}
		return toolbar;
	}
	
	/*创建按钮,并且带有事件监听*/
	private JButton createButtonWithAction(String btnString) { 
		JButton btn = new JButton(btnString);
		btn.addActionListener(this);
		return btn;
	}
	
	// ------------------------------------
	// 事件监听
	// ------------------------------------
	@Override
	public void actionPerformed(ActionEvent e) {
		String command = e.getActionCommand();
		if("重新开始(N)".equals(command)) {
			canvas.gameInit(gameLevel);
		}else if("暂停(P)".equals(command)) {
			
		}else if("排行榜(R)".equals(command)) {
			
		}else if("设置(O)".equals(command)) {
			
		}
		canvas.requestFocus();
	}
	
	public static void main(String[] args) {
		try {
			// 设置程序将采用的界面风格
			UIManager
					.setLookAndFeel("org.jvnet.substance.skin.SubstanceOfficeSilver2007LookAndFeel");

		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {
			e.printStackTrace();
		}
		new GameApplication().setVisible(true);
	}

	
}


  • 4
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值