這是去年寫的第一個小項目(雖然感覺稱不上是項目),但畢竟是一次完整的編程過程,當作是編程路上的學習經歷發一下好了。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(); } }