JAVA小游戏----俄罗斯方块

一、画墙

import javax.swing.JFrame;

public class Tetris extends JFrame {
	TetrisPanel TP = new TetrisPanel();

	public static void main(String[] args) {
		new Tetris().launchFrame();
	}
	
	public void launchFrame(){
		setBounds(1000, 100, 405, 570);  
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setVisible(true);
        setResizable(false);
        
        add(TP);//添加TetrisPanel面板
	}
}
import java.awt.Color;
import java.awt.Graphics;

import javax.swing.JPanel;

public class TetrisPanel extends JPanel{
	/*
	 *思想是使用二维数组表示平面,用其中的值标记哪里是墙壁哪里是方块
	 * 
	 */
	private int[][] map = new int[27][20];
	
	//初始化数组,即构造墙壁
		public TetrisPanel(){
		for(int i=0;i<map.length;i++){
			for(int j=0;j<map[i].length;j++){
				if(j==0||j==map[i].length-1||i==map.length-1){
					map[i][j]=3;
				}
				else map[i][j]=0;
			}
		  }
		}
		
		@Override
		public void paint(Graphics g) {		
			super.paint(g);
			//画墙壁
			for(int i=0;i<map.length;i++){
				for(int j=0;j<map[i].length;j++){
					if(map[i][j]==3){
						g.setColor(Color.gray);
						g.fillRect( j*20, i*20, 20, 20);
					}
					if(map[i][j]==1){
						g.setColor(Color.blue);
						g.fillRect(j*20, i*20, 20, 20);
					}
				}
			}
		}
}

二、画俄罗斯方块

1.定义方块

//方块形状定义
	public static int[][][][] shapes=new int[][][][]{  //四维数组,七种形状,每种形状四个方块组成
    	
    	//用多维数组表示方块,在为1的地方填色
            //T  四种形态
            {{{0,1,0}, {1,1,1}, {0,0,0}},  //第一行,第二行,第三行
             {{0,0,1}, {0,1,1}, {0,0,1}}, //朝左
             {{1,1,1}, {0,1,0}, {0,0,0}}, //朝下 
             {{1,0,0}, {1,1,0}, {1,0,0}}},
            //这是两种形态,不能通过旋转得到
            //L  四种形态
            {{{0,1,0}, {0,1,0}, {0,1,1}},  
             {{0,0,1}, {1,1,1}, {0,0,0}},  
             {{1,1,0}, {0,1,0}, {0,1,0}},  
             {{0,0,0}, {1,1,1}, {1,0,0}}},  
            //J  四种形态
            {{{0,1,0}, {0,1,0}, {1,1,0}},  
             {         {1,1,1}, {0,0,1}},  
             {{0,1,1}, {0,1,0}, {0,1,0}},  
             {{1,0,0}, {1,1,1}        }},  
            //S  两种形态
            {{{0,1,1}, {1,1,0} ,{0,0,0}},  
             {{0,1,0}, {0,1,1}, {0,0,1}}},  
             //Z  两种形态
            {{{1,1,0}, {0,1,1}, {0,0,0}},  
             {{0,1,0}, {1,1,0}, {1,0,0}}},  
             //田  一种形态
            {{{1,1}, {1,1}}},  
            //I  两种形态
            {{{1,1,1,1}		 },  //填0会造成无法靠近边框
             {{1},{1},{1},{1}}}  
    };

2.生成方块(TetrisPanel中添加)

        //新方块的初始位置
	int Block_x ;
	int Block_y ;
	
	private int blockType; // 方块类型(第一维数组,共七种)
	private int turnState; // 方块形态(第二维数组,I是两种,L是四种...)
//生成方块
	public void newBlock(){
		//初始在顶部中间位置
		Block_x = 9;
		Block_y = 0;
		
		blockType = (new Random()).nextInt(Tetris.shapes.length); // 不大于方块种类的随机数
		turnState = (new Random()).nextInt(Tetris.shapes[blockType].length); // 不大于方块形态的随机数
		
		repaint();
	}

在paint函数中添加绘制方块的代码

