简易俄罗斯方块(2)

1、提供一个start方法,封装游戏的主要逻辑

    (1)添加一个自动下落行为(死循环)

    public void start() {

                        while (true) {

                           /**

* 当程序运行到此,会进入睡眠状态, 睡眠时间为300毫秒,单位为毫秒 300毫秒后,会自动执行后续代码
*/
try {
Thread.sleep(800);
} catch (InterruptedException e) {
e.printStackTrace();
}


if (game_state == PLAYING) {
if (canDrop()) {
currentOne.softDrop();
} else {
landToWall();
destroyLine();
// 将下一个下落的四格方块赋值给正在下落的变量
if (!isGameOver()) {
currentOne = nextOne;
nextOne = Tetromino.randomOne();
} else {
game_state = GAMEOVER;
}
}
repaint();
/*
* 下落之后,要重新进行绘制,才会看到下落后的 位置 repaint方法 也是JPanel类中提供的 此方法中调用了paint方法
*/
}

}

    (2)考虑是否可以继续下落,定义方法canDrop

    public boolean canDrop() {
Cell[] cells = currentOne.cells;
/*

*/
for (Cell c : cells) {
/*
* 获取每个元素的行号和列号 判断: 只要有一个元素的下一行上有方块 或者只要有一个元素到达最后一行, 就不能再下落了
*/
int row = c.getRow();
int col = c.getCol();


if (row == 19) {
return false;
}
if (wall[row + 1][col] != null) {
return false;
}
}
return true;

}

    (3)不能下落的结果:着陆,修改正在下落的方块组合

    public void landToWall() {
Cell[] cells = currentOne.cells;
for (Cell c : cells) {
// 获取最终的行号和列号
int row = c.getRow();
int col = c.getCol();
wall[row][col] = c;
}

}

    (4)补全着陆功能landWall()

    (5)设置监听功能,进行键盘控制游戏

        game_state = PLAYING;
// 开启键盘监听事件
KeyListener l = new KeyAdapter() {
/*
* KeyPressed() 是键盘按钮 按下去所调用的方法
*/
public void keyPressed(KeyEvent e) {
// 获取一下键子的代号
int code = e.getKeyCode();


if (code == KeyEvent.VK_P) {
if (game_state == PLAYING) {
game_state = PAUSE;
}


}
if (code == KeyEvent.VK_C) {
if (game_state == PAUSE) {
game_state = PLAYING;
}
}
if (code == KeyEvent.VK_ENTER) {
game_state = PLAYING;
wall = new Cell[20][10];
currentOne = Tetromino.randomOne();
nextOne = Tetromino.randomOne();
totalScore = 0;
totalLine = 0;
}


switch (code) {
case KeyEvent.VK_DOWN:
softDropAction();
break;
case KeyEvent.VK_LEFT:
moveLeftAction();
break;
case KeyEvent.VK_RIGHT:
moveRightAction();
break;
case KeyEvent.VK_UP:
rotateRightAction();
break;
case KeyEvent.VK_SPACE:
handDropAction();
break;
}
repaint();
}


};
// 面板添加监听事件对象
this.addKeyListener(l);
// 面板对象设置成焦点

this.requestFocus();

(6)补全键盘监听需要的方法

    //使用down键控制四格方块的下落

    public void softDropAction() {
if (canDrop()) {
currentOne.softDrop();
} else {
landToWall();
destroyLine();
currentOne = nextOne;
nextOne = Tetromino.randomOne();
}

}

//使用left键控制向左的行为

protected void moveLeftAction() {
currentOne.moveLeft();
if (outOfBounds() || coincide()) {
currentOne.moveRight();
}

}

//使用right键控制向右的行为

protected void moveRightAction() {
currentOne.moveRight();
if (outOfBounds() || coincide()) {
currentOne.moveLeft();
}

}

2、旋转方块

(1)顺时针旋转方块

    public void rotateLeft() {
//旋转依次计数器增长1
count--;//100001
State s=states[count%states.length];
//需要获取轴的行号和列号
Cell c =cells[0];
int row=c.getRow();
int col=c.getCon();
cells[1].setRow(row+s.row1);
cells[1].setCon(col+s.col1);
cells[2].setRow(row+s.row2);
cells[2].setCon(col+s.col2);
cells[3].setRow(row+s.row3);
cells[3].setCon(col+s.col3);

}

(2)逆时针旋转方块

    public void rotateRight() {
//旋转依次计数器增长1
count++;//100001
State s=states[count%states.length];
//需要获取轴的行号和列号
Cell c =cells[0];
int row=c.getRow();
int col=c.getCon();
cells[1].setRow(row+s.row1);
cells[1].setCon(col+s.col1);
cells[2].setRow(row+s.row2);
cells[2].setCon(col+s.col2);
cells[3].setRow(row+s.row3);
cells[3].setCon(col+s.col3);

}

3、定义内部类,用于封装每次旋转后的相对于轴的其他三个方块的坐标(行号,列号)

public class State{
/*
* 设计八个属性,分别存储四格方块的相对位置
*/
int row0,col0,row1,col1,row2,col2,row3,col3;

public State(int row0, int col0, int row1, int col1, int row2, int col2, int row3, int col3) {
super();
this.row0 = row0;
this.col0 = col0;
this.row1 = row1;
this.col1 = col1;
this.row2 = row2;
this.col2 = col2;
this.row3 = row3;
this.col3 = col3;

}

    public State() {
super();

}

@Override
public String toString() {
return "State [row0=" + row0 + ", col0=" + col0 + ", row1=" + row1 + ", col1=" + col1 + ", row2=" + row2
+ ", col2=" + col2 + ", row3=" + row3 + ", col3=" + col3 + "]";
}


public int getRow0() {
return row0;
}


public void setRow0(int row0) {
this.row0 = row0;
}


public int getCol0() {
return col0;
}


public void setCol0(int col0) {
this.col0 = col0;
}


public int getRow1() {
return row1;
}


public void setRow1(int row1) {
this.row1 = row1;
}


public int getCol1() {
return col1;
}


public void setCol1(int col1) {
this.col1 = col1;
}


public int getRow2() {
return row2;
}


public void setRow2(int row2) {
this.row2 = row2;
}


public int getCol2() {
return col2;
}


public void setCol2(int col2) {
this.col2 = col2;
}


public int getRow3() {
return row3;
}


public void setRow3(int row3) {
this.row3 = row3;
}


public int getCol3() {
return col3;
}


public void setCol3(int col3) {
this.col3 = col3;
}



}

4、在方块形状类(I,L,...)中设置旋转之前和旋转n/4的余数次后的坐标表示

    I:

    states = new State[4];
states[0] = new State(0,0,0,-1,0,1,0,2);

states[1] = new State(0,0,-1,0,1,0,2,0);

    L:

    states = new State[4];
states[0] = new State(0,0,0,-1,0,1,1,1);
states[1] = new State(0,0,-1,0,1,0,1,-1);
states[2] = new State(0,0,0,1,0,-1,-1,-1);

states[3] = new State(0,0,1,0,-1,0,-1,1);

其他的类比I,L填写即可

5、消除方块,即满一行就消除一行,上面的方块向下平移

    public void destroyLine(){
Cell[] cells = currentOne.cells;
for(Cell c:cells){
//取出每个元素所在的行号
int row = c.getRow();
//取出当前行的所有列
Cell[] line = wall[row];
boolean flag = false;
for(Cell r:line){
if(r==null){
flag = true;
break;
}
}
if(!flag){
//使用null填满数组元素
Arrays.fill(wall[row], null);
for(int i=row;i>0;i--){
wall[i] = wall[i-1];
}
}
}

}

6、对方块会超出墙进行限制

     public boolean outOfBounds() {
Cell[] cells = currentOne.cells;
for (Cell c : cells) {
int col = c.getCol();
int row = c.getRow();
if (col < 0 || col > 9 || row > 19 || row < 0) {
return true;
}
}
return false;

}

public boolean coincide() {
Cell[] cells = currentOne.cells;
for (Cell c : cells) {
int row = c.getRow();
int col = c.getCol();
if (wall[row][col] != null) {
return true;
}
}
return false;

}

7、统计分数 一次消除一行为一分,一次消除2行为2分,一次消除3行为5分,一次消除4行为十分

int[] scores_pool = { 0, 1, 2, 5, 10 };
private int totalScore = 0;

private int totalLine = 0;

totalScore += scores_pool[lines];

totalLine += lines;

8、定义三个常量为游戏状态及定义属性储存游戏状态,并在图形界面中绘制出游戏状态位置

public static final int PLAYING = 0;
public static final int PAUSE = 1;

public static final int GAMEOVER = 2;

private int game_state;

private void paintState(Graphics g) {
if (game_state == GAMEOVER) {
g.drawImage(game_over, 0, 0, null);
g.drawString(showState[GAMEOVER], 285, 265);
}
if (game_state == PLAYING) {
g.drawString(showState[PLAYING], 285, 265);
}
if (game_state == PAUSE) {
g.drawString(showState[PAUSE], 285, 265);
}

}

public void paintScore(Graphics g) {
g.setFont(new Font(Font.SANS_SERIF, Font.ITALIC, 26));
g.drawString("SCORES:" + totalScore, 285, 165);
g.drawString("LINES:" + totalLine, 285, 215);
}

猜你喜欢

转载自blog.csdn.net/wyq15004350208/article/details/80545337