这个用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;
}
}
-
玩法展示
本文链接:https://www.kinber.cn/post/5733.html 转载需授权!
推荐本站淘宝优惠价购买喜欢的宝贝:

支付宝微信扫一扫,打赏作者吧~
