当前位置: 首页 > news >正文

基于C语言和Ncurses的俄罗斯方块游戏实现

📖 项目介绍

这是一个使用C语言和Ncurses库开发的终端版俄罗斯方块游戏。项目基于Stephen Brennan的原始工作,由Lillylll进行修改和扩展,支持单机游戏和网络对战模式。

GitHub地址: https://github.com/Lillylll/My_tetris/blob/main/Makefile

🎮 功能特性

  • ✅ 经典俄罗斯方块游戏机制

  • ✅ 彩色方块显示(支持7种颜色)

  • ✅ 实时键盘响应控制

  • ✅ 分数系统和消行动画

  • ✅ 网络对战功能(双玩家)

🛠️ 编译和运行

环境要求

  Linux虚拟机

编译项目

项目使用Makefile进行编译管理:

# Makefile
CC = gcc
CFLAGS = -Wall -Wextra -std=c11 -g
LDFLAGS = -lncurses -lrt
TARGET = tetris
SRCS = main.c tetris.c
OBJS = $(SRCS:.c=.o)# 默认目标:编译整个项目
all: $(TARGET)# 链接目标文件生成可执行程序
$(TARGET): $(OBJS)$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)# 编译规则:将.c文件编译为.o文件
%.o: %.c tetris.h$(CC) $(CFLAGS) -c $< -o $@# 清理编译生成的文件
clean:rm -f $(OBJS) $(TARGET).PHONY: all clean

编译命令:

make          # 编译项目
make clean    # 清理编译文件
./tetris      # 运行单机游戏

网络对战模式

终端1:启动服务器
make ./tetris# 终端2:连接客户端
./tetris 127.0.0.1

📁 代码结构

tetris-game/
├── main.c          # 主程序入口和游戏循环
├── tetris.h        # 头文件(数据结构声明)
├── tetris.c        # 游戏逻辑实现
├── Makefile        # 编译配置
└── README.md       # 项目说明

🎯 核心代码解析

1. 游戏数据结构定义 (tetris.h)

#ifndef _TETRIS_H
#define _TETRIS_H#include <ncurses.h>
#include <stdbool.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>// 游戏常量定义
#define ROWS 25                    // 游戏区域行数
#define COLS 33                    // 游戏区域列数
#define NUM_TETROMINOS 7           // 方块种类数量
#define NUM_ORIENTATIONS 4         // 方块旋转状态数
#define TETRIS 4                   // 每个方块的格子数
#define PORT 8888                  // 网络对战端口// 方块类型枚举
typedef enum {TYPE_I,    // I型方块TYPE_O,    // O型方块  TYPE_T,    // T型方块TYPE_S,    // S型方块TYPE_Z,    // Z型方块TYPE_J,    // J型方块TYPE_L     // L型方块
} TetrominoType;// 方块位置结构
typedef struct {int row;int col;
} TetrisLocation;// 当前活动方块结构
typedef struct {TetrominoType type;         // 方块类型int orientation;            // 旋转状态int row, col;               // 位置坐标
} Tetromino;// 游戏状态结构
typedef struct {char board[ROWS][COLS];     // 游戏棋盘Tetromino current;          // 当前方块int score;                  // 游戏分数bool game_over;             // 游戏结束标志
} Game;// 网络消息结构
typedef struct {int msg_type;               // 消息类型Game game_state;            // 游戏状态int key_pressed;            // 按键信息
} NetworkMessage;// 全局方块形状数据
extern const TetrisLocation TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS];// 函数声明
void init_game(Game *game);
void spawn_tetromino(Game *game);
void display_board(Game *game, WINDOW *win, int player_num);
bool move_tetromino(Game *game, int dir);
void falling(Game *game);
bool can_move(Game *game, int new_row, int new_col);
bool fix_tetromino(Game *game);
void rotate_tetromino(Game *game);
void hard_drop(Game *game);
void check_line(Game *game);
void game_over(Game *game);// 网络功能
int create_server();
int create_client(const char *server_ip);
void send_game_state(int sockfd, Game *game);
void receive_game_state(int sockfd, Game *game);
void send_key_press(int sockfd, int key);
int receive_key_press(int sockfd);#endif

