在”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、必须多练习,多敲代码,好记性不如烂笔头,而且邓小平书记说过,实践是检验真理的唯一标准,如果不
进行实践,我们就无法知道自己的欠缺在哪,那么改正加改进更无从谈起,码农码农,农民是种植物,码农
是种字母,种逻辑,种思维,同样都是很辛苦的,不过既然选择了这条路,那就坚定不移的走下去,如果
自己选择的路自己都怀疑,那我觉得这个世界上就没有什么是可以相信的了。
坚定不移!相信自己!持之以恒!再接再厉!