俄罗斯方块开发小结

作者: TaXue_WWL | 来源:发表于2014-12-07 20:45 被阅读847次
    俄罗斯方块.png

    学习Java半年有余,总想做点什么出来,而不是只纠结与语法和各种类包不可自拔。 于是我想,何不搞一个小游戏出来。 俄罗斯方块?脑海里浮现出这个名字,就它了,逻辑简单,对于我而言更可控, 在网上查找相关的规则之后,经过五天的编码和设计,终于做了出来。

    我也不多说废话了,直接贴代码,注释很详细了,希望可以帮到大家~

    1. 主逻辑的实现:游戏流程控制

      //package 俄罗斯方块;

      /**俄罗斯方块
      *date 14.11.17
      *@version 1.0

      @author TaXueWWL
      /
      import java.awt.
      ;
      import java.awt.event.
      ;
      import javax.swing.
      ;
      import javax.swing.Timer;

      class Tetrisblok extends JPanel implements KeyListener{
      /**
      *俄罗斯方块类Tetrisblok继承JPanel,同时实现键盘事件接口KeyListener
      */
      private static final long serialVersionUID = 1L;
      private int blockType;//方块类型
      private int turnState;//方块旋转状态
      private int score = 0;//分数
      private int nextblockType = -1, nextturnState = -1;//下一方块的类型和状态
      private int x, y;//当前方块的位置
      private Timer timer;//定时器
      //游戏地图,存储已经放下的方块(1)及围墙(2),空白处为(0)
      int[][] map = new int[12][21];
      //方块的形状,有倒Z,Z,L,J,I,田,和T 7种

      p/**
      *三维数组shapes存储7种方块形状及其旋转变形,代码如下
      */
      private final int shapes[][][] = new int[][][]{
      //长条T形 ***
      // ×
      { {0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},
      {0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0},
      {0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0},
      {0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0}},
      //倒Z字形 **
      // **
      { {0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},
      {1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
      {0,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0},
      {1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0}},
      //Z字形 **
      // **
      { {1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
      {0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0},
      {1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0},
      {0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0}},
      //J字形 *
      // ***
      { {0,1,0,0,0,1,0,0,1,1,0,0,0,0,0,0},
      {1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
      {1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0},
      {1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0}},
      //田字形 **
      // **
      { {1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
      {1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
      {1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0},
      {1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0}},
      //L字形 *
      // *
      // *×
      { {1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0},
      {1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0},
      {1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0},
      {0,0,1,0,1,1,1,0,0,0,0,0,0,0,0,0}},
      //⊥字形 *
      // ***
      { {0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0},
      {0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0},
      {1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0},
      {0,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0}}};

      /**
      产生下一方块及其旋转状态
      /
      public void newblock(){
      //没有下一方块
      if(nextblockType == -1 && nextturnState == -1){
      blockType = (int)(Math.random()
      1000)%7;
      turnState = (int)(Math.random()
      1000)%4;
      nextblockType = (int)(Math.random() * 1000)%7;
      nextturnState = (int)(Math.random() * 1000)%4;
      }
      else{//已有下一方块
      blockType = nextblockType;
      turnState = nextturnState;
      nextblockType = (int)(Math.random() * 1000)%7;
      nextturnState = (int)(Math.random() * 1000)%4;
      }
      x = 4; y = 0;//屏幕上方中央
      if(gameover(x, y) == 1){//游戏结束
      newmap();
      drawwall();
      score = 0;
      JOptionPane.showMessageDialog(null, "GAME OVER...");
      }
      }
      /**
      *画围墙
      */
      public void drawwall(){
      int i, j;
      for(i = 0; i < 12; i++){
      map[i][20] = 2;
      }
      for(j = 0; j < 21; j++){//在0列和11列
      map[11][j] = 2;
      map[0][j] = 2;
      }

      }
      //初始化地图
      public void newmap(){
      int i, j;
      for(i = 0; i < 12; i++){
      for(j = 0; j < 21; j++){
      map[i][j] = 0;
      }
      }
      }
      /**
      *Tetrisblok()构造方法产生一个新的下落方块,并启动定时器。
      *定时器触发事件完成屏幕屏幕重画,判断当前方块是否可以下落
      产生新的方块
      /
      Tetrisblok(){
      newblock();
      newmap();
      drawwall();
      timer = new Timer(500, new TimerListener());//0.5s
      timer.start();
      }
      //定时器监听事件
      class TimerListener implements ActionListener{
      public void actionPerformed(ActionEvent e){
      if(blow(x, y + 1, blockType, turnState) == 1){//可以下落
      y = y + 1;//当前方块下落
      }
      if(blow(x, y + 1, blockType, turnState) == 0){//不可以下落
      add(x, y, blockType, turnState);//固定当前方块
      delline();//消去满行
      newblock();//产生新的方块
      }
      repaint();
      }
      }
      //菜单事件,达到游戏暂停和继续
      public void newGame()//新游戏
      {
      newblock();
      newmap();
      drawwall();
      }
      public void pauseGame()//暂停游戏
      {
      timer.stop();
      }
      public void continueGame()//继续游戏
      {
      timer.start();
      }
      /

      *turn()旋转当前方块,旋转次数加一后,blow判断是否可以
      *旋转,不可以则旋转次数恢复为原来的值
      */

       //旋转当前方块
       public void turn(){
           int tempturnState = turnState;
           turnState = (turnState + 1) % 4;
           if(blow(x, y, blockType, turnState) == 1){//可以旋转
           }
           if(blow(x, y, blockType, turnState) == 0){//不可旋转
               turnState = tempturnState;//将旋转次数恢复为原来的值
           }
           repaint();
       }
       //方向移动方块,判断可移动后重画
      public void left(){
       if(blow(x - 1, y, blockType, turnState) == 1){
           x = x - 1;
       }
       repaint();
      }
      
      public void right(){
       if(blow(x + 1, y, blockType, turnState) == 1){
           x = x + 1;
       }
       repaint();
      }
      
      public void down(){
       if(blow(x, y + 1, blockType, turnState) == 1){//可以下落
           y = y + 1;
       }
       if(blow(x, y + 1, blockType, turnState) == 0){//不能下落
           add(x, y, blockType, turnState);
           newblock();
           delline();
       }
       repaint();
      }
      //判断移动或旋转后位置是否合法,是否与墙壁碰撞
      public int blow(int x, int y, int blockType, int turnState){
           for(int a = 0; a < 4; a++){
               for(int b = 0; b < 4; b++){
                   if(((shapes[blockType][turnState][a * 4 + b] == 1) &&
                   (map[x + b + 1][y + a] == 1)) || 
                   ((shapes[blockType][turnState][a * 4 + b] == 1) &&
                   (map[x + b + 1][y + a] == 2))){
                       return 0;
                   }
               }
           }
           return 1;
      }
      //delline()消去满行,第d行满则上方方块下移
      public void delline(){
           int c = 0;
           for(int b = 0; b < 21; b++){
               for(int a = 0; a < 12; a++){
                   if(map[a][b] == 1){
                       c += 1;
                       if(c == 10){//该行满
                           score += 10;
                           for(int d = b; d > 0; d--){
                               for(int e = 0; e < 12; e++){
                                   //上方方块下移
                                   map[e][d] = map[e][d - 1];
                               }
                           }
                       }
                   }
               }
               c = 0;
           }
      }
      //gameover
      public int gameover(int x, int y){
           if(blow(x, y, blockType, turnState) == 0){
               return 1;
           }
           return 0;
      }
      //添加当前方块到地图
      public void add(int x, int y, int blockType, int turnState){
           int j = 0;
           for(int a = 0; a < 4; a++){
               for(int b = 0; b < 4; b++){
                   if(shapes[blockType][turnState][j] == 1){
                       map[x + b + 1][y + a] = shapes[blockType][turnState][j];
                   }
                   j++;
               }
           }
      }
      //paint()重画屏幕
      public void paint(Graphics g){
           super.paint(g);//调用父类的paint()方法,实现初始化清屏
           int i, j;
           //画当前方块
           for(j = 0; j < 16; j++){
               if(shapes[blockType][turnState][j] == 1){
                   g.fillRect((j % 4 + x + 1) * 15, (j / 4 + y) * 15, 15, 15);  
               }
           }
           //画已经固定的方块和围墙
           for(j = 0; j < 21; j++){
               for(i = 0; i < 12; i++){
                   if(map[i][j] == 1){
                       //画方块
                       g.fillRect(i * 15, j * 15, 15, 15);
                   }
                   if(map[i][j] == 2){
                       //画围墙
                       g.fillRect(i * 15, j * 15, 15, 15);
                   }
               }
           }
           g.drawString("SCORE= " + score, 225, 15);
           g.drawString("nextBlockShape ", 225, 50);
           //在窗口右侧区域绘制下一方块
           for(j = 0; j < 16; j++){
               if(shapes[nextblockType][nextturnState][j] == 1){
                   g.fillRect(225 + (j % 4) * 15, (j / 4) * 15 + 100, 15, 15);
               }
           }
      }
      //键盘监听
      public void keyPressed(KeyEvent e){
           switch(e.getKeyCode()){
               case KeyEvent.VK_DOWN:
                   down();
                   break;
               case KeyEvent.VK_UP:
                   turn();
                   break;
               case KeyEvent.VK_RIGHT:
                   right();
                   break;
               case KeyEvent.VK_LEFT:
                   left();
                   break;  
           }
      }
      //No use to type other keys
      public void keyReleased(KeyEvent e){
      }
      public void keyTyped(KeyEvent e){
      } 
      

      }
      2.游戏面板呈现

      //package 俄罗斯方块;

      /**
      *显示游戏面板Tetrisblok界面,加入菜单以及时间监听
      */

      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      //import 俄罗斯方块.Tetrisblok;
      import javax.swing.*;
      @SuppressWarnings("serial")
      public class TetrisFrame extends JFrame implements ActionListener{
      static JMenu game = new JMenu("游戏");
      JMenuItem newgame = game.add("新游戏");
      JMenuItem pause = game.add("暂停");
      JMenuItem goon = game.add("继续");
      JMenuItem exit = game.add("退出");
      static JMenu help = new JMenu("帮助");
      JMenuItem about = help.add("关于");
      Tetrisblok a = new Tetrisblok();
      public TetrisFrame(){
      addKeyListener(a);
      this.add(a);
      newgame.addActionListener(this);//"新游戏"菜单项
      pause.addActionListener(this);//"暂停"菜单项
      goon.addActionListener(this);//"继续"菜单项
      about.addActionListener(this);//"关于"菜单项
      exit.addActionListener(this);//"退出"菜单项
      }

       public void actionPerformed(ActionEvent e){
           if(e.getSource() == newgame)//"新游戏"菜单项
           {
               a.newGame();
           }
           else if(e.getSource() == pause)//"暂停"菜单项
           {
               a.pauseGame();
           }
           else if(e.getSource() == goon)//"继续"菜单项
           {
               a.continueGame();
           }
           else if(e.getSource() == about)//"关于"菜单项
           {
               DisplayToast("按左右键移动\n上键进行方块旋转~\n\r\rMade_by_WWL\nFor SSR_LSC_LWW_CYD_XM");
           }
           else if(e.getSource() == exit)//"退出"菜单项
           {
               System.exit(0);
           }
       }
      
       public void DisplayToast(String str){
           JOptionPane.showMessageDialog(null, str, "游戏提示", 
                                       JOptionPane.ERROR_MESSAGE);
       }
      
       //Main Method
       public static void main(String[] args){
           TetrisFrame frame = new TetrisFrame();
           JMenuBar menu = new JMenuBar();
           frame.setJMenuBar(menu);
           menu.add(game);
           menu.add(help);
           frame.setLocationRelativeTo(null);
           frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//"结束"按钮可使用
           frame.setSize(320, 380);
           frame.setTitle("俄罗斯方块V1.0--for XM");
           //frame.setUndecorated(true);
           frame.setVisible(true);
           frame.setResizable(false);
       }
      

      }
      鸣谢:

    感谢一直支持我的父亲,默默地爱着我的母亲,还有9102的小伙伴们,以及316的兄弟们。
    也感谢努力着的自己,多年以后回头看到现在的自己,会笑着说声:“谢谢你,曾经这样的努力~”

    相关文章

      网友评论

        本文标题:俄罗斯方块开发小结

        本文链接:https://www.haomeiwen.com/subject/zehntttx.html