2. 方块形状定义 (tetris.c)

/** Original work Copyright (c) 2015 Stephen Brennan* Modified work Copyright (c) 2023 Lillylll* 根据BSD 3-Clause许可证发布*/#include "tetris.h"
#include <ncurses.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>// 所有俄罗斯方块形状定义
// 使用三维数组存储:方块类型 × 旋转状态 × 4个格子坐标
const TetrisLocation TETROMINOS[NUM_TETROMINOS][NUM_ORIENTATIONS][TETRIS] = {// I型方块(长条){{{1, 0}, {1, 1}, {1, 2}, {1, 3}},  // 水平状态{{0, 2}, {1, 2}, {2, 2}, {3, 2}},  // 垂直状态{{3, 0}, {3, 1}, {3, 2}, {3, 3}},  // 另一水平状态{{0, 1}, {1, 1}, {2, 1}, {3, 1}}}, // 另一垂直状态// J型方块{{{0, 0}, {1, 0}, {1, 1}, {1, 2}},{{0, 1}, {0, 2}, {1, 1}, {2, 1}},{{1, 0}, {1, 1}, {1, 2}, {2, 2}},{{0, 1}, {1, 1}, {2, 0}, {2, 1}}},// 其他方块定义...// L型方块{{{0, 2}, {1, 0}, {1, 1}, {1, 2}},{{0, 1}, {1, 1}, {2, 1}, {2, 2}},{{1, 0}, {1, 1}, {1, 2}, {2, 0}},{{0, 0}, {0, 1}, {1, 1}, {2, 1}}},// O型方块(正方形,旋转不变){{{0, 1}, {0, 2}, {1, 1}, {1, 2}},{{0, 1}, {0, 2}, {1, 1}, {1, 2}},{{0, 1}, {0, 2}, {1, 1}, {1, 2}},{{0, 1}, {0, 2}, {1, 1}, {1, 2}}},// S型方块{{{0, 1}, {0, 2}, {1, 0}, {1, 1}},{{0, 1}, {1, 1}, {1, 2}, {2, 2}},{{1, 1}, {1, 2}, {2, 0}, {2, 1}},{{0, 0}, {1, 0}, {1, 1}, {2, 1}}},// T型方块{{{0, 1}, {1, 0}, {1, 1}, {1, 2}},{{0, 1}, {1, 1}, {1, 2}, {2, 1}},{{1, 0}, {1, 1}, {1, 2}, {2, 1}},{{0, 1}, {1, 0}, {1, 1}, {2, 1}}},// Z型方块{{{0, 0}, {0, 1}, {1, 1}, {1, 2}},{{0, 2}, {1, 1}, {1, 2}, {2, 1}},{{1, 0}, {1, 1}, {2, 1}, {2, 2}},{{0, 1}, {1, 0}, {1, 1}, {2, 0}}}
};

3. 游戏初始化函数

/*** 初始化游戏状态* @param game 游戏状态指针*/
void init_game(Game *game)
{// 清空游戏棋盘for (int i = 0; i < ROWS; i++) {for (int j = 0; j < COLS; j++) {game->board[i][j] = ' ';  // 空格表示空位置}}game->score = 0;           // 初始化分数game->game_over = false;   // 游戏运行状态// 初始化随机数种子,用于生成随机方块srand(time(NULL));// 生成第一个方块spawn_tetromino(game);
}/*** 生成新的随机方块* @param game 游戏状态指针*/
void spawn_tetromino(Game *game)
{// 随机选择方块类型 (0-6)game->current.type = rand() % NUM_TETROMINOS;game->current.orientation = 0;  // 初始旋转状态game->current.row = 0;          // 从顶部开始// 根据方块类型计算初始水平位置(居中显示)int width = 3;  // 大多数方块宽度为3if (game->current.type == TYPE_O)width = 2;   // O型方块宽度为2else if (game->current.type == TYPE_I)width = 4;   // I型方块宽度为4// 计算居中位置game->current.col = (COLS - width) / 4;
}

4. 游戏主循环 (main.c)

