×

C语言编写俄罗斯方块小游戏

hqy hqy 发表于2025-10-20 20:18:34 浏览7 评论0

抢沙发发表评论

效果提前看


图片
简单说明


这个用C语言和EasyX图形库编写的俄罗斯方块游戏,是学习编程的绝佳练手项目!游戏规则很简单:控制不同形状的方块下落,让它们在底部完美拼接。当填满一整行时,这行就会消失并得分。你可以用方向键移动和旋转方块,空格键让方块快速落底。通过这个项目,你不仅能理解游戏逻辑、图形绘制、键盘交互等编程核心概念,还能亲手打造属于自己的经典游戏,体验从代码到成品的成就感!

源码分享


#include <graphics.h>
#include <conio.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>

// 定义常量
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
#define GRID_SIZE 25
#define GAME_LEFT 50
#define GAME_TOP 60
#define GAME_COLS 10
#define GAME_ROWS 20
#define GAME_WIDTH 500
#define GAME_HEIGHT 500

#define PANEL_LEFT 570
#define PANEL_TOP 60
#define PANEL_WIDTH 200
#define PANEL_HEIGHT 500

#define PREVIEW_LEFT 580
#define PREVIEW_TOP 70
#define PREVIEW_SIZE 100

// 颜色定义 - 简化版
#define BG_COLOR RGB(50, 50, 50)
#define GRID_COLOR RGB(100, 100, 100)
#define BORDER_COLOR RGB(255, 255, 255)
#define TITLE_COLOR RGB(255, 215, 0)  // 只保留标题为黄色
#define WHITE_COLOR RGB(255, 255, 255) // 所有其他元素使用白色
#define PANEL_BG RGB(60, 60, 60)
#define NOTICE_BG RGB(40, 40, 40)
#define OVERLAY_COLOR RGB(0, 0, 0)

// 方块颜色全部改为白色
#define COLOR_WHITE RGB(255, 255, 255)

