初学者——Java之实现简易俄罗斯方块

这是去年写的第一个小项目(虽然感觉称不上是项目),但毕竟是一次完整的编程过程,当作是编程路上的学习经历发一下好了。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.TextArea;
import java.awt.TextField;
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.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

class Block//方块父类
{
	private int x,y;//方块的坐标;
	protected int type;//方块的形态,横着是0,竖着是1
	protected int[][] bk;//横状方块
	protected int[][] kb;//竖状方块
	
	
	protected Block()//创建坐标,类型
	{
		Random random=new Random();
		x=random.nextInt(7);//随机方块出现的位置
		y=0;
		type=random.nextInt(2);//随机方块类型(横,竖)
	}
	
	
	//获取方块坐标
	public int getX()
	{
		return x;
	}
	
	public int getY()
	{
		return y;
	}

	//获取方块类型
	public int getType()
	{
		return type;
	}
	
	//获取数组宽度和高度
	public int getwidth()
	{
		return getBlock(type)[0].length;
	}
	
	public int getheigth()
	{
		return getBlock(type).length;
	}
	
	//根据类型返回状态方块
	public int[][] getBlock(int type)
	{
		if(type==0)
			return bk;
		else
			return kb;
	}
	
	public void Down()//下降方法
	{
		y++;
	}
	
	public void Left()//左移方法
	{
		x--;
	}
	
	public void Right()//右移方法
	{
		x++;
	}
	
	public void Turn()//旋转方法
	{
		
	}
	

	
}
//长条方块类
class Strip extends Block
{
	private final int w=4,h=1;
	
	Strip()
	{
		super();
		bk=new int[h][w];
		kb=new int[w][h];
		for(int i=0;i<w;i++)
		{
			bk[h-1][i]=1;
			kb[i][h-1]=1;
		}
	}

	public void Turn()//重写父类旋转方法
	{
		if(type==0)
			type=1;
		else
			type=0;
	}

}


//正方形方块类
class Square extends Block
{
	final private int w=2,h=2;
	
	Square()
	{
		super();
		bk=new int[h][w];
		kb=new int[w][h];
		for(int i=0;i<w;i++)
			for(int j=0;j<h;j++)
				{
					bk[i][j]=1;
					kb[j][i]=1;
				}
	}

}
//Z字方块1类
class Z1 extends Block
{
	final private int w=3,h=2;
	
	Z1()
	{
		super();
		bk=new int[h][w];
		kb=new int[w][h];
		bk[0][0]=bk[0][1]=bk[1][1]=bk[1][2]=1;
		kb[2][0]=kb[1][0]=kb[1][1]=kb[0][1]=1;
	}

	public void Turn()
	{
		if(type==0)
			type=1;
		else
			type=0;
	}
	
}

//Z字方块2类
class Z2 extends Block
{
	final private int w=3,h=2;
	
	Z2()
	{
		super();
		bk=new int[h][w];
		kb=new int[w][h];
		bk[0][2]=bk[0][1]=bk[1][1]=bk[1][0]=1;
		kb[0][0]=kb[1][0]=kb[1][1]=kb[2][1]=1;
	}

	public void Turn()
	{
		if(type==0)
			type=1;
		else
			type=0;
	}
	
}


//三角方块类
class triangle extends Block
{
	final private int w=3,h=2;
	
	triangle()
	{
		super();
		bk=new int[h][w];
		kb=new int[w][h];
		triangle(type);
	}
	
	//随机创建四种三角形状的一种
	private void triangle(int type) 
	{
		Random r=new Random();
		if(type==0)
		{
			if(r.nextInt(2)==0)
				bk[0][1]=bk[1][0]=bk[1][1]=bk[1][2]=1;
			else
				bk[1][1]=bk[0][0]=bk[0][1]=bk[0][2]=1;
		}
		else
		{
			if(r.nextInt(2)==0)
				kb[1][0]=kb[0][1]=kb[1][1]=kb[2][1]=1;
			else
				kb[1][1]=kb[0][0]=kb[1][0]=kb[2][0]=1;
		}
		
	}