#define _POSIX_C_SOURCE 199309L
#include <locale.h>
#include <ncurses.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "tetris.h"#define FALL_INTERVAL 1000000  // 方块下落间隔:1秒/*** 主函数 - 游戏入口点*/
int main(int argc, char *argv[])
{int sockfd = -1;bool is_server = false;// 解析命令行参数,确定运行模式if (argc == 2 && strcmp(argv[1], "server") == 0) {sockfd = create_server();  // 服务器模式is_server = true;} else if (argc == 2) {sockfd = create_client(argv[1]);  // 客户端模式} else {// 单机模式printf("单机游戏模式启动...\n");}// 初始化NCurses图形界面initscr();                    // 初始化屏幕curs_set(0);                  // 隐藏光标cbreak();                     // 字符立即输入noecho();                     // 关闭输入回显keypad(stdscr, true);         // 启用功能键nodelay(stdscr, true);        // 非阻塞输入timeout(0);                   // 立即返回的输入超时// 初始化颜色系统if (has_colors()) {start_color();// 定义7种方块颜色init_pair(1, COLOR_CYAN, COLOR_BLACK);    // I - 青色init_pair(2, COLOR_BLUE, COLOR_BLACK);    // J - 蓝色init_pair(3, COLOR_WHITE, COLOR_BLACK);   // L - 白色  init_pair(4, COLOR_YELLOW, COLOR_BLACK);  // O - 黄色init_pair(5, COLOR_GREEN, COLOR_BLACK);   // S - 绿色init_pair(6, COLOR_MAGENTA, COLOR_BLACK); // T - 洋红init_pair(7, COLOR_RED, COLOR_BLACK);     // Z - 红色}// 获取终端尺寸并创建游戏窗口int yMax, xMax;getmaxyx(stdscr, yMax, xMax);WINDOW *playwin = newwin(yMax - 3, (xMax / 2) - 4, 2, 2);box(playwin, 0, 0);  // 绘制窗口边框refresh();wrefresh(playwin);// 初始化游戏状态Game game;init_game(&game);// 初始化计时器struct timespec last_fall_time;clock_gettime(CLOCK_MONOTONIC, &last_fall_time);// 主游戏循环while (1) {// 渲染游戏界面display_board(&game, playwin, 1);// 显示分数mvwprintw(playwin, 2, 2, "Score: %d", game.score);wrefresh(playwin);// 处理键盘输入int ch;while ((ch = getch()) != ERR) {switch(ch) {case 'q': goto exit_game;  // 退出游戏case KEY_LEFT:case KEY_RIGHT: case KEY_DOWN:case KEY_UP:case ' ':move_tetromino(&game, ch);  // 移动方块break;}}// 自动下落逻辑struct timespec current_time;clock_gettime(CLOCK_MONOTONIC, &current_time);long elapsed_time = (current_time.tv_sec - last_fall_time.tv_sec) * 1000000L +(current_time.tv_nsec - last_fall_time.tv_nsec) / 1000L;if (elapsed_time >= FALL_INTERVAL) {falling(&game);  // 执行下落clock_gettime(CLOCK_MONOTONIC, &last_fall_time);}// 控制游戏帧率 (50ms)struct timespec ts = {0, 50000 * 1000L};nanosleep(&ts, NULL);// 检查游戏结束if (game.game_over) {game_over(&game);break;}}exit_game:// 清理资源delwin(playwin);endwin();if (sockfd >= 0) close(sockfd);return 0;
}
5. 游戏逻辑核心函数
c/*** 检查方块是否可以移动到指定位置* @param game 游戏状态* @param new_row 目标行* @param new_col 目标列* @return 是否可以移动*/
bool can_move(Game *game, int new_row, int new_col)
{int type = game->current.type;int orientation = game->current.orientation;// 检查方块的4个格子for (int t = 0; t < TETRIS; t++) {int r = new_row + TETROMINOS[type][orientation][t].row;int c = new_col + TETROMINOS[type][orientation][t].col;// 边界检查if (r >= ROWS || c < 0 || c >= COLS || game->board[r][c] != ' ') {return false;}}return true;
}/*** 旋转当前方块* @param game 游戏状态*/
void rotate_tetromino(Game *game)
{// 保存原始状态以便回滚Tetromino old = game->current;// 计算新的旋转状态game->current.orientation = (game->current.orientation + 1) % NUM_ORIENTATIONS;// 如果旋转后位置无效,则恢复原状态if (!can_move(game, game->current.row, game->current.col)) {game->current = old;}
}/*** 消行检测和分数计算* @param game 游戏状态*/
void check_line(Game *game)
{int lines_cleared = 0;// 从底部向上检查每一行for (int i = ROWS - 1; i >= 0; i--) {bool line_full = true;// 检查当前行是否已满for (int j = 0; j < COLS; j++) {if (game->board[i][j] == ' ') {line_full = false;break;}}// 如果行已满,则消除该行if (line_full) {lines_cleared++;// 将上方所有行下移for (int k = i; k > 0; k--) {for (int j = 0; j < COLS; j++) {game->board[k][j] = game->board[k - 1][j];}}// 清空最顶层for (int j = 0; j < COLS; j++) {game->board[0][j] = ' ';}// 重新检查当前行(因为内容已变化)i++;}}// 根据消除的行数计算分数if (lines_cleared > 0) {game->score += lines_cleared * 100;}
}