// 方块形状定义
int shapes[7][4][4][4] = {
    // I 型
    {
        {{0,0,0,0}, {1,1,1,1}, {0,0,0,0}, {0,0,0,0}},
        {{0,0,1,0}, {0,0,1,0}, {0,0,1,0}, {0,0,1,0}},
        {{0,0,0,0}, {0,0,0,0}, {1,1,1,1}, {0,0,0,0}},
        {{0,1,0,0}, {0,1,0,0}, {0,1,0,0}, {0,1,0,0}}
    },
    // O 型
    {
        {{0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {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,1,1,0}, {0,1,1,0}, {0,0,0,0}},
        {{0,0,0,0}, {0,1,1,0}, {0,1,1,0}, {0,0,0,0}}
    },
    // T 型
    {
        {{0,0,0,0}, {0,1,0,0}, {1,1,1,0}, {0,0,0,0}},
        {{0,0,0,0}, {0,1,0,0}, {0,1,1,0}, {0,1,0,0}},
        {{0,0,0,0}, {0,0,0,0}, {1,1,1,0}, {0,1,0,0}},
        {{0,0,0,0}, {0,1,0,0}, {1,1,0,0}, {0,1,0,0}}
    },
    // L 型
    {
        {{0,0,0,0}, {0,0,1,0}, {1,1,1,0}, {0,0,0,0}},
        {{0,0,0,0}, {0,1,0,0}, {0,1,0,0}, {0,1,1,0}},
        {{0,0,0,0}, {0,0,0,0}, {1,1,1,0}, {1,0,0,0}},
        {{0,0,0,0}, {1,1,0,0}, {0,1,0,0}, {0,1,0,0}}
    },
    // J 型
    {
        {{0,0,0,0}, {1,0,0,0}, {1,1,1,0}, {0,0,0,0}},
        {{0,0,0,0}, {0,1,1,0}, {0,1,0,0}, {0,1,0,0}},
        {{0,0,0,0}, {0,0,0,0}, {1,1,1,0}, {0,0,1,0}},
        {{0,0,0,0}, {0,1,0,0}, {0,1,0,0}, {1,1,0,0}}
    },
    // S 型
    {
        {{0,0,0,0}, {0,1,1,0}, {1,1,0,0}, {0,0,0,0}},
        {{0,0,0,0}, {0,1,0,0}, {0,1,1,0}, {0,0,1,0}},
        {{0,0,0,0}, {0,0,0,0}, {0,1,1,0}, {1,1,0,0}},
        {{0,0,0,0}, {1,0,0,0}, {1,1,0,0}, {0,1,0,0}}
    },
    // Z 型
    {
        {{0,0,0,0}, {1,1,0,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,0,0,0}, {1,1,0,0}, {0,1,1,0}},
        {{0,0,0,0}, {0,1,0,0}, {1,1,0,0}, {1,0,0,0}}
    }
};

// 方块颜色数组 - 全部使用白色
COLORREF shapeColors[7] = { COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE, COLOR_WHITE };

// 游戏状态结构体
struct GameState {
    int board[GAME_ROWS][GAME_COLS];
    int currentShape;
    int nextShape;
    int rotation;
    int posX, posY;
    int score;
    int lines;
    int level;
    int gameOver;
    int paused;
    int speed;
    clock_t lastMoveTime;
    char notice[100];
    int showNotice;
    clock_t noticeTime;
    int highScore;
    int flashState;
    clock_t flashTime;
} game;

// 函数声明
void initGame();
void drawGame();
void drawGrid();
void drawBlock(int x, int y);
void drawCurrentShape();
void drawNextShape();
void drawInfoPanel();
void drawTitle();
void drawControls();
void drawPanelNotice();
void drawGameOverOverlay();
int checkCollision();
void placeShape();
void clearLines();
void rotateShape();
void moveShape(int dx, int dy);
void dropShape();
void handleInput();
void updateGame();
void setNotice(const char* text);
void updateHighScore();
void drawInfo();

int main() {
    initgraph(WINDOW_WIDTH, WINDOW_HEIGHT);
    srand((unsigned)time(NULL));
    initGame();
    setbkmode(TRANSPARENT);
    BeginBatchDraw();

    while (true) {
        handleInput();
        updateGame();
        drawGame();
        Sleep(10);
    }

    EndBatchDraw();
    closegraph();
    return 0;
}

// 初始化游戏状态
void initGame() {
    for (int i = 0; i < GAME_ROWS; i++) {
        for (int j = 0; j < GAME_COLS; j++) {
            game.board[i][j] = -1;
        }
    }

    game.currentShape = rand() % 7;
    game.nextShape = rand() % 7;
    game.rotation = 0;
    game.posX = GAME_COLS / 2 - 2;
    game.posY = 0;
    game.score = 0;
    game.lines = 0;
    game.level = 1;
    game.gameOver = 0;
    game.paused = 0;
    game.speed = 500;
    game.lastMoveTime = clock();
    game.showNotice = 0;
    strcpy_s(game.notice, sizeof(game.notice), "");
    game.highScore = 0;
    game.flashState = 0;
    game.flashTime = clock();
}

// 更新最高分
void updateHighScore() {
    if (game.score > game.highScore) {
        game.highScore = game.score;
    }
}

// 设置提示信息
void setNotice(const char* text) {
    strcpy_s(game.notice, sizeof(game.notice), text);
    game.showNotice = 1;
    game.noticeTime = clock();
}

// 绘制游戏内容
void drawGame() {
    cleardevice();
    setfillcolor(BG_COLOR);
    solidrectangle(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);

    drawTitle();
    drawGrid();
    drawCurrentShape();

    if (game.gameOver) {
        drawGameOverOverlay();
    }

    drawInfoPanel();
    FlushBatchDraw();
}

// 绘制游戏结束遮罩和闪烁文字
void drawGameOverOverlay() {
    // 计算游戏网格在游戏区内的居中位置
    int gridWidth = GAME_COLS * GRID_SIZE;
    int gridHeight = GAME_ROWS * GRID_SIZE;
    int gridLeft = GAME_LEFT + (GAME_WIDTH - gridWidth) / 2;
    int gridTop = GAME_TOP + (GAME_HEIGHT - gridHeight) / 2;

    setfillcolor(OVERLAY_COLOR);
    solidrectangle(gridLeft, gridTop,
        gridLeft + gridWidth,
        gridTop + gridHeight);

    if (clock() - game.flashTime > 500) {
        game.flashState = !game.flashState;
        game.flashTime = clock();
    }

    COLORREF flashColor;
    if (game.flashState) {
        flashColor = RGB(255, 215, 0);  // 闪烁时使用黄色
    }
    else {
        flashColor = WHITE_COLOR;       // 其他时间使用白色
    }

    settextcolor(flashColor);
    settextstyle(22, 0, _T("宋体"));
    outtextxy(gridLeft, gridTop + gridHeight / 2 - 30,
        _T("游戏结束!按 R 重新开始"));
}

// 绘制面板提示区(位于右侧信息面板内)
void drawPanelNotice() {
    int noticeTop = PREVIEW_TOP + PREVIEW_SIZE + 140;

    // 绘制提示区背景
    setfillcolor(NOTICE_BG);
    solidrectangle(PREVIEW_LEFT, noticeTop, PREVIEW_LEFT + 180, noticeTop + 30);

    // 如果游戏暂停,显示暂停信息
    if (game.paused) {
        settextcolor(WHITE_COLOR);
        settextstyle(16, 0, _T("宋体"));
        outtextxy(PREVIEW_LEFT + 5, noticeTop + 7, _T("游戏已暂停"));
    }

    // 显示其他提示信息
    if (game.showNotice && !game.gameOver) {
        settextcolor(WHITE_COLOR);
        settextstyle(16, 0, _T("宋体"));
        outtextxy(PREVIEW_LEFT + 5, noticeTop + 7, game.notice);

        if (clock() - game.noticeTime > 3000) {
            game.showNotice = 0;
        }
    }
}

// 绘制统一信息面板
void drawInfoPanel() {
    // 绘制信息面板背景
    setfillcolor(PANEL_BG);
    solidrectangle(PANEL_LEFT, PANEL_TOP, PANEL_LEFT + PANEL_WIDTH, PANEL_TOP + PANEL_HEIGHT);

    // 绘制信息面板边框
    setlinecolor(BORDER_COLOR);
    rectangle(PANEL_LEFT, PANEL_TOP, PANEL_LEFT + PANEL_WIDTH, PANEL_TOP + PANEL_HEIGHT);

    // 绘制各个子区域
    drawNextShape();
    drawInfo();
    drawPanelNotice();
    drawControls();
}

// 绘制网格
void drawGrid() {
    // 计算游戏网格在游戏区内的居中位置
    int gridWidth = GAME_COLS * GRID_SIZE;
    int gridHeight = GAME_ROWS * GRID_SIZE;
    int gridLeft = GAME_LEFT + (GAME_WIDTH - gridWidth) / 2;
    int gridTop = GAME_TOP + (GAME_HEIGHT - gridHeight) / 2;

    // 绘制游戏区域边框
    setlinecolor(BORDER_COLOR);
    rectangle(GAME_LEFT, GAME_TOP, GAME_LEFT + GAME_WIDTH, GAME_TOP + GAME_HEIGHT);

    // 绘制网格边框
    rectangle(gridLeft - 2, gridTop - 2,
        gridLeft + gridWidth + 2,
        gridTop + gridHeight + 2);

    // 绘制网格线
    setlinecolor(GRID_COLOR);
    for (int i = 0; i <= GAME_COLS; i++) {
        line(gridLeft + i * GRID_SIZE, gridTop,
            gridLeft + i * GRID_SIZE, gridTop + gridHeight);
    }
    for (int i = 0; i <= GAME_ROWS; i++) {
        line(gridLeft, gridTop + i * GRID_SIZE,
            gridLeft + gridWidth, gridTop + i * GRID_SIZE);
    }

    // 绘制已放置的方块
    for (int i = 0; i < GAME_ROWS; i++) {
        for (int j = 0; j < GAME_COLS; j++) {
            if (game.board[i][j] != -1) {
                int x = gridLeft + j * GRID_SIZE;
                int y = gridTop + i * GRID_SIZE;
                setfillcolor(WHITE_COLOR);
                solidrectangle(x + 1, y + 1, x + GRID_SIZE - 1, y + GRID_SIZE - 1);
            }
        }
    }
}

// 绘制单个方块(用于当前下落方块)- 简化为只使用白色
void drawBlock(int x, int y) {
    // 计算游戏网格在游戏区内的居中位置
    int gridWidth = GAME_COLS * GRID_SIZE;
    int gridHeight = GAME_ROWS * GRID_SIZE;
    int gridLeft = GAME_LEFT + (GAME_WIDTH - gridWidth) / 2;
    int gridTop = GAME_TOP + (GAME_HEIGHT - gridHeight) / 2;

    setfillcolor(WHITE_COLOR);
    solidrectangle(gridLeft + x * GRID_SIZE + 1,
        gridTop + y * GRID_SIZE + 1,
        gridLeft + (x + 1) * GRID_SIZE - 1,
        gridTop + (y + 1) * GRID_SIZE - 1);
}

// 绘制当前方块
void drawCurrentShape() {
    if (game.gameOver) return;

    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (shapes[game.currentShape][game.rotation][i][j]) {
                int x = game.posX + j;
                int y = game.posY + i;
                if (y >= 0) {
                    drawBlock(x, y);
                }
            }
        }
    }
}