//画方块
for(int i=0;i<Tetris.shapes[blockType][turnState].length;i++){
    for(int j=0;j<Tetris.shapes[blockType][turnState][i].length;j++){
	if(Tetris.shapes[blockType][turnState][i][j]==1){
	    g.setColor(Color.cyan);
	/*
	 * 为什么加j和i??
	 * 第i行第j个方块(空的也算,只是不画)
	 */
	g.drawRect((Block_x+j)*20, (Block_y+i)*20, 20, 20);
	}			
      }
   }

3.使方块向下移动

Timer timer; 
int delay=300;
TimerListener timerListener=new TimerListener();
public void newGame(){//使用Timer来定时执行
    newBlock();
    timer = new Timer(delay, timerListener);
    timer.start();
}
public class TimerListener implements ActionListener{
	@Override
	public void actionPerformed(ActionEvent e) {
		down();
	}
}
private void down(){
    Block_y ++;//未撞底部墙向下
    repaint();
}

在LaunchFrame()中调用TP.newGame(),即可启动timer,使方块下落

三、判断是否触底

//判断是否撞到底部墙
private int is_crash(int blockType, int turnState, int local_x, int local_y){
    for(int i=0;i<Tetris.shapes[blockType][turnState].length;i++){
        for(int j=0;j<Tetris.shapes[blockType][turnState][i].length;j++){
            //在生成newBlock之前,Block_x,Block_y一直变化
            if((Tetris.shapes[blockType][turnState][i][j] & map[local_y+i][local_x+j])==1){
		return 1;
	    }
        }
    }
    return 0;
}

这里使用数字而不是boolean型来记录,因为有原始墙和新生成的墙两种墙,用数字更易表示

触底后墙即增长

//墙增加
	private void addWall(){
		for(int i=0;i<Tetris.shapes[blockType][turnState].length;i++){
			for(int j=0;j<Tetris.shapes[blockType][turnState][i].length;j++){
				//直接这样会覆盖以前的为1的地方
				//map[i+Block_y][j+Block_x]=Tetris.shapes[blockType][turnState][i][j];
				if(Tetris.shapes[blockType][turnState][i][j]==1){
					map[i+Block_y][j+Block_x]=1;
				}				
			}
		}
	}
改写down()函数,下落时同时判断是否撞墙
private void down(){
	if(is_crash(blockType,turnState,Block_x,Block_y+1)==0){
		Block_y ++;//未撞底部墙向下
	}else{
		//撞底部墙则墙增加,生成新方块
		addWall();
		newBlock();
	}
	repaint();
}

四、键盘控制移动及变形

private class KeyControl extends KeyAdapter{
		@Override
		public void keyPressed(KeyEvent e) {			
			super.keyPressed(e);
			int key = e.getKeyCode();
			switch(key){
			case KeyEvent.VK_DOWN:down();break;
			case KeyEvent.VK_LEFT:left();break;
			case KeyEvent.VK_RIGHT:right();break;
			case KeyEvent.VK_UP:turn();break;
			}
		}
	}
private void left(){
	if(is_crash(blockType,turnState,Block_x-1,Block_y)==0){
	    Block_x--;
	}
	repaint();
}
	
private void right(){
	if(is_crash(blockType,turnState,Block_x+1,Block_y)==0){
	    Block_x++;
	}
	repaint();
}
	
private void turn(){
	turnState=((turnState+1)%Tetris.shapes[blockType].length);
	repaint();
}

实例化键盘控制对象

KeyControl kc = new KeyControl();

在LaunchFrame()中添加addKeyListener(TP.kc);实现键盘控制

五、方块的消除

//消除方块
private void Deline(){
	for(int i=map.length-2;i>0;i--){
		//判断是否满行
		int c=1;
		for(int j=1;j<map[i].length-2;j++){
			c=map[i][j]&c;//只要有一个为0,c就为0
		}
		//消除
		if(c==1){
			for(int k=i;k>0;k--){
				for(int l=1;l<map[i].length-2;l++){
				    map[k][l]=map[k-1][l];//将上一行复制到下一行,最顶上单独处理
				}
			}
			for(int l=1;l<map[i].length-2;l++)
			    map[0][l]=0;//最顶上一行清零
			}
		}
	}

