C语言编程题实现一个简易的俄罗斯方块游戏

C语言编程题,实现一个简易的俄罗斯方块游戏,实现一个简易的俄罗斯方块游戏可以通过在控制台中使用字符绘制图形,同时用键盘控制方块的移动和旋转。俄罗斯方块是一个经典的益智游戏,其核心玩法是控制不断下落的方块,使其在到达底部或与其他方块碰撞时填满整行,消除并获得分数。

1、地图和方块

游戏区域由一个 20x10 的二维数组表示,其中 0 表示空白,1 表示已占用。将方块定义为一个 4x4 的小方阵,这样便于旋转操作。设计多种形状的方块,并用数据结构表示每个方块的形状和位置。使用 map[HEIGHT][WIDTH] 来表示游戏的20x10地图。tetrominoes 数组存储了7种不同形状的方块,每个方块都是4x4的阵列。

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>

// 地图大小
#define WIDTH 10
#define HEIGHT 20

// 方块定义(4x4的阵列表示7种不同的方块)
int tetrominoes[7][4][4] = {
    // O 形方块
    {{1, 1, 0, 0},
     {1, 1, 0, 0},
     {0, 0, 0, 0},
     {0, 0, 0, 0}},
     
    // I 形方块
    {{0, 1, 0, 0},
     {0, 1, 0, 0},
     {0, 1, 0, 0},
     {0, 1, 0, 0}},
     
    // S 形方块
    {{0, 1, 1, 0},
     {1, 1, 0, 0},
     {0, 0, 0, 0},
     {0, 0, 0, 0}},
     
    // Z 形方块
    {{1, 1, 0, 0},
     {0, 1, 1, 0},
     {0, 0, 0, 0},
     {0, 0, 0, 0}},
     
    // L 形方块
    {{1, 0, 0, 0},
     {1, 0, 0, 0},
     {1, 1, 0, 0},
     {0, 0, 0, 0}},
     
    // J 形方块
    {{0, 0, 1, 0},
     {0, 0, 1, 0},
     {0, 1, 1, 0},
     {0, 0, 0, 0}},
     
    // T 形方块
    {{0, 1, 0, 0},
     {1, 1, 1, 0},
     {0, 0, 0, 0},
     {0, 0, 0, 0}}
};

// 地图大小
#define WIDTH 10
#define HEIGHT 20

// 地图
int map[HEIGHT][WIDTH] = {0};

// 当前方块的位置
int current_tetromino[4][4];
int current_x, current_y;
int tetromino_index;

int main() {
  printf("Hello, World!");
  return 0;
}

2、方块生成与移动

通过键盘控制方块的左右移动、下落和旋转。spawn_tetromino() 随机生成一个方块。can_move() 用来检查方块能否向指定方向移动。rotate_tetromino() 实现方块的旋转。

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>

// 清屏函数
void clear_screen() {
    system("cls");
}

// 随机生成一个方块
void spawn_tetromino() {
    tetromino_index = rand() % 7;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            current_tetromino[i][j] = tetrominoes[tetromino_index][i][j];
        }
    }
    current_x = WIDTH / 2 - 2;
    current_y = 0;
}

// 检查方块是否能移动
int can_move(int dx, int dy) {
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (current_tetromino[i][j]) {
                int new_x = current_x + j + dx;
                int new_y = current_y + i + dy;
                if (new_x < 0 || new_x >= WIDTH || new_y >= HEIGHT || map[new_y][new_x]) {
                    return 0;
                }
            }
        }
    }
    return 1;
}

// 旋转方块
void rotate_tetromino() {
    int temp[4][4];
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            temp[i][j] = current_tetromino[3 - j][i];
        }
    }
    // 检查是否能旋转
    int old_x = current_x, old_y = current_y;
    if (can_move(0, 0)) {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                current_tetromino[i][j] = temp[i][j];
            }
        }
    }
}

int main() {
  printf("Hello, World!");
  return 0;
}

3、方块固定与行消除