// 绘制下一个方块
void drawNextShape() {
    // 绘制预览区域背景
    setfillcolor(PANEL_BG);
    solidrectangle(PREVIEW_LEFT, PREVIEW_TOP,
        PREVIEW_LEFT + PREVIEW_SIZE,
        PREVIEW_TOP + PREVIEW_SIZE);

    // 绘制预览区域边框
    setlinecolor(BORDER_COLOR);
    rectangle(PREVIEW_LEFT - 1, PREVIEW_TOP - 1,
        PREVIEW_LEFT + PREVIEW_SIZE + 1,
        PREVIEW_TOP + PREVIEW_SIZE + 1);

    // 计算预览方块在预览区内的居中位置
    int blockSize = PREVIEW_SIZE / 4;
    int previewCenterX = PREVIEW_LEFT + PREVIEW_SIZE / 2;
    int previewCenterY = PREVIEW_TOP + PREVIEW_SIZE / 2;

    // 绘制预览区域文字
    settextcolor(WHITE_COLOR);
    settextstyle(20, 0, _T("宋体"));
    outtextxy(PREVIEW_LEFT, PREVIEW_TOP - 30, _T("下一个:"));

    // 绘制下一个方块(居中显示)
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (shapes[game.nextShape][0][i][j]) {
                setfillcolor(WHITE_COLOR);
                int x = previewCenterX - 2 * blockSize + j * blockSize;
                int y = previewCenterY - 2 * blockSize + i * blockSize;
                solidrectangle(x + 1, y + 1, x + blockSize - 1, y + blockSize - 1);
            }
        }
    }
}

