先看看成品的效果
以下是完整代码
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Random;
import java.util.ArrayList;
import java.util.Collections;
public class Tetris
{
//主窗口
private JFrame mainWin = new JFrame("俄罗斯方块");
//菜单
private JMenuBar menubar = new JMenuBar();
//1
private JMenu control = new JMenu("控制");
private JMenuItem start = new JMenuItem("开始游戏");
private JMenuItem parse = new JMenuItem("暂停");
private JMenuItem end = new JMenuItem("结束游戏");
//2
private JMenu help = new JMenu("帮助");
private JMenuItem helpshow = new JMenuItem("帮助说明");
//菜单事件监听器
private MenuActionListener menulistener = new MenuActionListener();
//设置一个数组用来存储是否已经被填充了。
private int[][] store = new int[27][20];
/*
10和20根据窗体大小调整
根据实际情况,宽是400,高是600,每个方块边长20
所以横向可以放20个,纵向可以放30个
*/
//左边的游戏界面
private GamePanel gamePanel =new GamePanel();
//现在正在掉落的方块
AllShapes falling = new AllShapes();
//键盘事件
MyKeyListener myKeyListener = new MyKeyListener();
//定时器
private Timer timer;
private TimerTask task;
//随机位置
Random rand = new Random();
int nextshape = 0;
int nowshape = 0;
//记录得分
int score = 0;
//显示得分和下一个图形的JPanel
ShowNextPanel showNextPanel = new ShowNextPanel();
//防止一开始有一个小方块
boolean newgame = false;
public Tetris()
{
//初始化一下现在的和下一个形状
nowshape = rand.nextInt(7);
nextshape = rand.nextInt(7);
}
public void init()
{
JSplitPane splitPane = new JSplitPane();
splitPane.setDividerLocation(405);
splitPane.disable();
mainWin.add(splitPane);
splitPane.setLeftComponent(gamePanel);
JSplitPane leftsplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
leftsplitPane.setTopComponent(showNextPanel);
RightLowPanel rightlowpane = new RightLowPanel();
Button startBn = new Button("开始");
startBn.addActionListener(evt -> {
if( !newgame)
{
TimerModeInit();
newgame = true;
}
});
rightlowpane.add(startBn);
leftsplitPane.setBottomComponent(rightlowpane);
leftsplitPane.setDividerLocation(200);
leftsplitPane.disable();
splitPane.setRightComponent(leftsplitPane);
//设置菜单按钮
mainWin.setJMenuBar(menubar);
//1
menubar.add(control);
control.add(start);
control.add(parse);
control.add(end);
//2
menubar.add(help);
help.add(helpshow);
//设置菜单的监听事件
start.addActionListener(menulistener);
parse.addActionListener(menulistener);
end.addActionListener(menulistener);
//System.out.println("数组内的默认值"+store[0][0]);
mainWin.addKeyListener(myKeyListener);
//设置主界面
mainWin.setSize(600,603);
mainWin.setLocationRelativeTo(null);//居中
//mainWin.pack();
mainWin.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWin.setVisible(true);
mainWin.setResizable(false);//设置不准改变窗体大小
}
public void TimerModeInit()
{
timer = new Timer();
task = new TimerTask()
{
@Override
public void run()
{
//现在的图形
int[][] data = falling.getdata(nowshape);
boolean yes = falling.checkyes(data);//如果没有一个的底下为1的话就可以加1,
if((falling.y < 25) && yes)
{
falling.y += 1;
gamePanel.repaint();
showNextPanel.repaint();
}
else
{
falling.storeshape(data);
falling.resetxy();
nowshape = nextshape;
nextshape = rand.nextInt(7);
showNextPanel.repaint();
falling.resetrotate();
}
//每次循环检查
int count = 0;
for( int i = store.length-1; i>=0;i--)
{
boolean clean = true;
for( int j = 0 ; j<store[i].length; j++)
{
if( store[i][j]== 0)
{
clean = false;
}
}
if( clean)
{
for( int p = i; p>0; p--)
{
store[p] = store[p-1];
}
store[0] = new int[20];
score += 20;
}
//经过前面的清理之后,如果还是有20个的行有黑格子的话,就结束游戏
int hangcount = 0;
for( int j= 0 ;j< store[i].length; j++)
if( store[i][j] == 1)
hangcount ++;
if( hangcount > 0)
count++;
}
if(count >= 27)
{
System.out.println("游戏结束");
cancel();
}
}
};
timer.schedule(task,0,1000);
}
public static void main(String[] args)
{
new Tetris().init();
}
class GamePanel extends JPanel
{
@Override
public void paint(Graphics g)
{
/*
//模拟数据
store[0][18] = 2;
store[1][18] = 1;
store[1][19] = 2;
store[1][17] = 2;
*/
//白色背景
g.setColor(new Color(255,255,255));
g.fillRect(0,0,400,600);
//根据数组内容绘制
for(int i = 0 ; i < store[0].length; i++)
{
for( int j = 0 ; j< 27; j++)
{
//遍历数组,只要不为0,就绘制出来
if( store[j][i] != 0)
{
g.setColor(new Color(150,150,150));
g.fillRect(i*20,j*20,18,18);
}
else//不然的话,就绘制背景网格
{
int colorparam = 240;
g.setColor(new Color(colorparam,colorparam,colorparam));
g.fillRect(i*20, j*20, 18,18);
}
}
}
//画一个方块看看
//g.setColor(new Color(150,150,150));
//g.fillRect(100,100,20,20);
if(newgame == true)
{
g.setColor(new Color(150,150,150));
int[][] data = falling.getdata(nowshape);
for( int i = 0; i < data.length ; i++)
{
g.fillRect((data[i][0]+falling.x)*20,(data[i][1]+falling.y)*20,18,18);
}
}
}
}
class ShowNextPanel extends JPanel
{
@Override
public void paint(Graphics g)
{
//白色背景
g.setColor(new Color(255,255,255));
g.fillRect(0,0,200,200);
/*
//网格背景
g.setColor(new Color(240,240,240));
for(int i = 0;i< 10;i++)
{
for( int j = 2; j< 10;j ++)
{
g.fillRect(i*20,j*20,18,18);
}
}
*/
int[][] data = falling.getdata(nextshape);
g.setColor(new Color(150,150,150));
for( int i = 0 ; i < data.length; i++)
{
g.fillRect((data[i][0]+3)*20-5,(data[i][1]+4)*20+20,18,18);
}
//文字放最上面以防被覆盖
g.setColor(new Color(0,0,0));
g.drawString("得分:"+score,10,30);
g.drawString("下一个图形:", 10,50);
}
}
class RightLowPanel extends JPanel
{
@Override
public void paint(Graphics g)
{
g.setColor(new Color(255,255,255));
g.fillRect(0,0,200,400);
}
}
class MyKeyListener implements KeyListener
{
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
int[][] data = falling.getdata(nowshape);
switch(key)
{
case KeyEvent.VK_UP:
if(falling.canrotate(data) )//如果可以翻转的话
falling.rotate(nowshape);
break;
case KeyEvent.VK_DOWN:
if( falling.checkfall(data))
falling.y += 1;
break;
case KeyEvent.VK_LEFT:
if( falling.checksubsideyes(data))
{
falling.x -=1;
}
break;
case KeyEvent.VK_RIGHT:
if( falling.checkaddsideyes(data))
{
falling.x +=1;
}
break;
}
gamePanel.repaint();
}
public void keyReleased(KeyEvent e){}
public void keyTyped(KeyEvent e){}
}
class MenuActionListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
switch(e.getActionCommand())
{
case "开始游戏":
System.out.println("开始游戏");
nextshape = rand.nextInt(7);
if( !newgame )
{
newgame = true;
gamePanel.repaint();
//定时线程
//定时任务初始化
TimerModeInit();
}
break;
case "暂停":
if( newgame)
{
System.out.println("暂停");
timer.cancel();
timer.purge();
timer = null;
newgame = false;
}
break;
case "结束游戏":
System.out.println("结束游戏");
break;
}
}
}
class AllShapes
{
Random rand = new Random();
public int x = rand.nextInt(17)+1;
public int y =0;
private int[][] data1 = {{-1,0},{0,0},{1,0},{2,0}};// —
private int[][] data2 = {{-1,0},{0,0},{1,0},{-1,1}}; // L 左边突出
private int[][] data3 = {{-1,0},{0,0},{1,0},{1,1}}; // L 右边突出
private int[][] data4 = {{0,0},{1,0},{0,1},{1,1}}; //田
private int[][] data5 = {{-1,0},{0,0},{1,0},{0,1}}; // T
private int[][] data6 = {{-1,0},{0,0},{0,1},{1,1}}; //Z
private int[][] data7 = {{0,0},{1,0},{-1,1},{0,1}}; //反Z
private ArrayList<int[][]> list = new ArrayList<>();
public AllShapes(){
Collections.addAll(list,data1,data2,data3,data4,data5,data6,data7);
}
public void resetxy()
{
x = rand.nextInt(17)+1;
y = 0;
}
public void rotate(int nowshape)
{
for( int i = 0; i < list.get(nowshape).length; i ++)
{
int x = list.get(nowshape)[i][0];
list.get(nowshape)[i][0] = -list.get(nowshape)[i][1];
list.get(nowshape)[i][1] = x;
}
}
public void resetrotate()
{
int[][] data1 = {{-1,0},{0,0},{1,0},{2,0}};// —
int[][] data2 = {{-1,0},{0,0},{1,0},{-1,1}}; // L 左边突出
int[][] data3 = {{-1,0},{0,0},{1,0},{1,1}}; // L 右边突出
int[][] data4 = {{0,0},{1,0},{0,1},{1,1}}; //田
int[][] data5 = {{-1,0},{0,0},{1,0},{0,1}}; // T
int[][] data6 = {{-1,0},{0,0},{0,1},{1,1}}; //Z
int[][] data7 = {{0,0},{1,0},{-1,1},{0,1}}; //反Z
list.clear();
Collections.addAll(list,data1,data2,data3,data4,data5,data6,data7);
}
public boolean canrotate(int[][] data)
{
for( int i = 0; i < data.length; i++)
{
int temy = data[i][0];
int temx = -data[i][1];
if( temx+x > 19 || temx+x < 0 )
return false;
if( temy+y > 26 || temy+y < 0)
return false;
if( store[temy+y][temx+x] == 1 )
return false;
}
return true;
}
public int[][] getdata(int i)
{
return list.get(i);
}
public boolean checkyes(int[][] data)
{
boolean yes = true;
for(int i = 0; i < data.length; i++)
{
if( data[i][1] + y+1 >26 || store[data[i][1]+y+1][data[i][0]+x] == 1)
{
yes = false;
}
}
return yes;
}
public boolean checkfall(int[][] data)
{
for( int i = 0; i < data.length; i++)
{
if( data[i][1]+y+1 >= 27 || store[data[i][1]+y+1][data[i][0]+x] ==1)
return false;
}
return true;
}
public boolean checkaddsideyes( int[][] data)
{
for( int i=0; i< data.length; i++)
{
if( data[i][0]+x+1 > 19 || store[data[i][1]+y][data[i][0]+x+1]==1)
return false;
}
return true;
}
public boolean checksubsideyes(int[][] data)
{
for( int i = 0 ; i < data.length; i ++)
{
if( data[i][0] + x -1 < 0 || store[data[i][1]+y][data[i][0]+x-1] ==1)
return false;
}
return true;
}
public void storeshape(int[][] data)
{
for( int i = 0; i < data.length; i++)
{
store[data[i][1]+y][data[i][0]+x] = 1;
}
}
}
}