Linux下C语言实现俄罗斯方块——详细版
一、思路
1、创建界面map数组边界填充值 1。
2、rand生成随机数确定下移的图形。
3、界面显示,通过移动光标输出确定界面位置。
4、图形显示,通过光标移动输出图形,四个数据块每一块对应一个小方块。
下一个输出next为 反L3:{(0,0), (1,0), (0,1), (0,2)}。
5、图形下移,通过y变化改变位置下移。
6、下移完成,判断图形到界面边界,将图形到达位置写入map, map填充值2。
7、判断一行是否都填满,填满后忽略本行,将此行以上的拷贝下来,最上面一行不用拷贝(最上面一行如果有图形游戏已经结束了)。
8、判断结束,判断最上面那一行map中有 2 ,有则结束。
9、每次输出完,清理输出界面system("clear"),是一帧一帧输出后形成流畅画面。
10、控制颜色输出详细内容:https://mrleef.blog.csdn.net/article/details/125542134?spm=1001.2014.3001.5506
二、其他
本次用的Linux版本为,ubuntu-18.04.6-desktop-amd64.ios,更新20的版本也不错,个人感觉这个版本的更好用,CentoS不太好用,软件安装也不方便。
编辑器是VSCode和vim,VSCode是开源的,没有版权问题。
运行是用终端运行的。编译命令:gcc game.c -o game 运行:./game
三、代码
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<unistd.h>#define TTY_PATH "/dev/tty" //系统指令
#define STTY_US "stty raw -echo -F " //系统指令
#define STTY_DEF "stty -raw echo -F " //系统指令#define WIDE 18
#define HEIGHT 20
#define INFO_AREA 6
#define SPEED 8
#define Y_NEXT 4 // x_next, y_next下一个图形在方框的位置
#define X_NEXT WIDE - INFO_AREA / 2 - 1int score = 0; //分数
int map[HEIGHT][WIDE] = { 0 }; //界面int x, y; // x, y 正在下降图形的位置
int moveDown_count = 0;
int shapeIndex, shapeIndex_next; //shapeIndex:下移图形 shapeIndex_next:下一个图形struct Point { //中心点的偏移量,中心点以此延伸获得各形状点的坐标int shape_x;int shape_y;
};struct Point shapes[19][4] = {{{0, 0},{-1, 0},{1, 0},{2, 0}}, //横条 通过光标移动输出图形{{0, 0},{0, -1},{0, 1},{0, 2}}, //竖条 每一个图形由四个方块组成{{0,0},{-1,-1},{-1,0},{0,-1}}, //方块 四组,每一组对应输出一个方块 {{0, 0},{0, -1},{0, -2},{1, 0}}, //正L1 0, 1...反映光标移动情况{{0,0},{0,1},{1,0},{2,0}}, //正L2 {{0,0},{-1,0},{0,1},{0,2}}, //正L3 {{0,0},{0,-1},{-1,0},{-2,0}}, //正L4 {{0,0},{-1,0},{0,-1},{0,-2}}, //反L1 {{0,0},{0,-1},{1,0},{2,0}}, //反L2 {{0,0},{1,0},{0,1},{0,2}}, //反L3 {{0,0},{-1,0},{-2,0},{0,1}}, //反L4 {{0,0},{-1,0},{1,0},{0,-1}}, //T1 {{0,0},{0,1},{0,-1},{1,0}}, //T 2 {{0,0},{-1,0},{1,0},{0,1}}, //T 3 {{0,0},{-1,0},{0,-1},{0,1}}, //T 4 {{0,0},{1,0},{0,-1},{-1,-1}}, //正 Z 1 {{0,0},{1,-1},{0,1},{1,0}}, //正Z2 {{0,0},{1,-1},{-1,0},{0,-1}}, //反z1 {{0,0},{-1,-1},{-1,0},{0,1}} //反Z2
};void setFrame(); //构建边宽
void showMap(); //展示界面
void showPoint(int x, int y,int bright,int color);
void showShape(); //输出图形
void creatNewShape();//创建新的图形
int moveDown(); //图形下降,判断是否还可以移动
void addToMap(); //把确定位置的保存在map中
int overCheak(); //确定游戏是否结束
int get_char(); //获取输入
void control(char str); //控制移动
void chageShape(); //改变形状
void moveLeft(); //左移
void moveRight(); //右移
void clearLines(); //清除已满行int main()
{system(STTY_US TTY_PATH); //输入阻塞setFrame(); //初始化mapshowMap(); //展示界面srand(time(0));shapeIndex = rand() % 19;creatNewShape(); //创建下一个图形while(1) {system("clear"); //清除界面显示内容showShape(); //展示方块showMap(); //展示界面if (moveDown()) { //判断移动addToMap(); //不可移动后,写入到mapif (overCheak()) { //检查是否游戏结束break;}clearLines(); //判断一行是否满,并清理shapeIndex = shapeIndex_next;creatNewShape(); //创建下一个图形}char str = get_char(); //得到输入指令if (str == 3) { //是否为ctrl+Cbreak;}control(str); //控制移动usleep(1000*50); //阻碍运行速度}system(STTY_DEF TTY_PATH); //输入阻塞结束printf("\033[21;0H");
}/*** @brief Set the Frame object */
void setFrame()
{int i;for(i = 0; i < WIDE; i++) { //界面两条横线map[0][i] = 1;map[HEIGHT - 1][i] = 1;}for(i = 0; i < HEIGHT; i++) { //界面三条竖线map[i][0] = 1;map[i][WIDE - INFO_AREA - 1] = 1;map[i] [WIDE - 1] = 1;}
}/*** @brief 展示界面 */
void showMap()
{int i, j;for(i = 0; i < HEIGHT; i++) {for(j = 0;j < WIDE; j++) {if ( map[i][j] == 1 || map[i][j] == 2) {showPoint(j, i, 1, 32 + map[i][j]); //行标i,列表j与坐标系横纵坐标的值是相反的}}} printf("\033[2;27H"); // \033[X;XH 光标移动格式printf("\033[31mNext:"); printf("\033[11;27H"); printf("\033[32mScore:"); printf("\033[12;26H"); printf(" \033[32m%3d", score); fflush(stdout); //清理缓存,使画面动作流畅
}/*** @brief 输出一个方块* * @param x1 光标横轴位置* @param y1 光标纵轴位置* @param bright 颜色亮度* @param color 颜色种类*/
void showPoint(int x1, int y1, int bright, int color)
{printf("\033[%d;%dH", y1 + 1, x1 * 2 + 1); //光标位置printf("\033[%d;%dm■ \033[0m", bright, color); //颜色深浅,颜色种类
}/*** @brief 创建下一个图形和重置光标位置*/
void creatNewShape()
{ y = 2;x = (WIDE - INFO_AREA) / 2;shapeIndex_next = rand() % 19;
}/*** @brief 显示正在下降的图形和显示下一个图形*/
void showShape()
{int i;for(i = 0; i < 4; i++) { //显示正在下降的图形showPoint(x + shapes[shapeIndex][i].shape_x, y + shapes[shapeIndex][i].shape_y, 1, 31);}for(i = 0; i < 4; i++) { //显示下一个图形showPoint(X_NEXT + shapes[shapeIndex_next][i].shape_x, Y_NEXT + shapes[shapeIndex_next][i].shape_y, 1, 31);}
}/*** @brief 图形下降和控制移速* * @return int 1为已经处地,0还可移动*/
int moveDown()
{int i;if (moveDown_count < SPEED) { //控制移动速度moveDown_count++; //移动准确性return 0; //也就是两次进入函数图形下移一格}moveDown_count = 0;for (i = 0; i < 4; i++) {int dx = x + shapes[shapeIndex][i].shape_x;int dy = y + shapes[shapeIndex][i].shape_y + 1;//原来位置的map[x][y]已经是1if (map[dy][dx] == 1 || map[dy][dx] == 2) {return 1; //不可移动}}y++;return 0;
}/*** @brief 把不能移动的方块保存到map中*/
void addToMap()
{int i;for(i = 0; i < 4; i++) {map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x] = 2;}
}/*** @brief 检测游戏是否结束* * @return int 0为结束,1还可继续*/
int overCheak()
{int i;for (i = 0; i < WIDE; i++) {if (map[1][i] == 2) {return 1;}}return 0;
}/*** @brief Get the char object* * @return int 返回输入的字符对应的ASCII值*/
int get_char()
{fd_set rfds;struct timeval tv;int ch = 0;FD_ZERO(&rfds);FD_SET(0, &rfds);tv.tv_sec = 0;tv.tv_usec = 10; if (select(1, &rfds, NULL, NULL, &tv) > 0) {ch = getchar(); }return ch;
}/*** @brief 判断输入,得出下一步移动* * @param str 输入的字符*/
void control(char str)
{switch (str) {case 'w': //变形chageShape();break;case 'a': //左移moveLeft();break;case 's': //下移moveDown_count = moveDown_count + SPEED;break;case 'd': //右移moveRight();break;}
}/*** @brief 改变形状* 原理:通过改变shapeIndex的值*/
void chageShape()
{int ts = shapeIndex;switch(ts) {case 0:ts++;break;case 1: ts = 0;break;case 2:break;case 3:case 4:case 5:ts++;break;case 6:ts = 3;break;case 7:case 8:case 9:ts++;break;case 10:ts = 7;break;case 11:case 12:case 13:ts++;break;case 14:ts = 11;break;case 15:ts++;break;case 16:ts = 15;break;case 17:ts++;break;case 18:ts = 17;break;}//ts是假设变形后的图形值int i; //判断假设的图形是否发生碰撞for(i = 0;i < 4;i++) {int cx = x+shapes[ts][i].shape_x;int cy = y+shapes[ts][i].shape_y;if (map[cy][cx]==1 || map [cy][cx]==2) {return;}}shapeIndex = ts; //完成变形
}/*** @brief 左移*/
void moveLeft()
{int i;for (i = 0; i < 4; i++) {if(map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x - 1] == 1|| map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x - 1] == 2) {return;}}x--;
}/*** @brief 右移*/
void moveRight()
{int i;for(i = 0; i < 4; i++) {if (map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x + 1] == 1|| map[y + shapes[shapeIndex][i].shape_y][x + shapes[shapeIndex][i].shape_x + 1] == 2) {return;}}x++;
}/*** @brief 判断一行是否满,并清理,拷贝上面内容*/
void clearLines()
{int i, j, a;for (i = HEIGHT - 2; i > 0; i--) {a = 1;for(j = 1; j < WIDE - INFO_AREA - 1; j++) { //确定是否一行排满if (map[i][j] != 2) {a = 0;break;} }if (a == 1) {score++;int n;for(n = i; n > 1 ; n--) { //把上面的拷贝下来for(j = 0; j < WIDE - INFO_AREA - 1; j++) {map[n][j] = map[n- 1][j];}}i++; //防止有多行一起排满}}fflush(stdout); //清理缓存,使画面动作流畅
}
有什么问题欢迎留言私信,必回!!!
去克制自己纠正别人的欲望,收起你改造他人的执着!人教人是教不会的。
Linux下C语言实现俄罗斯方块——详细版相关推荐
- Linux下SVN服务器迁移(详细版)
最近因公司测试环境需要做迁移,除了应用需要迁移外,项目中平时用到的软件都得迁,涉及到nginx,redis , active MQ ,jenkins 以及SVN.SVN的迁移涉及到了代码的同步,在网上 ...
- GCC编译器简明教程(Linux下C语言开发环境的搭建)
GCC编译器简明教程(Linux下C语言开发环境的搭建) 市面上常见的Linux都是发行版本,典型的Linux发行版包含了Linux内核.桌面环境(例如GNOME.KDE.Unity等)和各种常用的必 ...
- Linux下C语言编程
第1章 Linux下C语言编程简介 本章将简要介绍一下什么是Linux,C语言的特点,程序开发的预备知识,Linux下C语言开发的环境,程序设计的特点和原则以及编码风格等.通过本章的学习,可以对在Li ...
- Linux下函数调用堆栈帧的详细解释【转】
转自:http://blog.chinaunix.net/uid-30339363-id-5116170.html 原文地址: Linux下函数调用堆栈帧的详细解释 作者:cssjtuer http: ...
- 初识Linux下C语言编程
本章将简要介绍一下什么是Linux,C语言的特点,程序开发的预备知识,Linux下C语言开发的环境,程序设计的特点和原则以及编码风格等.通过本章的学习,可以对在Linux下使用C语言编程有一个基本的了 ...
- Linux下使用中文、字体、版
月20日 Unicode BOM 发现网上某广为流传的中文帖子将Unicode字节流的标识字节(BOM, byte order mark)弄错了,正确的应该是: 00 00 FE FF UTF-32, ...
- Linux安装Mysql(图文解说详细版)
安装前必看 这篇文章是用yum安装的,如果是官网安装包tar包安装请移步 Linux安装Mysql(图文解说详细版,安装包tar包版) 文章目录 安装前必看 最近开个新坑,就是在linux环境中操作开 ...
- Linux 应用程序 嵌汇编,Linux下C语言嵌汇编
Using Assembly Language in Linux. Intel和AT&T汇编语法差异: 1.前缀: Intel汇编寄存器和立即数无需前缀.后者寄存器前缀为%,立即数前缀为$. ...
- Linux下C语言编程-进程的创建
Linux下C语言编程-进程的创建 作者:hoyt 1.进程的概念 Linux操作系统是面向多用户的.在同一时间可以有许多用户向操作系统发出各种命令.那么操作系统是怎么实现多用户的环境呢?在现代的操作 ...
- linux父进程中显示子进程pid,请教linux下c语言函数fork父进程打印子进程的PID
请教linux下c语言函数fork父进程打印子进程的PID 关注:296 答案:2 信息版本:手机版 解决时间 2019-01-14 04:55 雨不眠的下 2019-01-13 12:23 用于 ...
最新文章
- Python培训教程分享:Python模块如何导入__all__属性?
- 【Joomla】TinyMCE - Add custom styles
- 并查集(压缩路径+按秩排序)
- 中国安防视频监控行业发展前景分析
- android9.0不能用4g定位,Android 9.0新特性:让用户认为4G信号更强
- php ascii hex编码
- Codeforces Round #497 (Div. 1)
- 正则表达式的环视实际应用案例
- 【动态规划】完全背包问题
- android的listview点击获取当前选项值的方法
- 嘿,我这里有一个 Survey!
- 30首优秀奥运歌曲获奖作品出炉
- 1. golang 接入Discord做消息推送
- 7个碎片的excel重组实验
- Use YSlow to know why your web Slow
- 运筹学及其matlab应用,运筹学基础及其MATLAB应用
- 4个方法:提升用户活跃度
- 【uniapp | 微信小程序】注册和开发环境搭建
- Android 5.x浏览器webView或者qqX5崩溃,Resources$NotFoundException:String resource ID #0x2040003
- 苹果7p最佳系统版本_苹果代码中发现, iPhone12 刘海没了!