// 绘制信息区域
void drawInfo() {
    int infoTop = PREVIEW_TOP + PREVIEW_SIZE + 20;
    updateHighScore();

    settextstyle(20, 0, _T("宋体"));
    settextcolor(WHITE_COLOR); // 所有信息文字使用白色

    char scoreText[50], linesText[50], levelText[50], highScoreText[50];
    sprintf_s(scoreText, sizeof(scoreText), "分数:%d", game.score);
    sprintf_s(linesText, sizeof(linesText), "行数:%d", game.lines);
    sprintf_s(levelText, sizeof(levelText), "等级:%d", game.level);
    sprintf_s(highScoreText, sizeof(highScoreText), "历史最高分:%d", game.highScore);

    // 左对齐显示信息,行间距30px
    outtextxy(PREVIEW_LEFT, infoTop, scoreText);
    outtextxy(PREVIEW_LEFT, infoTop + 30, linesText);
    outtextxy(PREVIEW_LEFT, infoTop + 60, levelText);
    outtextxy(PREVIEW_LEFT, infoTop + 90, highScoreText);
}

// 绘制操作说明
void drawControls() {
    int controlsTop = PREVIEW_TOP + PREVIEW_SIZE + 180;

    settextcolor(WHITE_COLOR);
    settextstyle(18, 0, _T("宋体"));

    int textLeft = PREVIEW_LEFT;
    int lineHeight = 20;

    // 所有操作说明使用白色
    outtextxy(textLeft, controlsTop, _T("←→ 移动方块"));
    outtextxy(textLeft, controlsTop + lineHeight, _T("↑ 旋转方块"));
    outtextxy(textLeft, controlsTop + lineHeight * 2, _T("↓ 加速下落"));
    outtextxy(textLeft, controlsTop + lineHeight * 3, _T("空格 直接落底"));
    outtextxy(textLeft, controlsTop + lineHeight * 4, _T("P 暂停/继续"));
    outtextxy(textLeft, controlsTop + lineHeight * 5, _T("R 重新开始"));
}

// 绘制标题(保持黄色)
void drawTitle() {
    settextcolor(TITLE_COLOR);
    settextstyle(36, 0, _T("宋体"));
    outtextxy(300, 9, _T("俄罗斯方块"));
}