在down()添加Deline(),即可实现消除功能



完整代码如下:

import javax.swing.JFrame;

public class Tetris extends JFrame {
	TetrisPanel TP = new TetrisPanel();
	
	//方块形状定义
		public static int[][][][] shapes=new int[][][][]{  //四维数组,七种形状,每种形状四个方块组成
	    	
	    	//用多维数组表示方块,在为1的地方填色
	            //T  四种形态
	            {{{0,1,0}, {1,1,1}, {0,0,0}},  //第一行,第二行,第三行
	             {{0,0,1}, {0,1,1}, {0,0,1}}, //朝左
	             {{1,1,1}, {0,1,0}, {0,0,0}}, //朝下 
	             {{1,0,0}, {1,1,0}, {1,0,0}}},
	            //这是两种形态,不能通过旋转得到
	            //L  四种形态
	            {{{0,1,0}, {0,1,0}, {0,1,1}},  
	             {{0,0,1}, {1,1,1}, {0,0,0}},  
	             {{1,1,0}, {0,1,0}, {0,1,0}},  
	             {{0,0,0}, {1,1,1}, {1,0,0}}},  
	            //J  四种形态
	            {{{0,1,0}, {0,1,0}, {1,1,0}},  
	             {         {1,1,1}, {0,0,1}},  
	             {{0,1,1}, {0,1,0}, {0,1,0}},  
	             {{1,0,0}, {1,1,1}        }},  
	            //S  两种形态
	            {{{0,1,1}, {1,1,0} ,{0,0,0}},  
	             {{0,1,0}, {0,1,1}, {0,0,1}}},  
	             //Z  两种形态
	            {{{1,1,0}, {0,1,1}, {0,0,0}},  
	             {{0,1,0}, {1,1,0}, {1,0,0}}},  
	             //田  一种形态
	            {{{1,1}, {1,1}}},  
	            //I  两种形态
	            {{{1,1,1,1}		 },  //填0会造成无法靠近边框
	             {{1},{1},{1},{1}}}  
	    };

	public static void main(String[] args) {
		new Tetris().launchFrame();
	}
	
	public void launchFrame(){
	setBounds(1000, 100, 405, 570);  
        setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        setVisible(true);
        setResizable(false);
        
        add(TP);//添加TetrisPanel面板
        addKeyListener(TP.kc);
        TP.newGame();
	}
}
import java.awt.Color;
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.JPanel;
import javax.swing.Timer;

public class TetrisPanel extends JPanel {
	/*
	 * 思想是使用二维数组表示平面,用其中的值标记哪里是墙壁哪里是方块
	 * 
	 */
	private int[][] map = new int[27][20];

	// 新方块的初始位置
	int Block_x;
	int Block_y;

	private int blockType; // 方块类型(第一维数组,共七种)
	private int turnState; // 方块形态(第二维数组,I是两种,L是四种...)

	Timer timer;
	int delay = 300;
	public TimerListener timerListener = new TimerListener();

	KeyControl kc = new KeyControl();

