使用Java实现小游戏:俄罗斯方块

使用Java实现小游戏:俄罗斯方块

使用一个二维数组保存游戏的地图:

// 游戏地图格子,每个格子保存一个方块,数组纪录方块的状态
private State map[][] = new State[rows][columns];

游戏前先将所有地图中的格子初始化为空:

/* 初始化所有的方块为空 */
for (int i = 0; i < map.length; i++) {
    for (int j = 0; j < map[i].length; j++) {
        map[i][j] = State.EMPTY;
    }
}

玩游戏过程中,我们能够看到界面上的方块,那么就得将地图中所有的方块绘制出来,当然,除了需要绘制方块外,游戏积分和游戏结束的字符串在必要的时候也需要绘制:

/**
 * 绘制窗体内容,包括游戏方块,游戏积分或结束字符串
 */
@Override
public void paint(Graphics g) {
    super.paint(g);
    for (int i = 0; i < rows; i++) {
        for (int j = 0; j < columns; j++) {
            if (map[i][j] == State.ACTIVE) { // 绘制活动块
                g.setColor(activeColor);
                g.fillRoundRect(j * BLOCK_SIZE, i * BLOCK_SIZE + 25,
                        BLOCK_SIZE - 1, BLOCK_SIZE - 1, BLOCK_SIZE / 5,
                        BLOCK_SIZE / 5);
            } else if (map[i][j] == State.STOPED) { // 绘制静止块
                g.setColor(stopedColor);
                g.fillRoundRect(j * BLOCK_SIZE, i * BLOCK_SIZE + 25,
                        BLOCK_SIZE - 1, BLOCK_SIZE - 1, BLOCK_SIZE / 5,
                        BLOCK_SIZE / 5);
            }
        }
    }

    /* 打印得分 */
    g.setColor(scoreColor);
    g.setFont(new Font("Times New Roman", Font.BOLD, 30));
    g.drawString("SCORE : " + totalScore, 5, 70);

    // 游戏结束,打印结束字符串
    if (!isGoingOn) {
        g.setColor(Color.RED);
        g.setFont(new Font("Times New Roman", Font.BOLD, 40));
        g.drawString("GAME OVER !", this.getWidth() / 2 - 140,
                this.getHeight() / 2);
    }
}

通过随机数的方式产生方块所组成的几种图形,一般七种图形:条形、田形、正7形、反7形、T形、Z形和反Z形,如生成条形:

map[0][randPos] = map[0][randPos - 1] = map[0][randPos + 1] 
                = map[0][randPos + 2] = State.ACTIVE;

生成图形后,实现下落的操作。如果遇到阻碍,则不能再继续下落:

isFall = true; // 是否能够下落
// 从当前行检查,如果遇到阻碍,则停止下落
for (int i = 0; i < blockRows; i++) {
    for (int j = 0; j < columns; j++) {
        // 遍历到行中块为活动块,而下一行块为静止块,则遇到阻碍
        if (map[rowIndex - i][j] == State.ACTIVE
                && map[rowIndex - i + 1][j] == State.STOPED) {
            isFall = false; // 停止下落
            break;
        }
    }
    if (!isFall)
        break;
}

如果未遇到阻碍,则下落的时候,方块图形整体向下移动一行:

// 图形下落一行
for (int i = 0; i < blockRows; i++) {
    for (int j = 0; j < columns; j++) {
        if (map[rowIndex - i][j] == State.ACTIVE) { // 活动块向下移动一行
            map[rowIndex - i][j] = State.EMPTY; // 原活动块变成空块
            map[rowIndex - i + 1][j] = State.ACTIVE; // 下一行块变成活动块
        }
    }
}

向左、向右方向移动时是类似的操作:

/**
 * 向左走
 */