// 检查碰撞
int checkCollision() {
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (shapes[game.currentShape][game.rotation][i][j]) {
                int x = game.posX + j;
                int y = game.posY + i;

                if (x < 0 || x >= GAME_COLS || y >= GAME_ROWS) {
                    return 1;
                }

                if (y >= 0 && game.board[y][x] != -1) {
                    return 1;
                }
            }
        }
    }
    return 0;
}

// 放置方块
void placeShape() {
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (shapes[game.currentShape][game.rotation][i][j]) {
                int x = game.posX + j;
                int y = game.posY + i;
                if (y >= 0) {
                    game.board[y][x] = game.currentShape;
                }
            }
        }
    }
}

// 消除完整的行
void clearLines() {
    int linesCleared = 0;
    int oldLevel = game.level;

    for (int i = GAME_ROWS - 1; i >= 0; i--) {
        int full = 1;
        for (int j = 0; j < GAME_COLS; j++) {
            if (game.board[i][j] == -1) {
                full = 0;
                break;
            }
        }

        if (full) {
            linesCleared++;
            for (int k = i; k > 0; k--) {
                for (int j = 0; j < GAME_COLS; j++) {
                    game.board[k][j] = game.board[k - 1][j];
                }
            }
            for (int j = 0; j < GAME_COLS; j++) {
                game.board[0][j] = -1;
            }
            i++;
        }
    }

    if (linesCleared > 0) {
        game.lines += linesCleared;
        game.score += linesCleared * 100 * linesCleared;

        game.level = game.lines / 10 + 1;
        game.speed = 500 - (game.level - 1) * 50;
        if (game.speed < 100) game.speed = 100;

        if (game.level > oldLevel) {
            char levelUpText[50];
            sprintf_s(levelUpText, sizeof(levelUpText), "升级到第 %d 级!", game.level);
            setNotice(levelUpText);
        }
    }
}

// 旋转方块
void rotateShape() {
    int oldRotation = game.rotation;
    game.rotation = (game.rotation + 1) % 4;

    if (checkCollision()) {
        game.rotation = oldRotation;
    }
}

// 移动方块
void moveShape(int dx, int dy) {
    game.posX += dx;
    game.posY += dy;

    if (checkCollision()) {
        game.posX -= dx;
        game.posY -= dy;

        if (dy > 0) {
            placeShape();
            clearLines();

            game.currentShape = game.nextShape;
            game.nextShape = rand() % 7;
            game.rotation = 0;
            game.posX = GAME_COLS / 2 - 2;
            game.posY = 0;

            if (checkCollision()) {
                game.gameOver = 1;
                updateHighScore();
            }
        }
    }
}

// 快速下落
void dropShape() {
    while (checkCollision() == 0) {
        game.posY++;
    }
    game.posY--;
    moveShape(0, 1);
}

// 处理输入
void handleInput() {
    if (_kbhit()) {
        int key = _getch();

        if (key == 0 || key == 224) {
            key = _getch();

            if (!game.paused && !game.gameOver) {
                switch (key) {
                case 75: moveShape(-1, 0); break;
                case 77: moveShape(1, 0); break;
                case 80: moveShape(0, 1); break;
                case 72: rotateShape(); break;
                }
            }
        }
        else {
            if (!game.paused && !game.gameOver) {
                switch (key) {
                case 'a': case 'A': moveShape(-1, 0); break;
                case 'd': case 'D': moveShape(1, 0); break;
                case 's': case 'S': moveShape(0, 1); break;
                case 'w': case 'W': rotateShape(); break;
                case 32: dropShape(); break;
                }
            }
            // 绘制提示区背景

            switch (key) {
            case 'p': case 'P':
                game.paused = !game.paused;
                if (game.paused) 
                {

                    setNotice("游戏已暂停");
                }
                else
                {
                    setNotice("游戏继续");
                }
                break;
            case 'r': case 'R':
                initGame();
                setNotice("游戏重新开始");
                break;
            }
        }
    }
}

// 更新游戏状态
void updateGame() {
    if (game.paused || game.gameOver) {
        return;
    }

    clock_t currentTime = clock();
    if (currentTime - game.lastMoveTime > game.speed) {
        moveShape(0, 1);
        game.lastMoveTime = currentTime;
    }
}






  • 玩法展示

image.png



打赏

本文链接:https://www.kinber.cn/post/5733.html 转载需授权!

分享到:


推荐本站淘宝优惠价购买喜欢的宝贝:

image.png

 您阅读本篇文章共花了: 

群贤毕至

访客