这是去年写的第一个小项目(虽然感觉称不上是项目),但毕竟是一次完整的编程过程,当作是编程路上的学习经历发一下好了。
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();
}
}