当方块无法下落时,使用 fix_tetromino() 将方块固定在地图上。clear_lines() 检查地图是否有完整的行,如果有就清除该行并将上方的行下移。

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>


// 固定方块到地图
void fix_tetromino() {
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (current_tetromino[i][j]) {
                map[current_y + i][current_x + j] = 1;
            }
        }
    }
}

// 检查并清除完整的行
void clear_lines() {
    for (int i = 0; i < HEIGHT; i++) {
        int full_line = 1;
        for (int j = 0; j < WIDTH; j++) {
            if (map[i][j] == 0) {
                full_line = 0;
                break;
            }
        }
        if (full_line) {
            for (int k = i; k > 0; k--) {
                for (int j = 0; j < WIDTH; j++) {
                    map[k][j] = map[k - 1][j];
                }
            }
            for (int j = 0; j < WIDTH; j++) {
                map[0][j] = 0;
            }
        }
    }
}

int main() {
  printf("Hello, World!");
  return 0;
}

4、绘制地图

draw() 函数负责在控制台上绘制当前地图和正在下落的方块。

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>


// 游戏逻辑循环
void game_loop() {
    spawn_tetromino();
    while (1) {
        if (_kbhit()) {
            switch (_getch()) {
                case 'a':
                    if (can_move(-1, 0)) current_x--;
                    break;
                case 'd':
                    if (can_move(1, 0)) current_x++;
                    break;
                case 's':
                    if (can_move(0, 1)) current_y++;
                    break;
                case 'w':
                    rotate_tetromino();
                    break;
            }
        }

        if (can_move(0, 1)) {
            current_y++;
        } else {
            fix_tetromino();
            clear_lines();
            spawn_tetromino();
            if (!can_move(0, 0)) {
                printf("Game Over!\n");
                break;
            }
        }

        draw();
        Sleep(300);
    }
}

int main() {
  printf("Hello, World!");
  return 0;
}

5、控制与游戏循环

使用 _kbhit()_getch() 获取玩家输入,支持左右移动 (a, d),快速下落 (s),以及旋转方块 (w)。游戏循环中持续进行方块的下落、绘制和行检测,直到游戏结束。

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>

// 游戏逻辑循环
void game_loop() {
    spawn_tetromino();
    while (1) {
        if (_kbhit()) {
            switch (_getch()) {
                case 'a':
                    if (can_move(-1, 0)) current_x--;
                    break;
                case 'd':
                    if (can_move(1, 0)) current_x++;
                    break;
                case 's':
                    if (can_move(0, 1)) current_y++;
                    break;
                case 'w':
                    rotate_tetromino();
                    break;
            }
        }

        if (can_move(0, 1)) {
            current_y++;
        } else {
            fix_tetromino();
            clear_lines();
            spawn_tetromino();
            if (!can_move(0, 0)) {
                printf("Game Over!\n");
                break;
            }
        }

        draw();
        Sleep(300);
    }
}

int main() {
  printf("Hello, World!");
  return 0;
}

6、完整代码

一个简易的俄罗斯方块游戏,可以根据自己的需求进行扩展和完善。

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>

// 地图大小
#define WIDTH 10
#define HEIGHT 20

// 方块定义(4x4的阵列表示7种不同的方块)
int tetrominoes[7][4][4] = {
    // O 形方块
    {{1, 1, 0, 0},
     {1, 1, 0, 0},
     {0, 0, 0, 0},
     {0, 0, 0, 0}},
     
    // I 形方块
    {{0, 1, 0, 0},
     {0, 1, 0, 0},
     {0, 1, 0, 0},
     {0, 1, 0, 0}},
     
    // S 形方块
    {{0, 1, 1, 0},
     {1, 1, 0, 0},
     {0, 0, 0, 0},
     {0, 0, 0, 0}},
     
    // Z 形方块
    {{1, 1, 0, 0},
     {0, 1, 1, 0},
     {0, 0, 0, 0},
     {0, 0, 0, 0}},
     
    // L 形方块
    {{1, 0, 0, 0},
     {1, 0, 0, 0},
     {1, 1, 0, 0},
     {0, 0, 0, 0}},
     
    // J 形方块
    {{0, 0, 1, 0},
     {0, 0, 1, 0},
     {0, 1, 1, 0},
     {0, 0, 0, 0}},
     
    // T 形方块
    {{0, 1, 0, 0},
     {1, 1, 1, 0},
     {0, 0, 0, 0},
     {0, 0, 0, 0}}
};

