java俄罗斯方块小游戏编写心得03

    在”java俄罗斯方块小游戏编写心得02”中,我们已经做到了方块的各种功能的实现,那么接下来我们需要一个destroyLine()方法来对方块进行消除。我们需要想一个问题,当一个方块下落后,最多消除的行数也就只是方块可以达到的最大的行数。所以我们首先需要从方块行数最低的那个开始向下扫描,扫描每一个最基本小方块所处的行是否已经满了,如果没满,那么继续向下扫描,如果满了,那么该行消除,该行的上一行下落到该行,一定不可以从下向上扫描,如果从下向上扫描,可能会导致漏消。注:该方法应该在softMoveDropAction()、hardMoveDropAction()方法中均进行调用,否则会导致仅仅自由下落后才能消除,手动进行操作后无法进行消除。注: wall[n]=new Cell[10];wall[n]=wall[n-1];这个方法是不可取的

代码如下:

package com.CSDN;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Tetris extends JPanel{
    public void start() {
        while(true) {
            try {
                Thread.sleep(300);
            }catch(InterruptedException e) {
                e.printStackTrace();;
            }
            if(canDrop()) {
                currentOne.moveDrop();
            }else {
                landToWall();
                destroyLine();
                currentOne=nextOne;
                nextOne=Tetromino.RandomeOne();
            }
            repaint();
        }
    }
    public void softMoveDropAction() {
        if(canDrop()) {
            currentOne.moveDrop();
        }else {
            landToWall();
            destroyLine();
            currentOne=nextOne;
            nextOne=Tetromino.RandomeOne();
        }
    }
    public void hardMoveDropAction() {
        while(canDrop()) {
            currentOne.moveDrop();
        }
        landToWall();
        destroyLine();
        currentOne=nextOne;
        nextOne=Tetromino.RandomeOne();
    }
    public void destroyLine() {
        Cell[] cells=currentOne.cells;
        int row=cells[0].getRow();
        for(int i=0;i<4;i++) {
            if(cells[i].getRow()<row) {
                row=cells[i].getRow();
            }
        }
        for(int row1=row;row1<20;row1++) {
            int flag=1;
            for(int col1=0;col1<10;col1++) {
                if(wall[row1][col1]==null) {
                    flag=0;
                    break;
                }
            }
            if(flag==1) {
                System.out.println("0");
                for(int n=row1;n>0;n--) {
                    System.arraycopy(wall[n - 1], 0, wall[n], 0, 10);
                }
            }
        }
    }
}

    现在我们再次运行代码,已经可以进行消行了,但是仅仅消行还不行,我们还得让用户知道一共消了多少行,当然,每次消多少行也可以看到,只要会了总行数,将每次的消除的行数显示出来也是很轻而易举的,现在对于这个游戏只做总消除数,光有这个仍然是不够的,如果一个游戏没有分数,那显然是无法提起用户的兴趣和提升分数的决心的,所以我们可以消除一行就加1分,但是我们知道,一次性消行不仅仅只可以消一行,可能是一次性消除1、2、3、4行,所以我们可以这样设置分数,消除一行1分,两行2分,三行5分,四行10分,如何将行数和分数联系起来呢,轻而易举就想到了一维数组,一个是下标,一个是元素,所以,我们可以定义一个整形数组score_poor分数池,里面存放四个等级的分数,行数作为下标来提取分数。做完这些后,我们还需要将行数与分数显示在面板上,同样的定义一个paintScore(Graphics g)方法,然后在paint(Graphics g)方法中调用该方法即可。

代码如下:

package com.CSDN;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Tetris extends JPanel{
    private int[] score_poor= {0,1,2,5,10};
    private int totalScore=0;
    private int totalLines=0;
    public void paint(Graphics g) {
        paintScore(g);
    }
    public void destroyLine() {
        Cell[] cells=currentOne.cells;
        int row=cells[0].getRow();
        int line=0;
        for(int i=0;i<4;i++) {
            if(cells[i].getRow()<row) {
                row=cells[i].getRow();
            }
        }
        for(int row1=row;row1<20;row1++) {
            int flag=1;
            for(int col1=0;col1<10;col1++) {
                if(wall[row1][col1]==null) {
                    flag=0;
                    break;
                }
            }
            if(flag==1) {
                line++;
                System.out.println("0");
                for(int n=row1;n>0;n--) {
                    wall[n]=new Cell[10];
                    wall[n]=wall[n-1];
                }
            }
        }
        totalScore=totalScore+score_poor[line];
        totalLines=totalLines+line;
    }
    public void paintScore(Graphics g) {
        g.setFont(new Font(Font.DIALOG_INPUT,Font.BOLD,26));
        g.drawString("Score:"+totalScore,285, 165);
        g.drawString("Line:"+totalLines,285,215);
    }
}

    现在我们再次运行,界面上已经有了分数和行数,进行消行测试,我们功能正常,接下来我们进行下一步,我们知道,如果在玩游戏时有事情需要出去,那么游戏就需要暂停,所以,游戏还需要一个暂停功能,那么在暂停后如果我们想要继续游戏,所以还需要一个继续功能,如果游戏结束了,我们想要再来一局,总不能再次重新运行程序,所以我们需要一个重新开始键,综上所述,我们应该将这些分为两大类,操作与状态,一个状态对应一个操作,说道这里,对,又是一维数组,在游戏进行时(PLAYING)我们需要在旁边提示用户P键暂停,在游戏暂停时(PAUSE),我们需要在旁边提示用户C键继续,在游戏结束时(GAMEOVER),我们需要提示用户S键重新开始,所以我们需要再加入三个键的监听。其次,我们如何实现游戏是否结束的判断呢?当currentOne方块landToWall后,我们在此处应该先不使currentOne=nextOne,应该先判断是否isGameOver,如果return true;那么游戏结束,game_state==GAMEOVER,如果return false;那么游戏继续,所以现在的关键点就是isGameOver()方法如何来实现,我们知道当landToWall后,此时currentOne还并未=nextOne,所以我们可以用nextOne来判断,遍历nextOne每一个最基本小方块,如果该方块所处行列均为null,则说明还未结束,如果不为null,则说明方块已经到达了顶端,游戏无法再继续下去,所以我们由此可将game_state变为GAMEOVER。

