C语言实现俄罗斯方块游戏

1 前言

本文介绍的是我空闲时间用C语言写的一个俄罗斯方块游戏,整个程序只有一个文件,实现了基本的游戏功能,但还是有些缺陷,希望有心之士能够继续完善,感谢各位!

2 游戏截图

请注意!a、d、s、w都是小写

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3 源代码

/*
author: New_Teen
time: 2023.11.2 20:14 周四
IDE: visual studio 2019
俄罗斯方块
*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
#include <stdbool.h>
#include <conio.h>

#define BOARD_CUBE ' '
#define WIDTH 15
#define HEIGHT 15
#define FLUSH_RATE 200

char curr_cube;
int curr_square;
int curr_x, curr_y;
int score = 0;
int start_number = 0;
char board[HEIGHT][WIDTH];
int tmp[4][2];
int square[5][4][4] = { {{1,0,0,0},
                        {1,0,0,0},
                        {1,0,0,0},
                        {1,0,0,0}},

                        {{1,0,0,0},
                        {1,1,1,0},
                        {0,0,0,0},
                        {0,0,0,0}},

                        {{0,1,0,0},
                        {1,1,1,0},
                        {0,0,0,0},
                        {0,0,0,0}},

                        {{1,1,0,0},
                        {1,1,0,0},
                        {0,0,0,0},
                        {0,0,0,0}},

                        {{0,1,0,0},
                        {1,1,0,0},
                        {1,0,0,0},
                        {0,0,0,0}} };

void init_board(); //初始化游戏面板
void clear_board(); //清空控制台
void delay_board(); //延时
void print_board(); //打印游戏面板
void init_square(); //初始化方块
void drop_square(); //方块默认下落
void update_board(); //更新游戏面板
bool is_collision_left(); //检测方块左侧是否碰撞
bool is_collision_right(); //检测方块右侧是否碰撞
bool is_collision_bottom(); //检测方块下方是否碰撞
bool is_collsion_rotate(); //检测方块是否可以旋转
bool is_game_over(); //检测游戏是否结束
void rotate(); //旋转方块
void rush_board(); //消除成层方块(得分)
void start_game(); //游戏开始面板

int main() {
    srand((unsigned)time(NULL)); //根据程序执行时间产生随机数种子
    start_game();
    init_board();
    while (1) {
        init_square();
        if (is_game_over())
            break;
        for (;;) {
            if (!is_collision_bottom())
                drop_square();
            else
                break;

            if (_kbhit()) {
                char ch = _getch();
                if (ch == 'a' && !is_collision_left())
                    curr_x--;
                else if (ch == 'd' && !is_collision_right())
                    curr_x++;
                else if (ch == 's' && !is_collision_bottom())
                    curr_y++;
                else if (ch == 'w' && !is_collsion_rotate())
                    rotate();
            }

            update_board();
            rush_board();
            print_board();
            delay_board();
            clear_board();
        }
    }
    printf("Game over!!\nYour score is %d\n", score);
    return 0;
}

void init_board() {
    for (int i = 0; i < HEIGHT; ++i)
        for (int j = 0; j < WIDTH; ++j)
            board[i][j] = BOARD_CUBE;
}

void clear_board() {
    system("cls");
}

void delay_board() {
    Sleep(FLUSH_RATE);
}

void print_board() {
    for (int i = 0; i < HEIGHT; ++i) {
        for (int j = 0; j < WIDTH; ++j)
            putchar(board[i][j]);
        puts("#");
    }
    puts("################");
    printf("score: %d\n", score);
}

void init_square() {
    curr_cube = "ABCDEFGH"[rand()%8];
    start_number == 1 ? curr_square = 0 : curr_square = rand() % 5;
    curr_x = WIDTH / 2, curr_y = -4;
    int count = 0;
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < 4; ++j)
            if (square[curr_square][i][j]) {
                tmp[count][0] = curr_y + i;
                tmp[count][1] = curr_x + j;
                count++;
            }
}

void drop_square() {
    curr_y++;
}

void update_board() {
    //清除之前位置的方块
    int row, col;
    for (int i = 0; i < 4; ++i) {
        row = tmp[i][0];
        col = tmp[i][1];
        if (row >= 0 && row < HEIGHT
            && col >= 0 && col < WIDTH)
            board[row][col] = BOARD_CUBE;
    }

    int count = 0;
    //画出现在位置的方块,并更新tmp
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            row = curr_y + i;
            col = curr_x + j;
            if (square[curr_square][i][j]) {
                tmp[count][0] = row;
                tmp[count][1] = col;
                count++;
                if (row >= 0 && row < HEIGHT
                    && col >= 0 && col < WIDTH)
                    board[row][col] = curr_cube;
            }
        }
    }
}

bool is_collision_left() {
    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 4; j++)
            if (square[curr_square][i][j]) {
                //检测方块与面板左墙壁的碰撞
                if (curr_x + j <= 0)
                    return true;
                //检测方块与左侧方块的碰撞
                if (j == 0) {
                    if (board[curr_y + i][curr_x + j - 1] != BOARD_CUBE)
                        return true;
                }
                else {
                    if (!square[curr_square][i][j - 1] && 
                        board[curr_y + i][curr_x + j - 1] != BOARD_CUBE)
                        return true;
                }
            }
    return false;
}

bool is_collision_right() {
    for (int i = 0; i < 4; i++)
        for (int j = 0; j < 4; j++)
            if (square[curr_square][i][j]) {
                //检测方块与面板右墙壁的碰撞
                if (curr_x + j >= WIDTH-1)
                        return true;
                //检测方块与右侧方块的碰撞
                if (j == 3) {
                    if (board[curr_y + i][curr_x + j + 1] != BOARD_CUBE)
                        return true;
                }
                else {
                    if (!square[curr_square][i][j + 1] &&
                        board[curr_y + i][curr_x + j + 1] != BOARD_CUBE)
                        return true;
                }
            }
    return false;
}

bool is_collision_bottom() {
    //找到当前方块的最下层
    int low = -99;
    for (int i = 0; i < 4; i++) 
        for (int j = 0; j < 4; j++)
            if (square[curr_square][i][j] == 1)
                low = i;
    //如果达到面板最底部
    if(curr_y + low >= HEIGHT-1)
        return true;

    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            //考虑方块下面有方块的情况
            if (i < 3) {
                if (square[curr_square][i][j] && !square[curr_square][i + 1][j]
                    && (curr_y + i + 1 >=0) && board[curr_y + i + 1][curr_x + j] != BOARD_CUBE)
                    return true;
            }
            else {
                if (square[curr_square][i][j] && (curr_y + i + 1 >= 0) 
                    && board[curr_y + i + 1][curr_x + j] != BOARD_CUBE)
                    return true;
            }
        }
    }
    return false;
}

bool is_collsion_rotate() {
    int middle[4][4] = { 0 };
    //暂存旋转后方块
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < 4; ++j)
            middle[i][j] = square[curr_square][j][i];
    //旋转后方块是否与面板已有方块重叠
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < 4; ++j)
            if (!square[curr_square][i][j] && middle[i][j]
                && board[curr_y + i][curr_x + j] != BOARD_CUBE)
                return true;
    return false;
}

void rotate() {
    //清除之前位置的方块
    int row, col;
    for (int i = 0; i < 4; ++i) {
        row = tmp[i][0];
        col = tmp[i][1];
        if (row >= 0 && row < HEIGHT
            && col >= 0 && col < WIDTH)
            board[row][col] = BOARD_CUBE;
    }

    //旋转方块
    int rotate_tmp[4][4] = { 0 };
    memcpy(rotate_tmp, square[curr_square], 16 * sizeof(int));
    for (int i = 0; i < 4; ++i)
        for (int j = 0; j < 4; ++j)
            square[curr_square][i][j] = rotate_tmp[j][i];
    
    int count = 0;
    //画出现在位置的方块,并更新tmp
    for (int i = 0; i < 4; ++i) {
        for (int j = 0; j < 4; ++j) {
            row = curr_y + i;
            col = curr_x + j;
            if (square[curr_square][i][j]) {
                tmp[count][0] = row;
                tmp[count][1] = col;
                count++;
                if (row >= 0 && row < HEIGHT
                    && col >= 0 && col < WIDTH)
                    board[row][col] = curr_cube;
            }
        }
    }
}

bool is_game_over() {
   for (int j = 0; j < WIDTH; ++j)
       if (board[0][j] != BOARD_CUBE)
           return true;          
    return false;
}

void rush_board() {
    int count, floor;
    floor = 0;
    for (int i = HEIGHT - 1; i >= 0; --i) {
        count = 0;
        for (int j = 0; j < WIDTH; ++j)
            if (board[i][j] != BOARD_CUBE)
                count++;
        if (count == WIDTH)
            floor++;
        else
            break;
    }

    //得到floor后,面板下移floor层
    if (floor != 0) {
        for (int i = HEIGHT - 1 - floor; i >= 0; --i)
            for (int j = 0; j < WIDTH; ++j)
                board[i + floor][j] = board[i][j];
        score += floor;
    }
}

void start_game() {
    printf("----------------俄罗斯方块----------------\n");
    printf("\n游戏规则:a:左移  d:右移  s:下移  w:旋转\n");
    printf("\n输入1:全程长条方块     输入2:经典随机方块\n");
    while (start_number != 1 && start_number != 2) {\
        printf("\n请输入序号(1或者2): ");
        scanf_s("%d", &start_number);
    }
    clear_board();
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

New_Teen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值