	// 初始化数组,即构造墙壁
	public TetrisPanel() {
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[i].length; j++) {
				if (j == 0 || j == map[i].length - 1 || i == map.length - 1) {
					map[i][j] = 3;
				} else
					map[i][j] = 0;
			}
		}
	}

	// 生成方块
	public void newBlock() {
		// 初始在顶部中间位置
		Block_x = 9;
		Block_y = 0;

		blockType = (new Random()).nextInt(Tetris.shapes.length); // 不大于方块种类的随机数
		turnState = (new Random()).nextInt(Tetris.shapes[blockType].length); // 不大于方块形态的随机数

		repaint();
	}

	public void newGame() {// 使用Timer来定时执行
		newBlock();
		timer = new Timer(delay, timerListener);
		timer.start();
	}

	public class TimerListener implements ActionListener {
		@Override
		public void actionPerformed(ActionEvent e) {
			down();
		}
	}

	private void down() {
		if (is_crash(blockType, turnState, Block_x, Block_y + 1) == 0) {
			Block_y++;// 未撞底部墙向下
		} else {
			// 撞底部墙则墙增加,生成新方块
			addWall();
			newBlock();
		}
		Deline();
		repaint();
	}

	// 判断是否撞到底部墙
	private int is_crash(int blockType, int turnState, int local_x, int local_y) {
		for (int i = 0; i < Tetris.shapes[blockType][turnState].length; i++) {
			for (int j = 0; j < Tetris.shapes[blockType][turnState][i].length; j++) {
				// 在生成newBlock之前,Block_x,Block_y一直变化
				if ((Tetris.shapes[blockType][turnState][i][j] & map[local_y + i][local_x + j]) == 1) {
					return 1;
				}
			}
		}
		return 0;
	}

	// 墙增加,在撞到前生成新墙
	private void addWall() {
		for (int i = 0; i < Tetris.shapes[blockType][turnState].length; i++) {
			for (int j = 0; j < Tetris.shapes[blockType][turnState][i].length; j++) {
				// 直接这样会覆盖以前的为1的地方
				// map[i+Block_y][j+Block_x]=Tetris.shapes[blockType][turnState][i][j];
				if (Tetris.shapes[blockType][turnState][i][j] == 1) {
					map[i + Block_y][j + Block_x] = 1;
				}
			}
		}
	}

	// 消除方块
	private void Deline() {
		for (int i = map.length - 2; i > 0; i--) {
			// 判断是否满行
			int c = 1;
			for (int j = 1; j < map[i].length - 2; j++) {
				c = map[i][j] & c;// 只要有一个为0,c就为0
			}
			// 消除
			if (c == 1) {
				for (int k = i; k > 0; k--) {
					for (int l = 1; l < map[i].length - 2; l++) {
						map[k][l] = map[k - 1][l];// 将上一行复制到下一行,最顶上单独处理
					}
				}
				for (int l = 1; l < map[i].length - 2; l++)
					map[0][l] = 0;// 最顶上一行清零
			}
		}
	}

	@Override
	public void paint(Graphics g) {
		super.paint(g);
		// 画墙壁
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map[i].length; j++) {
				if (map[i][j] == 3) {
					g.setColor(Color.gray);
					g.fillRect(j * 20, i * 20, 20, 20);
				}
				if (map[i][j] == 1) {
					g.setColor(Color.blue);
					g.fillRect(j * 20, i * 20, 20, 20);
				}
			}
		}
		// 画方块
		for (int i = 0; i < Tetris.shapes[blockType][turnState].length; i++) {
			for (int j = 0; j < Tetris.shapes[blockType][turnState][i].length; j++) {
				if (Tetris.shapes[blockType][turnState][i][j] == 1) {
					g.setColor(Color.cyan);
					/*
					 * 为什么加j和i?? 第i行第j个方块(空的也算,只是不画)
					 */
					g.drawRect((Block_x + j) * 20, (Block_y + i) * 20, 20, 20);
				}
			}
		}
	}

	private class KeyControl extends KeyAdapter {
		@Override
		public void keyPressed(KeyEvent e) {
			super.keyPressed(e);
			int key = e.getKeyCode();
			switch (key) {
			case KeyEvent.VK_DOWN:
				down();
				break;
			case KeyEvent.VK_LEFT:
				left();
				break;
			case KeyEvent.VK_RIGHT:
				right();
				break;
			case KeyEvent.VK_UP:
				turn();
				break;
			}
		}
	}

	private void left() {
		if (is_crash(blockType, turnState, Block_x - 1, Block_y) == 0) {
			Block_x--;
		}
		repaint();
	}

	private void right() {
		if (is_crash(blockType, turnState, Block_x + 1, Block_y) == 0) {
			Block_x++;
		}
		repaint();
	}

	private void turn() {
		turnState = ((turnState + 1) % Tetris.shapes[blockType].length);
		repaint();
	}
}
点击下载源码


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值