private void left() {
    // 标记左边是否有阻碍
    boolean hasBlock = false;

    /* 判断是否左边有阻碍 */
    for (int i = 0; i < blockRows; i++) {
        if (map[rowIndex - i][0] == State.ACTIVE) { // 判断左边是否为墙
            hasBlock = true;
            break; // 有阻碍,不用再循环判断行
        } else {
            for (int j = 1; j < columns; j++) { // 判断左边是否有其它块
                if (map[rowIndex - i][j] == State.ACTIVE
                        && map[rowIndex - i][j - 1] == State.STOPED) {
                    hasBlock = true;
                    break; // 有阻碍,不用再循环判断列
                }
            }
            if (hasBlock)
                break; // 有阻碍,不用再循环判断行
        }
    }

    /* 左边没有阻碍,则将图形向左移动一个块的距离 */
    if (!hasBlock) {
        for (int i = 0; i < blockRows; i++) {
            for (int j = 1; j < columns; j++) {
                if (map[rowIndex - i][j] == State.ACTIVE) {
                    map[rowIndex - i][j] = State.EMPTY;
                    map[rowIndex - i][j - 1] = State.ACTIVE;
                }
            }
        }

        // 重绘
        repaint();
    }
}

向下加速移动时,就是减小每次正常状态下落的时间间隔:

/**
 * 向下直走
 */
private void down() {
    // 标记可以加速下落
    immediate = true;
}

如何变换图形方向,这里仅使用了非常简单的方法来实现方向变换,当然可以有更优的算法实现方向变换操作,大家可以自己研究:

/**
 * 旋转方块图形
 */
private void rotate() {
    try {
        if (shape == 4) { // 方形,旋转前后是同一个形状
            return;
        } else if (shape == 0) { // 条状
            // 临时数组,放置旋转后图形
            State[][] tmp = new State[4][4];
            int startColumn = 0;
            // 找到图形开始的第一个方块位置
            for (int i = 0; i < columns; i++) {
                if (map[rowIndex][i] == State.ACTIVE) {
                    startColumn = i;
                    break;
                }
            }
            // 查找旋转之后是否有阻碍,如果有阻碍,则不旋转
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 4; j++) {
                    if (map[rowIndex - 3 + i][j + startColumn] == State.STOPED) {
                        return;
                    }
                }
            }

            if (map[rowIndex][startColumn + 1] == State.ACTIVE) { // 横向条形,变换为竖立条形
                for (int i = 0; i < 4; i++) {
                    tmp[i][0] = State.ACTIVE;
                    for (int j = 1; j < 4; j++) {
                        tmp[i][j] = State.EMPTY;
                    }
                }
                blockRows = 4;
            } else { // 竖立条形,变换为横向条形
                for (int j = 0; j < 4; j++) {
                    tmp[3][j] = State.ACTIVE;
                    for (int i = 0; i < 3; i++) {
                        tmp[i][j] = State.EMPTY;
                    }
                }
                blockRows = 1;
            }
            // 将原地图中图形修改为变换后图形
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 4; j++) {
                    map[rowIndex - 3 + i][startColumn + j] = tmp[i][j];
                }
            }
        } else {
            // 临时数组,放置旋转后图形
            State[][] tmp = new State[3][3];
            int startColumn = columns;
            // 找到图形开始的第一个方块位置
            for (int j = 0; j < 3; j++) {
                for (int i = 0; i < columns; i++) {
                    if (map[rowIndex - j][i] == State.ACTIVE) {
                        startColumn = i < startColumn ? i : startColumn;
                    }
                }
            }
            // 判断变换后是否会遇到阻碍
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    if (map[rowIndex - 2 + j][startColumn + 2 - i] == State.STOPED)
                        return;
                }
            }
            // 变换
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    tmp[2 - j][i] = map[rowIndex - 2 + i][startColumn + j];
                }
            }
            // 将原地图中图形修改为变换后图形
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    map[rowIndex - 2 + i][startColumn + j] = tmp[i][j];
                }
            }

            // 重绘
            repaint();
            // 重新修改行指针
            for (int i = 0; i < 3; i++) {
                for (int j = 0; j < 3; j++) {
                    if (map[rowIndex - i][startColumn + j] != null
                            || map[rowIndex - i][startColumn + j] != State.EMPTY) {
                        rowIndex = rowIndex - i;
                        blockRows = 3;
                        return;
                    }
                }
            }
        }
    } catch (Exception e) {
        // 遇到数组下标越界,说明不能变换图形形状,不作任何处理
    }
}

