import java.awt.Color;
import java.awt.Font;
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.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Tetris extends JFrame{
private TetrisPane tp;//画图板
private JMenuItem itemNewGame,itemExit,itemPause;
public Tetris(){
setTitle("俄罗斯方块");
//设置菜单栏,需要加在前面,否则出现空指针异常
JMenuBar bar=new JMenuBar();
setJMenuBar(bar);
JMenu menuGame=new JMenu("游戏");
bar.add(menuGame);
itemNewGame=new JMenuItem("新游戏");
menuGame.add(itemNewGame);
menuGame.addSeparator();//设置分界线
itemPause=new JMenuItem("暂停/继续");
menuGame.add(itemPause);
menuGame.addSeparator();
itemExit=new JMenuItem("退出");
menuGame.add(itemExit);
JMenu menuHelp=new JMenu("帮助");
bar.add(menuHelp);
JMenuItem itemHelp=new JMenuItem("操作帮助...");
menuHelp.add(itemHelp);
JMenuItem itemMessage=new JMenuItem("版权信息...");
menuHelp.add(itemMessage);
//添加菜单监听
MenuListenser menulistener =new MenuListenser();
itemNewGame.setActionCommand("newGame");//设置命令符
itemNewGame.addActionListener(menulistener);
itemPause.setActionCommand("pause");
itemPause.addActionListener(menulistener);
itemExit.setActionCommand("exit");
itemExit.addActionListener(menulistener);
itemHelp.setActionCommand("help");//帮助信息
itemHelp.addActionListener(menulistener);
itemMessage.setActionCommand("message");//版权信息
itemMessage.addActionListener(menulistener);
//添加画图
tp=new TetrisPane();
add(tp);
addKeyListener(tp.listener);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(400, 60, 400, 670);//设置长宽高
}
public static void main(String[] args) {
Tetris t=new Tetris();
t.setVisible(true);
}
class TetrisPane extends JPanel{
int map[][]=new int[13][32];//// 定义地图,用来存放整个游戏方块区的状态(显示方格或不显示)//多留2行
// 存放块的位置:x=0~11 y=0~29
private int type;//7中类型
private int turnState;//四种状态
private Block block,tempBlock;//一个块,一个预算块
private Timer timer;//定时器
private TimerListener listener;//监听
private Color[][] netsColor=new Color[12][30];//设置每一格的颜色!
private int score;//分数
private int delay=1000;
private boolean isStop=true;//停止继续命令
public TetrisPane(){
showNextBlock();
nextBlock();
newGame();
}
private void newGame() {
for(int i=0;i<12;i++){
for(int j=0;j<30;j++){
map[i][j]=0;
map[0][j]=map[11][j]=3;
}
map[i][29]=3;
}
nextBlock();
if (timer!=null) {//移除监听,继续添加,否则会越来越快
timer.removeActionListener(listener);
}
listener=new TimerListener();
delay=1000;
timer=new Timer(delay, listener);
timer.start();
// itemNewGame.setEnabled(false);
}
//new一个新的块,
private void nextBlock() {
block=new Block(type, turnState);
block.Myvoid(tempBlock);
showNextBlock();//下一次更新是出现预算块
if(crash(block.x, block.y)==0){
timer.stop();
int option=JOptionPane.showConfirmDialog(this, "GAME OVER!,你输了!还敢来吗?");
if(option==JOptionPane.OK_OPTION){
newGame();
}else if(option==JOptionPane.NO_OPTION){
System.exit(0);
}else if(option==JOptionPane.CANCEL_OPTION){
}
}
}
public void showNextBlock(){
Random r=new Random();
type=r.nextInt(7);
turnState=r.nextInt(4);
tempBlock=new Block(type, turnState);
tempBlock.x=4;
tempBlock.y=0;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(block.shape[i][j]==1){//画块
g.setColor(block.c);
g.fillRect((i + block.x + 1) * 20, (j +block. y) * 20, 20, 20);
}
if(tempBlock.shape[i][j]==1){//画预算块
g.setColor(tempBlock.c);
g.fillRect((i + tempBlock.x + 10) * 20, (j + 2 +tempBlock. y) * 20, 20, 20);
}
}
}
g.setColor(Color.red);
// 画地图(已经固定的方块)
for (int j = 0; j < 30; j++) {
for (int i = 0; i < 12; i++) {
if (map[i][j] == 1) {
g.setColor(netsColor[i][j]);
g.fillRect(i * 20, j * 20, 20, 20);
// 让堆积块有分界线
g.setColor(Color.green);
g.drawRect(i * 20, j * 20, 20, 20);
g.setColor(Color.red);
} else if (map[i][j] == 3) {
g.drawRect(i * 20, j * 20, 20, 20);
}
}
}
//右侧部分
g.setColor(Color.blue);
g.setFont(new Font("aa", Font.BOLD, 25));//下一块提示
g.drawString("下一块:", 270, 30);
g.drawString("分数:"+score, 260, 180);
g.setFont(new Font("aa", Font.PLAIN, 20));
g.setColor(Color.green);
g.drawString("拒绝盗版游戏", 250, 260);
g.drawString("注意自我保护", 250, 290);
g.drawString("谨防受骗上当。", 250, 320);
g.drawString("适度游戏益脑,", 250, 350);
g.drawString("沉迷游戏伤身。", 250, 380);
g.drawString("合理安排时间,", 250, 410);
g.drawString("享受健康生活。", 250, 440);
g.drawString(" 解 释 权 归", 250, 480);
g.drawString(" 作 者 所 有", 250, 510);
g.setColor(Color.black);
g.setFont(new Font("aa", Font.ITALIC, 25));//下一块提示
g.drawString("王 建 安", 270, 600);
}
private int crash(int x, int y){//判断是否碰壁或碰撞,是返回0,否返回1
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if((block.shape[i][j]&map[x+i+1][y+j])==1){
return 0;
}
}
}
return 1;
}
private void add(Block block){
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(block.shape[i][j]==1){
map[block.x+i+1][block.y+j]=block.shape[i][j];
netsColor[block.x+i+1][block.y+j]=block.c;
}
}
}
tryDeline();
}
private void tryDeline() {
int count=0;//记录消了几行
for(int i=0;i<29;i++){//行号
int c=1;
for(int j=0;j<12;j++){
c=c&map[j][i];//相与,如果有一格不是1,则消不了
}
if(c==1){ //实心块是1,边界是3。这两者的最后一位都是1,和1&运算的结果是1
count++;
for(int k=i;k>0;k--){
for(int f=1;f<11;f++){
map[f][k]=map[f][k-1];
}
}
}
}
if (count!=0) {//设置得分和速度
if (count == 1) {
score += 10;
} else if (count == 2) {
score += 30;
} else if (count == 3) {
score += 80;
} else if (count == 4) {
score += 160;
}
if (delay>200) {
delay /= 2;
}
else{
delay -= 20;
}
}
}
private void down() {//向下走
if (block.y<29) {
if (crash(block.x, block.y + 1) == 0) {
add(block);
nextBlock();
}
block.y++;
repaint();
}
}
private void right(){//向右走
if(block.x<8){
block.x+=crash(block.x+1,block.y);
repaint();
}
}
private void left(){//左走
if(block.x>=0)
block.x-=crash(block.x-1,block.y);
repaint();
}
private void turn(){
block.turnState=(block.turnState+1)%4;
block.getShape();//必须要更新,不然信息对不上
block.turnState=((block.turnState+3)%4+crash(block.x,block.y ))%4;//如果碰撞,则返回
block.getShape();
repaint();
}
private void pause(){
if(isStop){
timer.stop();
isStop=false;
}else{
timer.restart();
isStop=true;
}
}
class TimerListener extends KeyAdapter implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
down();
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode=e.getKeyCode();
switch (keyCode) {
case KeyEvent.VK_UP:
turn();
break;
case KeyEvent.VK_DOWN:
down();
break;
case KeyEvent.VK_LEFT:
left();
break;
case KeyEvent.VK_RIGHT:
right();
break;
case KeyEvent.VK_P:
pause();
default:
break;
}
}
}
}
class Block
{
private int shape[][]=new int[4][4] ;
private Color c;//颜色
private int type;//类型
private int turnState;//旋转状态
private int x,y;//起始位置map[i][j]
public Block(int type, int turnState) {
this.type = type;
this.turnState = turnState;
getShape();
}
public void getShape(){
for(int i=0;i<4;i++){//初始化
for(int j=0;j<4;j++){
shape[i][j]=0;
}
}
if(type==0){//代表I型的情况
if(turnState==0||turnState==2){
for(int i=0;i<4;i++){
shape[i][1]=1;
}
}
if(turnState==1||turnState==3){
for(int i=0;i<4;i++){
shape[1][i]=1;
}
}
c=Color.red;
}
if(type==1){//代表o型
shape[1][1]=1;
shape[1][2]=1;
shape[2][1]=1;
shape[2][2]=1;
c=Color.CYAN;
}
if(type==2){//代表J型
if(turnState==0){
shape[1][0]=1;
shape[1][1]=1;
shape[1][2]=1;
shape[2][0]=1;
}else if(turnState==1){
shape[0][0]=1;
shape[1][0]=1;
shape[1][1]=1;
shape[1][2]=1;
}else if(turnState==2){
shape[0][0]=1;
shape[0][1]=1;
shape[1][1]=1;
shape[2][1]=1;
}else if(turnState==3){
shape[0][2]=1;
shape[0][0]=1;
shape[0][1]=1;
shape[1][2]=1;
}
c=Color.BLUE;
}
if(type==3){//代表L型
if(turnState==0){
shape[1][0]=1;
shape[1][1]=1;
shape[1][2]=1;
shape[2][2]=1;
}else if(turnState==1){
shape[0][0]=1;
shape[1][0]=1;
shape[0][1]=1;
shape[0][2]=1;
}else if(turnState==2){
shape[0][0]=1;
shape[0][1]=1;
shape[1][1]=1;
shape[2][1]=1;
}else if(turnState==3){
shape[0][1]=1;
shape[1][1]=1;
shape[2][1]=1;
shape[2][2]=1;
}
c=Color.MAGENTA;
}
if(type==4){//代表Z型
if(turnState==0||turnState==2){
shape[0][0]=1;
shape[0][1]=1;
shape[1][1]=1;
shape[1][2]=1;
}else {
shape[0][1]=1;
shape[1][0]=1;
shape[1][1]=1;
shape[2][0]=1;
}
c=Color.yellow;
}
if(type==5){//代表S型
if(turnState==0||turnState==2){
shape[0][1]=1;
shape[0][2]=1;
shape[1][0]=1;
shape[1][1]=1;
}else {
shape[0][0]=1;
shape[1][0]=1;
shape[1][1]=1;
shape[2][1]=1;
}
c=Color.PINK;
}
if(type==6){//代表T型
if(turnState==0){
shape[0][1]=1;
shape[1][0]=1;
shape[1][1]=1;
shape[1][2]=1;
}else if(turnState==1){
shape[0][1]=1;
shape[1][0]=1;
shape[1][1]=1;
shape[2][1]=1;
}else if(turnState==2){
shape[1][0]=1;
shape[1][1]=1;
shape[1][2]=1;
shape[2][1]=1;
}else if(turnState==3){
shape[0][1]=1;
shape[1][1]=1;
shape[1][2]=1;
shape[2][1]=1;
}
c=Color.orange;
}
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getTurnState() {
return turnState;
}
public void setTurnState(int turnState) {
this.turnState = turnState;
}
public Block Myvoid(Block temp){
this.x=temp.x;
this.y=temp.y;
this.shape=temp.shape;
this.turnState=temp.turnState;
this.c=temp.c;
this.type=temp.type;
return temp;
}
}
class MenuListenser implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
if(e.getActionCommand().equalsIgnoreCase("newGame")){
tp.newGame();
}else if(e.getActionCommand().equalsIgnoreCase("pause")){
tp.pause();
}else if(e.getActionCommand().equalsIgnoreCase("exit")){
System.exit(0);
}else if(e.getActionCommand().equalsIgnoreCase("help")){
tp.timer.stop();
JOptionPane.showMessageDialog(null, "↑为变换,↓为向下\n→为向右,←为向左\n P为暂停/继续");
tp.timer.restart();
}else if(e.getActionCommand().equalsIgnoreCase("message")){
tp.timer.stop();
JOptionPane.showMessageDialog(null, "单位: 湖南城市学院信科院\n作者 :王建安\n时间 :2016-1-24");
tp.timer.restart();
}
}
}
}