自学内容网 自学内容网

【C++进阶实战】俄罗斯方块游戏

俄罗斯方块游戏

题目描述: 开发一个简单的俄罗斯方块游戏,支持以下功能:

  1. 初始化游戏板。
  2. 随机生成方块并使其下降。
  3. 用户可以通过键盘控制方块的左右移动和旋转。
  4. 检查是否有完整的行并消除。
  5. 显示游戏板的状态。
  6. 用户可以选择重新开始游戏或退出游戏。

要求

  1. 使用二维数组来表示游戏板。
  2. 提供友好的用户界面,使用菜单选择功能。

示例代码框架

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
#include <conio.h>  // 用于非阻塞输入
#include <thread>
#include <chrono>
using namespace std;

const int BOARD_WIDTH = 10;
const int BOARD_HEIGHT = 20;
const char EMPTY = ' ';
const char BLOCK = '#';

enum TetrominoType {
    I, J, L, O, S, T, Z
};

struct Tetromino {
    TetrominoType type;
    vector<vector<char>> shape;
    int x, y;
};

class Tetris {
private:
    vector<vector<char>> board;
    Tetromino currentTetromino;
    bool gameOver;

    void initializeBoard() {
        board.resize(BOARD_HEIGHT, vector<char>(BOARD_WIDTH, EMPTY));
        gameOver = false;
    }

    void generateTetromino() {
        srand(time(0));  // 初始化随机数生成器
        TetrominoType type = static_cast<TetrominoType>(rand() % 7);
        currentTetromino.type = type;
        switch (type) {
            case I:
                currentTetromino.shape = {{BLOCK, BLOCK, BLOCK, BLOCK}};
                break;
            case J:
                currentTetromino.shape = {{BLOCK, 0, 0}, {BLOCK, BLOCK, BLOCK}};
                break;
            case L:
                currentTetromino.shape = {{0, 0, BLOCK}, {BLOCK, BLOCK, BLOCK}};
                break;
            case O:
                currentTetromino.shape = {{BLOCK, BLOCK}, {BLOCK, BLOCK}};
                break;
            case S:
                currentTetromino.shape = {{0, BLOCK, BLOCK}, {BLOCK, BLOCK, 0}};
                break;
            case T:
                currentTetromino.shape = {{0, BLOCK, 0}, {BLOCK, BLOCK, BLOCK}};
                break;
            case Z:
                currentTetromino.shape = {{BLOCK, BLOCK, 0}, {0, BLOCK, BLOCK}};
                break;
        }
        currentTetromino.x = BOARD_WIDTH / 2 - currentTetromino.shape[0].size() / 2;
        currentTetromino.y = 0;
    }

    void rotateTetromino() {
        vector<vector<char>> rotatedShape(currentTetromino.shape[0].size(), vector<char>(currentTetromino.shape.size()));
        for (int i = 0; i < currentTetromino.shape.size(); ++i) {
            for (int j = 0; j < currentTetromino.shape[i].size(); ++j) {
                rotatedShape[j][currentTetromino.shape.size() - 1 - i] = currentTetromino.shape[i][j];
            }
        }
        currentTetromino.shape = rotatedShape;
    }

    bool canMove(int dx, int dy) {
        for (int i = 0; i < currentTetromino.shape.size(); ++i) {
            for (int j = 0; j < currentTetromino.shape[i].size(); ++j) {
                if (currentTetromino.shape[i][j] == BLOCK) {
                    int newX = currentTetromino.x + j + dx;
                    int newY = currentTetromino.y + i + dy;
                    if (newX < 0 || newX >= BOARD_WIDTH || newY >= BOARD_HEIGHT || board[newY][newX] == BLOCK) {
                        return false;
                    }
                }
            }
        }
        return true;
    }

    void moveTetromino(int dx, int dy) {
        if (canMove(dx, dy)) {
            currentTetromino.x += dx;
            currentTetromino.y += dy;
        }
    }