// 地图
int map[HEIGHT][WIDTH] = {0};

// 当前方块的位置
int current_tetromino[4][4];
int current_x, current_y;
int tetromino_index;

// 清屏函数
void clear_screen() {
    system("cls");
}

// 随机生成一个方块
void spawn_tetromino() {
    tetromino_index = rand() % 7;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            current_tetromino[i][j] = tetrominoes[tetromino_index][i][j];
        }
    }
    current_x = WIDTH / 2 - 2;
    current_y = 0;
}

// 检查方块是否能移动
int can_move(int dx, int dy) {
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (current_tetromino[i][j]) {
                int new_x = current_x + j + dx;
                int new_y = current_y + i + dy;
                if (new_x < 0 || new_x >= WIDTH || new_y >= HEIGHT || map[new_y][new_x]) {
                    return 0;
                }
            }
        }
    }
    return 1;
}

// 旋转方块
void rotate_tetromino() {
    int temp[4][4];
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            temp[i][j] = current_tetromino[3 - j][i];
        }
    }
    // 检查是否能旋转
    int old_x = current_x, old_y = current_y;
    if (can_move(0, 0)) {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                current_tetromino[i][j] = temp[i][j];
            }
        }
    }
}

// 固定方块到地图
void fix_tetromino() {
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (current_tetromino[i][j]) {
                map[current_y + i][current_x + j] = 1;
            }
        }
    }
}

// 检查并清除完整的行
void clear_lines() {
    for (int i = 0; i < HEIGHT; i++) {
        int full_line = 1;
        for (int j = 0; j < WIDTH; j++) {
            if (map[i][j] == 0) {
                full_line = 0;
                break;
            }
        }
        if (full_line) {
            for (int k = i; k > 0; k--) {
                for (int j = 0; j < WIDTH; j++) {
                    map[k][j] = map[k - 1][j];
                }
            }
            for (int j = 0; j < WIDTH; j++) {
                map[0][j] = 0;
            }
        }
    }
}

// 打印地图和当前方块
void draw() {
    clear_screen();
    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < WIDTH; j++) {
            if (map[i][j]) {
                printf("#");
            } else {
                int is_part_of_tetromino = 0;
                for (int m = 0; m < 4; m++) {
                    for (int n = 0; n < 4; n++) {
                        if (current_tetromino[m][n] && current_y + m == i && current_x + n == j) {
                            is_part_of_tetromino = 1;
                        }
                    }
                }
                if (is_part_of_tetromino) {
                    printf("O");
                } else {
                    printf(" ");
                }
            }
        }
        printf("\n");
    }
}

// 游戏逻辑循环
void game_loop() {
    spawn_tetromino();
    while (1) {
        if (_kbhit()) {
            switch (_getch()) {
                case 'a':
                    if (can_move(-1, 0)) current_x--;
                    break;
                case 'd':
                    if (can_move(1, 0)) current_x++;
                    break;
                case 's':
                    if (can_move(0, 1)) current_y++;
                    break;
                case 'w':
                    rotate_tetromino();
                    break;
            }
        }

        if (can_move(0, 1)) {
            current_y++;
        } else {
            fix_tetromino();
            clear_lines();
            spawn_tetromino();
            if (!can_move(0, 0)) {
                printf("Game Over!\n");
                break;
            }
        }

        draw();
        Sleep(300);
    }
}

int main() {
    srand(time(0));
    game_loop();
    return 0;
}

推荐阅读
cjavapy编程之路首页