当图形下落遇到阻碍时停止,我们就需要判断这时是否有某一行或几行可以消除掉,这时可以先获取每行中方块的个数,然后再进行判断:

int[] blocksCount = new int[rows]; // 记录每行有方块的列数
int eliminateRows = 0; // 消除的行数
/* 计算每行方块数量 */
for (int i = 0; i < rows; i++) {
    blocksCount[i] = 0;
    for (int j = 0; j < columns; j++) {
        if (map[i][j] == State.STOPED)
            blocksCount[i]++;
    }
}

如果有满行的方块,则消除掉该行方块:

/* 实现有满行的方块消除操作 */
for (int i = 0; i < rows; i++) {
    if (blocksCount[i] == columns) {
        // 清除一行
        for (int m = i; m >= 0; m--) {
            for (int n = 0; n < columns; n++) {
                map[m][n] = (m == 0) ? State.EMPTY : map[m - 1][n];
            }
        }
            eliminateRows++; // 记录消除行数
    }
}

最后我们再重绘显示积分就可以了。

重复以上的生成图形、图形下落、左右下移动、判断消除行的操作,一个简单的俄罗斯方块就完成了。

运行效果:

运行效果

完整示例代码:http://download.csdn.net/download/zhliro/8703889

  • 10
    点赞
  • 86
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
很高兴回答你的问题!以下是一个简单的使用Java实现俄罗斯方块小游戏的示例代码: ```java import javax.swing.*; import java.awt.*; import java.awt.event.*; public class TetrisGame extends JFrame { private final int WIDTH = 10; private final int HEIGHT = 20; private final int SQUARE_SIZE = 30; private final int BOARD_X = 10; private final int BOARD_Y = 30; private final int FPS = 60; private Timer gameTimer; private Tetromino currentPiece; private Board board; public TetrisGame() { setTitle("Tetris"); setSize(WIDTH * SQUARE_SIZE + 2 * BOARD_X, HEIGHT * SQUARE_SIZE + 2 * BOARD_Y); setDefaultCloseOperation(EXIT_ON_CLOSE); setLocationRelativeTo(null); setResizable(false); board = new Board(WIDTH, HEIGHT); currentPiece = new Tetromino(); gameTimer = new Timer(1000 / FPS, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { update(); repaint(); } }); addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { handleKeyPress(e.getKeyCode()); } }); setVisible(true); gameTimer.start(); } private void update() { if (!board.isGameOver()) { currentPiece.update(); if (board.isCollision(currentPiece)) { currentPiece.undo(); board.addPiece(currentPiece); currentPiece = new Tetromino(); if (board.isCollision(currentPiece)) { board.setGameOver(true); gameTimer.stop(); } } } } private void handleKeyPress(int keyCode) { if (!board.isGameOver()) { switch (keyCode) { case KeyEvent.VK_LEFT: currentPiece.moveLeft(); if (board.isCollision(currentPiece)) { currentPiece.moveRight(); } break; case KeyEvent.VK_RIGHT: currentPiece.moveRight(); if (board.isCollision(currentPiece)) { currentPiece.moveLeft(); } break; case KeyEvent.VK_DOWN: currentPiece.moveDown(); if (board.isCollision(currentPiece)) { currentPiece.moveUp(); board.addPiece(currentPiece); currentPiece = new Tetromino(); if (board.isCollision(currentPiece)) { board.setGameOver(true); gameTimer.stop(); } } break; case KeyEvent.VK_SPACE: currentPiece.rotate(); if (board.isCollision(currentPiece)) { currentPiece.rotateBack(); } break; } } } @Override public void paint(Graphics g) { super.paint(g); g.translate(BOARD_X, BOARD_Y); board.draw(g); currentPiece.draw(g); } public static void main(String[] args) { new TetrisGame(); } } ``` 这是一个简单的俄罗斯方块游戏使用Java的Swing库进行界面的绘制和事件的处理。游戏中,使用方向键控制方块的移动,空格键控制方块的旋转。 希望这个示例代码对你有所帮助!如果有任何疑问,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值