	//旋转方法利用数组的特性赋值
	public void Turn()
	{
		if(type==0)
		{
			for(int i=0;i<h;i++)
				for(int j=0;j<w;j++)
					kb[j][h-i-1]=bk[i][j];
			type=1;
		}
		else
		{
			for(int i=0;i<w;i++)
				for(int j=0;j<h;j++)
					bk[j][w-i-1]=kb[i][j];
			type=0;
		}
	}
	
}

//不规则方块类1
class irregular1 extends Block
{
	final private int w=3,h=2;
	
	irregular1()
	{
		super();
		bk=new int[h][w];
		kb=new int[w][h];
		irregular1(type);
	}
	
	//随机创建四种状的一种
	private void irregular1(int type) 
	{
		Random r=new Random();
		if(type==0)
		{
			if(r.nextInt(2)==0)
				bk[0][0]=bk[1][0]=bk[1][1]=bk[1][2]=1;
			else
				bk[1][2]=bk[0][0]=bk[0][1]=bk[0][2]=1;
		}
		else
		{
			if(r.nextInt(2)==0)
				kb[2][0]=kb[0][1]=kb[1][1]=kb[2][1]=1;
			else
				kb[0][1]=kb[0][0]=kb[1][0]=kb[2][0]=1;
		}
		
	}

	//旋转方法利用数组的特性赋值
	public void Turn()
	{
		if(type==0)
		{
			for(int i=0;i<h;i++)
				for(int j=0;j<w;j++)
					kb[j][h-i-1]=bk[i][j];
			type=1;
		}
		else
		{
			for(int i=0;i<w;i++)
				for(int j=0;j<h;j++)
					bk[j][w-i-1]=kb[i][j];
			type=0;
		}
	}
	
}

//不规则方块类2
class irregular2 extends Block
{
	final private int w=3,h=2;
	
	irregular2()
	{
		super();
		bk=new int[h][w];
		kb=new int[w][h];
		irregular2(type);
	}
	
	//随机创建四种状的一种
	private void irregular2(int type) 
	{
		Random r=new Random();
		if(type==0)
		{
			if(r.nextInt(2)==0)
				bk[0][2]=bk[1][0]=bk[1][1]=bk[1][2]=1;
			else
				bk[1][0]=bk[0][0]=bk[0][1]=bk[0][2]=1;
		}
		else
		{
			if(r.nextInt(2)==0)
				kb[0][0]=kb[0][1]=kb[1][1]=kb[2][1]=1;
			else
				kb[2][1]=kb[0][0]=kb[1][0]=kb[2][0]=1;
		}
		
	}

	//旋转方法利用数组的特性赋值
	public void Turn()
	{
		if(type==0)
		{
			for(int i=0;i<h;i++)
				for(int j=0;j<w;j++)
					kb[j][h-i-1]=bk[i][j];
			type=1;
		}
		else
		{
			for(int i=0;i<w;i++)
				for(int j=0;j<h;j++)
					bk[j][w-i-1]=kb[i][j];
			type=0;
		}
	}
	
}

//游戏主体类
class theGame extends JPanel implements Runnable
{
	private int score;//游戏得分
	private int speed;//方块下落速度
	private int MAX_blockheight;//方块堆积的最大高度
	private final int widht=10,height=20,size=30;//面板宽度,高度和大小
	private final int[][] board;//游戏面板
	private Block[] block;//游戏运行时的方块
	private boolean isgameover,iscontinue;//游戏是否结束,游戏是否继续
	
	theGame()
	{
		board=new int[height][widht];
		block=new Block[2];//定义两个方块,一个运行,另一个预览
		buildblock();//初始化预览个方块
		MAX_blockheight=height-1;//初始化方块堆积最大高度
		score=0;
		speed=500;
		isgameover=false;
		iscontinue=true;
		this.addKeyListener(new Move());//对面板键盘监听
		
	}
	
	public void Start()//开始方法,由按钮控制
	{
		Thread run=new Thread(this);
		run.start();//创建线程1,游戏开始
	}

	public void setcontinue(boolean b) //设置是否继续游戏
	{
			iscontinue=b;
	}
	