    void placeTetromino() {
        for (int i = 0; i < currentTetromino.shape.size(); ++i) {
            for (int j = 0; j < currentTetromino.shape[i].size(); ++j) {
                if (currentTetromino.shape[i][j] == BLOCK) {
                    int x = currentTetromino.x + j;
                    int y = currentTetromino.y + i;
                    if (y >= 0) {
                        board[y][x] = BLOCK;
                    }
                }
            }
        }
    }

    void clearLines() {
        for (int i = BOARD_HEIGHT - 1; i >= 0; --i) {
            bool fullLine = true;
            for (int j = 0; j < BOARD_WIDTH; ++j) {
                if (board[i][j] != BLOCK) {
                    fullLine = false;
                    break;
                }
            }
            if (fullLine) {
                for (int k = i; k > 0; --k) {
                    for (int j = 0; j < BOARD_WIDTH; ++j) {
                        board[k][j] = board[k - 1][j];
                    }
                }
                for (int j = 0; j < BOARD_WIDTH; ++j) {
                    board[0][j] = EMPTY;
                }
                i++;  // 因为行已经被清除,所以需要重新检查这一行
            }
        }
    }

    void displayBoard() {
        for (int i = 0; i < BOARD_HEIGHT; ++i) {
            for (int j = 0; j < BOARD_WIDTH; ++j) {
                char block = board[i][j];
                for (int k = 0; k < currentTetromino.shape.size(); ++k) {
                    for (int l = 0; l < currentTetromino.shape[k].size(); ++l) {
                        if (currentTetromino.shape[k][l] == BLOCK && currentTetromino.y + k == i && currentTetromino.x + l == j) {
                            block = BLOCK;
                        }
                    }
                }
                cout << block << " ";
            }
            cout << endl;
        }
    }

    void playGame() {
        generateTetromino();
        while (!gameOver) {
            if (_kbhit()) {
                char key = _getch();
                switch (key) {
                    case 'a': moveTetromino(-1, 0); break;
                    case 'd': moveTetromino(1, 0); break;
                    case 's': moveTetromino(0, 1); break;
                    case 'w': rotateTetromino(); break;
                }
            }
            moveTetromino(0, 1);
            if (currentTetromino.y + currentTetromino.shape.size() > BOARD_HEIGHT) {
                placeTetromino();
                clearLines();
                generateTetromino();
                if (!canMove(0, 0)) {
                    gameOver = true;
                }
            }
            system("cls");  // 清屏
            displayBoard();
            this_thread::sleep_for(chrono::milliseconds(100));  // 控制游戏速度
        }
        cout << "游戏结束!\n";
    }

public:
    Tetris() {
        initializeBoard();
    }

    void startGame() {
        playGame();
    }
};

int main() {
    char choice;
    do {
        cout << "欢迎来到俄罗斯方块游戏!\n";
        cout << "按任意键开始游戏,或输入 q 退出:";
        choice = _getch();
        if (choice != 'q') {
            Tetris game;
            game.startGame();
        }
    } while (choice != 'q');

    cout << "谢谢游玩!再见!\n";
    return 0;
}

项目说明

  1. 初始化游戏板

    • initializeBoard 方法初始化游戏板。
    • generateTetromino 方法生成一个新的方块并设置其初始位置。
  2. 方块操作

    • rotateTetromino 方法旋转当前方块。
    • canMove 方法检查方块是否可以移动到指定位置。
    • moveTetromino 方法移动方块。
    • placeTetromino 方法将方块固定在游戏板上。
    • clearLines 方法检查并清除完整行。
  3. 显示游戏板

    • displayBoard 方法显示当前游戏板的状态。
  4. 主游戏循环

    • playGame 方法包含主游戏循环,处理用户输入、移动方块、更新游戏板和检查游戏结束条件。

原文地址:https://blog.csdn.net/weixin_42300449/article/details/143701134

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!