package MyGame;
/**
* Created by zu on 2015/3/30.
*/
/*
整个游戏界面分为两部分,左边显示信息,右边是游戏区,是两个JPanel,它们的父窗口是MainWindowFrame。
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class MainWindowFrame extends JFrame
{
public MainWindowFrame()
{
setSize(DEFAULT_WIDTH,DEFAULT_HEIGHT);
setResizable(false);//不可设置大小
infoPanel=new InfoPanel();
gamePanel=new GamePanel();
timer=new Timer(500,new timeActionListener());//新建一个定时器对象,每0.5s触发一次
Container contentPane=getContentPane();
contentPane.add(infoPanel,BorderLayout.WEST);
contentPane.add(gamePanel,BorderLayout.CENTER);
//全局键盘监控事件
Toolkit toolkit = Toolkit.getDefaultToolkit();
toolkit.addAWTEventListener(new ImplAWTEventListener(), AWTEvent.KEY_EVENT_MASK);
}
public static void startTimer()
{
timer.start();
}
public static void stopTimer()
{
timer.stop();
}
private static Timer timer;
//每触发一次,方块便向下移动一格
private class timeActionListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
gamePanel.move(DIRECTION_NONE);
infoPanel.setScore(gamePanel.checkLine());
infoPanel.repaint();
}
}
//全局事件,用来监控键盘输入
class ImplAWTEventListener implements AWTEventListener
{
@Override
public void eventDispatched(AWTEvent event) {
if (event.getClass() == KeyEvent.class) {
// 被处理的事件是键盘事件.
KeyEvent keyEvent = (KeyEvent) event;
if (keyEvent.getID() == KeyEvent.KEY_PRESSED) {
//按下时你要做的事情
keyPressed(keyEvent);
} else if (keyEvent.getID() == KeyEvent.KEY_RELEASED) {
//放开时你要做的事情
keyReleased(keyEvent);
}
}
}
private void keyPressed(KeyEvent e)
{
int keyCode=e.getKeyCode();
if(keyCode==KeyEvent.VK_LEFT)
{
gamePanel.move(DIRECTION_LEFT);
infoPanel.setScore(gamePanel.checkLine());
}
else if(keyCode==KeyEvent.VK_RIGHT)
{
gamePanel.move(DIRECTION_RIGHT);
infoPanel.setScore(gamePanel.checkLine());
}
else if(keyCode==KeyEvent.VK_UP)
{
gamePanel.changePosition();
infoPanel.setScore(gamePanel.checkLine());
}
else if(keyCode==KeyEvent.VK_DOWN)
{
gamePanel.moveToBottom();
infoPanel.setScore(gamePanel.checkLine());
}
}
private void keyReleased(KeyEvent event) {}
}
InfoPanel infoPanel;
GamePanel gamePanel;
private final int DEFAULT_WIDTH=550;
private final int DEFAULT_HEIGHT=633;
private int DIRECTION_LEFT=-1;
private int DIRECTION_RIGHT=1;
private int DIRECTION_NONE=0;
}
package MyGame;
/**
* Created by zu on 2015/3/30.
*/
/*
存储各种block的类,每个类都有一个getPosition方法,这个方法接受一个参考点的坐标,然后返回其他各点坐标
*/
public class Blocks
{
public int[][] getLocation(int x,int y)
{
return new int[4][2];
}
public void changePosition()
{
currentMethod++;
if(currentMethod>3)
currentMethod=0;
}
protected int currentMethod=0;
}
class OneBlock extends Blocks//立形
{
public int[][] getLocation(int x,int y)
{
int[][] points=new int[4][2];
points[0]=new int[]{x,y};
if(currentMethod==0)
{
points[1]=new int[]{x-1,y};
points[2]=new int[]{x+1,y};
points[3]=new int[]{x,y-1};
}
else if(currentMethod==1)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x,y-2};
points[3]=new int[]{x-1,y-1};
}
else if(currentMethod==2)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x-1,y-1};
points[3]=new int[]{x+1,y-1};
}
else if(currentMethod==3)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x,y-2};
points[3]=new int[]{x+1,y-1};
}
return points;
}
}
class LeftTwoBlock extends Blocks
{
public int[][] getLocation(int x,int y)
{
int[][] points=new int[4][2];
points[0]=new int[]{x,y};
if(currentMethod==0)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x,y-2};
points[3]=new int[]{x-1,y-2};
}
else if(currentMethod==1)
{
points[1]=new int[]{x-1,y};
points[2]=new int[]{x+1,y};
points[3]=new int[]{x+1,y-1};
}
else if(currentMethod==2)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x,y-2};
points[3]=new int[]{x+1,y};
}
else if(currentMethod==3)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x+1,y-1};
points[3]=new int[]{x+2,y-1};
}
return points;
}
}
class RightTwoBlock extends Blocks
{
public int[][] getLocation(int x,int y)
{
int[][] points=new int[4][2];
points[0]=new int[]{x,y};
if(currentMethod==0)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x,y-2};
points[3]=new int[]{x+1,y-2};
}
else if(currentMethod==1)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x-1,y-1};
points[3]=new int[]{x-2,y-1};
}
else if(currentMethod==2)
{
points[1]=new int[]{x-1,y};
points[2]=new int[]{x,y-1};
points[3]=new int[]{x,y-2};
}
else if(currentMethod==3)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x+1,y};
points[3]=new int[]{x+2,y};
}
return points;
}
}
class LeftThreeBlock extends Blocks
{
public int[][] getLocation(int x,int y)
{
int[][] points=new int[4][2];
points[0]=new int[]{x,y};
if(currentMethod==0||currentMethod==2)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x-1,y-1};
points[3]=new int[]{x-1,y-2};
}
else if(currentMethod==1||currentMethod==3)
{
points[1]=new int[]{x-1,y};
points[2]=new int[]{x,y-1};
points[3]=new int[]{x+1,y-1};
}
return points;
}
}
class RightThreeBlock extends Blocks
{
public int[][] getLocation(int x,int y)
{
int[][] points=new int[4][2];
points[0]=new int[]{x,y};
if(currentMethod==0||currentMethod==2)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x+1,y-1};
points[3]=new int[]{x+1,y-2};
}
else if(currentMethod==1||currentMethod==3)
{
points[1]=new int[]{x+1,y};
points[2]=new int[]{x,y-1};
points[3]=new int[]{x-1,y-1};
}
return points;
}
}
class FourBlock extends Blocks
{
public int[][] getLocation(int x,int y)
{
int[][] points=new int[4][2];
points[0]=new int[]{x,y};
points[1]=new int[]{x+1,y};
points[2]=new int[]{x,y-1};
points[3]=new int[]{x+1,y-1};
return points;
}
}
class FiveBlock extends Blocks
{
public int[][] getLocation(int x,int y)
{
int[][] points=new int[4][2];
points[0]=new int[]{x,y};
if(currentMethod==0||currentMethod==2)
{
points[1]=new int[]{x,y-1};
points[2]=new int[]{x,y-2};
points[3]=new int[]{x,y-3};
}
else if(currentMethod==1||currentMethod==3)
{
points[1]=new int[]{x+1,y};
points[2]=new int[]{x+2,y};
points[3]=new int[]{x-1,y};
}
return points;
}
}
package MyGame;
/**
* Created by zu on 2015/3/30.
*/
/*
用来显示游戏信息的,还包含一个next显示面板
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.geom.*;
public class InfoPanel extends JPanel
{
public InfoPanel()
{
setBounds(POSITION_X,POSITION_Y,WIDTH,HEIGHT);
setLayout(new GridLayout(6,1));
JLabel nextLabel=new JLabel("Next");
nextLabel.setFont(new Font("Serif",Font.BOLD,30));
JLabel scoreLabel=new JLabel("Score");
scoreLabel.setFont(new Font("Serif",Font.BOLD,30));
//显示分数的面板
displayScoreLabel.setFont(new Font("Serif",Font.BOLD,30));
//开始按钮
JButton startButton=new JButton("Start");
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
MainWindowFrame.startTimer();
}
});
//暂停按钮
JButton pauseButton=new JButton("Pause");
pauseButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
MainWindowFrame.stopTimer();
}
});
//重新开始按钮
JButton restartButton=new JButton("Restart");
restartButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
GamePanel.resetGamePanel();
score=0;
setScore(0);
}
});
JPanel buttonPanel1=new JPanel();
buttonPanel1.add(startButton);
buttonPanel1.add(pauseButton);
JPanel buttonPanel2=new JPanel();
buttonPanel2.add(restartButton);
add(nextLabel);
add(nextPaintPanel);
add(scoreLabel);
add(displayScoreLabel);
add(buttonPanel1);
add(buttonPanel2);
}
//设置分数
public void setScore(int s)
{
score+=s*100;
displayScoreLabel.setText(String.valueOf(score));
}
private final int POSITION_X=0;
private final int POSITION_Y=0;
private final int WIDTH=200;
private final int HEIGHT=600;
private JLabel displayScoreLabel=new JLabel("0");
private int score=0;
private paintPanel nextPaintPanel=new paintPanel();
}
//显示next的面板
class paintPanel extends JPanel
{
public paintPanel()
{
nextBlock=getNextBlock();
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2=(Graphics2D)g;
int[][] locations=nextBlock.getLocation(4,4);
g2.setPaint(Color.BLUE);
for(int i=0;i<4;i++)
{
Rectangle2D rectangle=new Rectangle2D.Double(locations[i][0]*POINT_DISTANCE-1,locations[i][1]*POINT_DISTANCE-1,BLOCK_WIDTH,BLOCK_HEIGHT);
g2.fill(rectangle);
}
}
//获得下一个block的方法
private static Blocks getNextBlock()
{
int i=(int)(Math.random()*7);
if(i==0)
nextBlock=new OneBlock();
else if(i==1)
nextBlock=new LeftTwoBlock();
else if(i==2)
nextBlock=new RightTwoBlock();
else if(i==3)
nextBlock=new LeftThreeBlock();
else if(i==4)
nextBlock=new RightThreeBlock();
else if(i==5)
nextBlock=new FourBlock();
else if(i==6)
nextBlock=new FiveBlock();
return nextBlock;
}
//向GamePanel传递block的方法
public static Blocks getBlock()
{
Blocks temp=nextBlock;
nextBlock=getNextBlock();
return temp;
}
private static Blocks nextBlock;
private final double BLOCK_WIDTH=10;
private final double BLOCK_HEIGHT=10;
private final double POINT_DISTANCE=12;
}
package MyGame;
/**
* Created by zu on 2015/3/30.
*/
import java.awt.*;
import java.awt.geom.Rectangle2D;
import javax.swing.*;
public class GamePanel extends JPanel
{
public GamePanel()
{
for(int i=0;i<20;i++)
{
for(int j=0;j<30;j++)
grid[i][j]=0;
}
setBackground(Color.BLACK);//黑色背景
currentBlock=paintPanel.getBlock();
currentLocation[0]=9;
currentLocation[1]=0;
locations=currentBlock.getLocation(currentLocation[0], currentLocation[1]);
flag=false;
}
public void paintComponent(Graphics g)//绘制游戏区
{
super.paintComponent(g);
Graphics2D g2=(Graphics2D)g;
g2.setPaint(Color.BLUE);//蓝色方块
for(int i=0;i<20;i++)//将grid里所有为1的区域都绘制正方形
{
for(int j=0;j<30;j++)
{
if(grid[i][j]==1)
{
Rectangle2D rectangle=new Rectangle2D.Double(i*POINT_DISTANCE-1,j*POINT_DISTANCE-1,BLOCK_WIDTH,BLOCK_HEIGHT);
g2.fill(rectangle);
}
}
}
//然后再将当前方块对象绘制在游戏区
for(int i=0;i<4;i++)
{
if(locations[i][1]>=0)
{
Rectangle2D rectangle=new Rectangle2D.Double(locations[i][0]*POINT_DISTANCE-1,locations[i][1]*POINT_DISTANCE-1,BLOCK_WIDTH,BLOCK_HEIGHT);
g2.fill(rectangle);
}
}
}
//在游戏中移动方块的函数,是主要函数
public void move(int direction)
{
//flag==true,表示当前区域没有活动的对象,需要得到下一个对象
if(flag==true)
{
currentBlock=paintPanel.getBlock();
currentLocation[0]=9;
currentLocation[1]=0;
locations=currentBlock.getLocation(currentLocation[0], currentLocation[1]);
flag=false;
}
//表示当前区域有活动的对象
//判断是否到底,如果不能再落下,那么将当前对象的块坐标添加进grid里,然后设置flag为true
if(isBottom(locations)==true)
{
flag=true;
for(int i=0;i<4;i++)
{
if(locations[i][1]>=0)
grid[locations[i][0]][locations[i][1]]=1;
}
repaint();
if(checkOver()==true)
{
MainWindowFrame.stopTimer();
JOptionPane.showMessageDialog(null,"Game Over");
}
return;
}
//判断是否能左右移动,如果不行,那么当前点坐标的y值不再变化,如果可以,则y值加上direction,direction=1表示右移,-1表示左移,0表示没有左右移动
if(isEdge(direction)==false)
{
currentLocation[0]+=direction;
}
if(direction==0)
currentLocation[1]++;
locations=currentBlock.getLocation(currentLocation[0], currentLocation[1]);
repaint();
}
//在按下了向下的键后,直接移到底部的函数
public void moveToBottom()
{
int i=0;
while(isBottom(locations)==false)
{
i++;
for(int j=0;j<4;j++)
{
locations[j][1]++;
}
}
for(int j=0;j<4;j++)
{
if(locations[j][1]>=0)
{
grid[locations[j][0]][locations[j][1]]=1;
}
}
flag=true;
repaint();
}
//检测是否游戏结束
public boolean checkOver()
{
for(int i=0;i<4;i++)
{
if(locations[i][1]<0)
return true;
}
return false;
}
//检测是否到底
private boolean isBottom(int[][] l)
{
for(int i=0;i<4;i++)
{
if(l[i][1]>=0&&l[i][0]>=0&&l[i][0]<20)
{
if((l[i][1]+1)>=30||grid[l[i][0]][l[i][1]+1]==1)
{
return true;
}
}
}
return false;
}
//检测是否到达边缘
private boolean isEdge(int direction)
{
for(int i=0;i<4;i++)
{
if(locations[i][1]>=0)
{
if((locations[i][0]+direction)>=20||(locations[i][0]+direction)<0||grid[locations[i][0]+direction][locations[i][1]]==1)
{
return true;
}
}
}
return false;
}
//检测该行是否已满,并且进行消行处理
public int checkLine()
{
int lines=0;
for(int i=0;i<30;i++)
{
int sum=0;
for(int j=0;j<20;j++)
{
sum+=grid[j][i];
}
if(sum==20)
{
lines++;
for(int k=i;k>0;k--)
{
for(int h=0;h<20;h++)
{
grid[h][k]=grid[h][k-1];
}
}
for(int k=0;k<20;k++)
{
grid[k][0]=0;
}
i--;
repaint();
}
}
return lines;
}
//改变方块姿态的函数,不仅要改变姿态,还要检测改变后的方块是否越界,如果越界,就要进行调整
public void changePosition()
{
currentBlock.changePosition();
int min=0;
int max=0;
locations=currentBlock.getLocation(currentLocation[0], currentLocation[1]);
for(int i=0;i<4;i++)
{
if(min>locations[i][0])
{
min=locations[i][0];
}
if(max19)
{
currentLocation[0]-=(max-19);
}
locations=currentBlock.getLocation(currentLocation[0], currentLocation[1]);
repaint();
}
//当按下reset键的时候,重置GamePanel
public static void resetGamePanel()
{
for(int i=0;i<30;i++)
{
for(int j=0;j<20;j++)
{
grid[j][i]=0;
}
}
flag=true;
}
private static int[][] grid=new int[20][30];//用来存储游戏区数据的数组,为1表示当前格有方块,前个坐标表示x,后一个表示y,与一般的数组有点不一样
private Blocks currentBlock;//目前正在游戏区活动的方块
private int[][] locations;//当前活动方块的各个方块的坐标
private int[] currentLocation=new int[]{0,0};//当前参考点的坐标
private int BLOCK_WIDTH=18;//方块的边长
private int BLOCK_HEIGHT=18;
private int POINT_DISTANCE=20;//坐标点的间距
private static boolean flag=true;//为true时,表示当前没有活动的方块
}
package MyGame;
import javax.swing.*;
/**
* Created by zu on 2015/3/30.
*/
/*整个游戏的思路:在MainWindowFrame进程里建立一个定时器对象,每0.5s触发一次定时器事件,然后用此事件驱动游戏进行。
*/
public class Tetris
{
public static void main(String args[])
{
MainWindowFrame mainWindow=new MainWindowFrame();
mainWindow.setTitle("Tetris");
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainWindow.setVisible(true);
}
}
所用jdk版本为1.8.0,工具为IDEA 14.0.3