	//游戏运行线程
	public void run() 
	{
		do
		{
			passblock();//将预览方块传递给运行方块
			buildblock();//新建预览方块
			PaintNext();//显示预览方块
			createblock();//在面板产生方块
			while(!collideD())//碰撞检测
			{
				makeDown();	//方块下落方法
				
				try {
					Thread.sleep(speed);//挂起线程,控制方块速度
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				if(!iscontinue)//若不继续,挂起该线程直到点击继续
				{
				
					Threadt t=new Threadt();
					synchronized(t) 
					{
								try 
								{
									t.start();
									t.wait();
								}catch(InterruptedException e) {}
					}
				}
			}
			create_stable_block();//方块无法下落,固定方块
			setMax_ofblockheight();//记录方块堆积的最高高度
			score();//计分方法
			destoryblock();//销毁方块
			
		}while(!gameover());//检测游戏是否结束
		
		repaint();
	}


	private void PaintNext() //显示预览方块方法
	{
		new Nextb(block[1].getBlock(block[1].getType()));//将预览方块数组传递给预览面板类构造对象
		newtetris.menu.repaint();//刷新菜单面板
	}

	private void create_stable_block() //固定方块方法
	{
		for(int bi=block[0].getY();bi<block[0].getY()+block[0].getheigth();bi++)
			for(int bj=block[0].getX();bj<block[0].getX()+block[0].getwidth();bj++)
				if(board[bi][bj]==1)
					board[bi][bj]=2;
	}

	private void destoryblock() //销毁方块方法
	{
		block[0]=null;
		System.gc();
	}

	private void setMax_ofblockheight() //设置方块堆积的最高点
	{
		if(block[0].getY()<MAX_blockheight)
			MAX_blockheight=block[0].getY();
	}

	private void score() //计分方法
	{
		int n;
		for(int i=height-1;i>=MAX_blockheight;i--)
		{
			n=0;//计算这行方块数
			
			for(int j=0;j<widht;j++)
			{
				if(board[i][j]==0)
					break;
				else
					n++;
			}
			
			if(n==widht)//判断这行是否布满方块
			{
				enLine(i);//消去这行
				score++;
				newtetris.score.setText(""+score);
				i+=1;
			}
		}
	}

	//消行方法
	private void enLine(int x) 
	{
		for(int i=x;i>=MAX_blockheight;i--)
			for(int j=0;j<widht;j++)
				board[i][j]=board[i-1][j];
		
		MAX_blockheight+=1;
	}

	private boolean gameover() //判断游戏是否结束方法
	{
		if(MAX_blockheight<=3)
		{
			isgameover=true;
			return true;
		}
		return false;
	}

	private boolean collideD() //下落碰撞检测
	{
		if(block[0].getY()+block[0].getheigth()>=height)//检测是否最低点
				return true;
		
		//检测下方是否有方块
		for(int i=block[0].getY()+block[0].getheigth()-1;i>=0;i--)
			for(int j=block[0].getX()+block[0].getwidth()-1;j>=0;j--)
				if(board[i][j]==1&&board[i+1][j]==2)
					return true;
		return false;
	}

	private void makeDown() //下降方法
	{
		
		erasureblock();//擦除原方块
		block[0].Down();//改变y值使下降
		createblock();//产生新方块
		repaint();
	}

	//在新坐标上产生一个方块
	private void createblock() 
	{
		for(int bi=block[0].getY(),i=0;i<block[0].getheigth();i++,bi++)
			for(int bj=block[0].getX(),j=0;j<block[0].getwidth();j++,bj++)
				if(board[bi][bj]==0&&block[0].getBlock(block[0].getType())[i][j]==1)
					board[bi][bj]=block[0].getBlock(block[0].getType())[i][j];
	}

	//擦除原来坐标上的方块
	private void erasureblock() 
	{
		for(int bi=block[0].getY();bi<block[0].getY()+block[0].getheigth();bi++)
			for(int bj=block[0].getX();bj<block[0].getX()+block[0].getwidth();bj++)
				if(board[bi][bj]==1)
					board[bi][bj]=0;
				
		
	}

	private void passblock() //将预览方块传给运行方块方法
	{
		block[0]=block[1];
		
	}

	private void buildblock() //创建预览方块方法
	{
		Random r=new Random();
		switch(r.nextInt(7))//随机创建七种方块
		{
		case 0:block[1]=new Strip();break;
		case 1:block[1]=new Square();break;
		case 2:block[1]=new Z1();break;
		case 3:block[1]=new Z2();break;
		case 4:block[1]=new triangle();break;
		case 5:block[1]=new irregular1();break;
		case 6:block[1]=new irregular2();break;
		
		}

		
	}


	public void makeTurn() //旋转方法
	{
		erasureblock();//擦除原方块
		block[0].Turn();//调用方块的旋转方法
		createblock();//产生新方块
		repaint();
	}

	public boolean collideT() //旋转碰撞检测
	{

			for(int bi=block[0].getY()+block[0].getwidth()-1;bi>=block[0].getY();bi--)	
				for(int bj=block[0].getX()+block[0].getheigth()-1;bj>=block[0].getX();bj--)
					if(board[bi][bj]==2)
						return true;

		return false;
	}

	public void makeRight() //右移方法
	{
		erasureblock();//擦除原方块
		block[0].Right();//调用方块的右移方法
		createblock();//产生新方块
		repaint();
	}

	public boolean collideR() //右移碰撞检测
	{
		if(block[0].getX()+block[0].getwidth()>=widht)
			return true;

		for(int bj=block[0].getX()+block[0].getwidth()-1;bj>=block[0].getX();bj--)
			for(int bi=block[0].getY();bi<block[0].getY()+block[0].getheigth();bi++)	
				if(board[bi][bj]==1&&board[bi][bj+1]==2)
					return true;
		
		return false;
	}

	public void makeLeft() //左移方法
	{
		//和前面一样,不写了
		erasureblock();
		block[0].Left();
		createblock();
		repaint();
	}
	
	public boolean collideL() //左移碰撞检测
	{
		if(block[0].getX()<=0)//是否在最左端
			return true;

		//左边是否有方块
		for(int bj=block[0].getX();bj<block[0].getX()+block[0].getwidth();bj++)
			for(int bi=block[0].getY();bi<block[0].getY()+block[0].getheigth();bi++)	
				if(board[bi][bj]==1&&board[bi][bj-1]==2)
					return true;
		
		return false;
	}
	
	class Threadt extends Thread
	{
		public void run()//线程2,用来启动线程1
		{
			synchronized(this) 
			{
				while(true)
				{
					try 
					{                         
		                Thread.sleep(1000); 
		            } catch (Exception e) {}  
					
			           if(iscontinue)//游戏是否继续
			           {
			            this.notify();
			            break;
			           }
				}
			}
		}
	}
	
	
	class Move extends KeyAdapter//键盘适配器
	{
		
		public void keyReleased(KeyEvent e) 
		{
			
			if(e.getKeyCode()==KeyEvent.VK_DOWN)//释放下键,速度变慢
			{
				if(speed==50)
					speed=500;
			}
		}
		
		public void keyPressed(KeyEvent e)
		{
			if(e.getKeyCode()==KeyEvent.VK_LEFT)//按下左键触发事件
			{
				if(!collideL())//是否可以左移
					makeLeft();//左移方法
			}
			//以下同上
			else if (e.getKeyCode() == KeyEvent.VK_RIGHT)
			{
				if(!collideR())
					makeRight();
			}
			else if (e.getKeyCode() == KeyEvent.VK_UP)
			{
				if(!collideT())
					makeTurn();
			}
			else if(e.getKeyCode()==KeyEvent.VK_DOWN)
			{
				speed=50;
			}
		}
	}

	public void paintComponent(Graphics g)//绘制面板
	{
		super.paintComponent(g);
		
			for(int i=0;i<height;i++)
			{
				for(int j=0;j<widht;j++)
				{
					switch(board[i][j])//三种型号对应三种颜色
					{
					case 0:g.setColor(Color.BLACK);break;//没有方块
					case 1:g.setColor(Color.WHITE);break;//移动中的方块
					case 2:g.setColor(Color.GRAY);break;//已固定的方块
					}
					g.fillRect((size+1)*j+15, (size+1)*i+25, size, size);//画方块
				}
				if(i==4)//方块堆积界限
				{
					g.setColor(Color.RED);
					g.drawLine(15, (size+1)*i+25, (size+1)*10+15, (size+1)*i+25);
				}
		}
			
			if(isgameover)//游戏结束则打印“Game Over”
			{
				Font lose=new Font("黑体",Font.BOLD,50);
				g.setFont(lose);
				g.setColor(Color.RED);
				g.drawString("Game Over", 50, 250);
			}
	}

	
}

class Nextb extends JPanel//预览面板类
{
	 int Size;
	 private static int[][] paint;//预览方块
	 Nextb()
	 {
		 Size=40;
		 paint=null;
	 }
	 Nextb(int[][] p)//构造预览方块
	 {
		 Size=40;
		 paint=new int[p.length][p[0].length];
		 
		for(int i=0;i<p.length;i++)
			for(int j=0;j<p[0].length;j++)
					paint[i][j]=p[i][j];
		
		repaint();
		
	 }
	public void paintComponent(Graphics gg)//绘制面板
	 {
		 super.paintComponent(gg);//刷新面板,以免重叠
		 
		 if(paint!=null)
		 {
			for(int i=0;i<paint.length;i++)
				for(int j=0;j<paint[0].length;j++)
					{
						gg.setColor(Color.GREEN);
						if(paint[i][j]==1)
							gg.fillRect((Size+1)*j+15, (Size+1)*i+25, Size, Size);
						
					}
		 }
	 }
}

public class newtetris extends JFrame implements ActionListener//游戏界面类
{
	theGame game;//定义一个游戏对象
	public static JPanel menu;//定义静态菜单面板
	Label prompt1,prompt2,prompt3;
	public static TextField score;//计分文本框
	TextArea methon;//玩法介绍文本区
	JButton start,replay;//开始,暂停按钮
	
	
	newtetris()
	{
		game=new theGame();
		menu=new JPanel();
		
		Font se=new Font("宋体",Font.BOLD,25);
		prompt1=new Label("             下一个:");
		prompt2=new Label("               得分:");
		prompt3=new Label("               玩法:");
		prompt1.setFont(se);
		prompt2.setFont(se);
		prompt3.setFont(se);
		
		score=new TextField(3);
		methon=new TextArea(""+10,8,TextArea.SCROLLBARS_NONE);
		start=new JButton("开始");
		replay=new JButton("暂停");
		
		menu.setLayout(new GridLayout(0,2,10,30));//菜单面板使用网格布局
		
		Font sc=new Font("宋体",Font.BOLD,15);
		Font sp=new Font("宋体",Font.BOLD,100);
		methon.setFont(sc);
		methon.setText("↑:顺时针旋转90度\n↓:快速下移\n←:向左移动\n→:向右移动");
		methon.setEditable(false);
		methon.setFocusable(false);
		score.setFont(sp);
		score.setText("0");
		score.setEditable(false);
		score.setFocusable(false);
		
		menu.setPreferredSize(new Dimension(400,600));
		menu.add(prompt1);
		menu.add(new Nextb());
		menu.add(prompt2);
		menu.add(score);
		menu.add(prompt3);
		menu.add(methon);
		menu.add(start);
		menu.add(replay);
		
		this.add(menu,BorderLayout.EAST);
		this.add(game,BorderLayout.CENTER);
		
		start.addActionListener(this);
		replay.addActionListener(this);
		
		this.setVisible(true);
		this.setSize(750,700);
		this.setResizable(false);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setTitle("俄罗斯方块");
	}
	
	public void actionPerformed(ActionEvent e)
	{
		if(e.getSource()==start)
		{			
			game.Start();//开始游戏
			game.requestFocusInWindow();//聚焦到游戏面板
		}
		
		else if(e.getSource()==replay)
		{
			if(e.getActionCommand().equals("暂停"))
			{
				game.setcontinue(false);//设置游戏暂停
				replay.setText("继续");//按钮变成继续
				game.requestFocusInWindow();//聚焦到面板
			}
			else if(e.getActionCommand().equals("继续"))
			{
				game.setcontinue(true);//设置游戏继续
				replay.setText("暂停");//按钮变成暂停
				game.requestFocusInWindow();//聚焦到面板
			}
		}
		
	}
		
	public static void main(String[] args)
	{
		new newtetris();
	}

}
  • 12
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值