🎮 操作说明

按键功能
方向键 ↑旋转方块
方向键 ↓加速下落
方向键 ←/→左右移动
空格键硬降(立即下落到底部)
Q键退出游戏

🚀 扩展功能

网络对战实现

项目支持简单的网络对战功能,使用TCP socket进行通信:

// 创建服务器监听连接
int create_server() {int sockfd = socket(AF_INET, SOCK_STREAM, 0);struct sockaddr_in server_addr = {.sin_family = AF_INET,.sin_port = htons(PORT),.sin_addr.s_addr = INADDR_ANY};bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));listen(sockfd, 1);// 等待客户端连接int client_sock = accept(sockfd, NULL, NULL);return client_sock;
}

📝 学习价值

这个项目涵盖了以下编程概念:

  • 数据结构设计:游戏状态管理、方块形状表示

  • 算法实现:碰撞检测、消行算法、旋转逻辑

  • 图形编程:NCurses库的使用、终端图形界面

  • 网络编程:Socket通信、数据同步

  • 时间管理:高精度定时器、游戏循环控制

  • 模块化设计:头文件组织、函数分离

如果有什么建议或改善,欢迎评论!

http://www.dtcms.com/a/508820.html

相关文章:

  • 企业网站脚本语言网站代备案公司
  • 网站建设托管预算清单展厅设计培训
  • PCIe协议之 Equalization篇 之 关于 TxSwing 的理解
  • 海康域名网站有做门窗找活的网站吗
  • 福建省龙岩市建设培训中心网站网站内容一样影响收录
  • 流行网站类型大学网站建设宣传方案
  • 久久网站建设巴中市平昌县建设局网站
  • idea整合Git
  • 如何选择性价比高的中药饮片才能确保品质与效果?
  • 设计师网站图片重庆市建设工程信息网官网工程押证
  • 私人程序定制:纳什欺诈谈判
  • 呼和浩特市网站建设什么叫宣传类网站
  • 建设银行网站-个人业务泰州网站建设设计
  • MySQL的json处理相关方法
  • 兰州网站建设营销q479185700刷屏外贸网站排名
  • 网站加入地图企业网站维护工作
  • TDengine 数据函数 MOD 用户手册
  • 创业公司做网站免费开发游戏
  • 企业网站seo策略网站开发费
  • 怎么介绍自己做的网站网站标签怎样修改
  • 保定电子商务网站建设域名申请好了怎么做网站
  • 大规模车辆路径问题的增强神经组合优化(ICRL‘25)
  • 怎么用自己电脑做网站服务器吗wordpress 房产类模板
  • 优质双轴倾角传感器厂家与物联网角度传感器资源整合探讨
  • 股票分析AI系统部署技术方案
  • 视频网站的制作教程移动互联网开发作业
  • 2010-2050年中国中国多类产品废物流出预测数据(电子电器、线缆、汽车等)
  • 手机网站建设价格明细表中文wordpress案例
  • 吴江区建设银行招聘网站世界杯网页设计素材
  • 萝岗微网站建设无锡seo公司找哪家好