代码如下:

package com.CSDN;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Tetris extends JPanel{
    private static final int PLAYING=0;
    private static final int PAUSE=1;
    private static final int GAMEOVER=2;
    private int game_state;
    public void start() {
        KeyListener l=new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                int code=e.getKeyCode();
                switch(code) {
                case KeyEvent.VK_P:
                    if(game_state==PLAYING) {
                        game_state=PAUSE;
                    }
                    break;
                case KeyEvent.VK_C:
                    if(game_state==PAUSE) {
                        game_state=PLAYING;
                    }
                    break;
                case KeyEvent.VK_S:
                    game_state=PLAYING;
                    wall=new Cell[20][10];
                    currentOne=Tetromino.RandomeOne();
                    nextOne=Tetromino.RandomeOne();
                    totalScore=0;
                    totalLines=0;
                    break;
                }
                repaint();
            }
        };
        this.addKeyListener(l);
        this.requestFocus();
        while(true) {
            try {
                Thread.sleep(300);
            }catch(InterruptedException e) {
                e.printStackTrace();;
            }
            if(game_state==PLAYING) {
                if(canDrop()) {
                    currentOne.moveDrop();
                }else {
                    landToWall();
                    destroyLine();
                    if(!isGameOver()) {
                        currentOne=nextOne;
                        nextOne=Tetromino.RandomeOne();
                    }else{
                        game_state=GAMEOVER;
                    }
                }
            }
            repaint();
        }    
    }
    public boolean isGameOver() {
        Cell[] cells=nextOne.cells;
        for(Cell c:cells) {
            int row=c.getRow();
            int col=c.getCol();
            if(wall[row][col]!=null) {
                return true;
            }
        }
        return false;
    }
    public void paintState(Graphics g) {
        if(game_state==PLAYING) {
            g.drawString(show_state[PLAYING],285,265);
        }
        if(game_state==PAUSE) {
            g.drawString(show_state[PAUSE],285,265);
        }
        if(game_state==GAMEOVER) {
            g.drawImage(GAMEOVERIMAGE,0,0,null);
            g.drawString(show_state[GAMEOVER],285,265);
        }
    }
}

   

文章到了此处,这个游戏便结束了,已经是第三次完整的写了一次,通过这第三次的再写,总结出几点:

1、有些东西并不是想想就能会的,一定要经过自己的手,一次两次还不够,一定要三次以上,才能够将
   一些知识点基本记在心底。
2、对于一些常犯的错误一定要予以总结,将错误原因写出,将当时的想法写出,最后将解决方法写出,
   这样能够更好的帮助以后不再犯同样的错误。
3、在面对问题时,首先想到的一定不能是放弃,程序遇到了BUG,我们就观察程序,是什么时候出的问题,
   在哪一步出的问题,比如在没消行时就不会出现某个方块落下后突然扩充到了整个列,而在消行后就会
   出现这个问题,那么必然就是消行方法出现了问题,所以就要去消行方法找问题所在,问题所在既然找
   到了,那么解决的方法逐渐逐渐就可以找到,毕竟方法总比问题多嘛。
4、在面对BUG时,一定要善于发现与总结,再根据计算机逻辑思想从运行顺序着手,总结出病症所在,然后
   进行解决,最重要的是形成一种自己的思维方式,拥有自己的思维及编程方式是我认为是一个程序员必
   不可少的能力。
5、必须多练习,多敲代码,好记性不如烂笔头,而且邓小平书记说过,实践是检验真理的唯一标准,如果不
   进行实践,我们就无法知道自己的欠缺在哪,那么改正加改进更无从谈起,码农码农,农民是种植物,码农
   是种字母,种逻辑,种思维,同样都是很辛苦的,不过既然选择了这条路,那就坚定不移的走下去,如果
   自己选择的路自己都怀疑,那我觉得这个世界上就没有什么是可以相信的了。

   
   坚定不移!相信自己!持之以恒!再接再厉!

猜你喜欢

转载自blog.csdn.net/z774884795/article/details/81269919
今日推荐