C语言实现简单打字游戏

您所在的位置:网站首页 简单游戏程序代码是什么 C语言实现简单打字游戏

C语言实现简单打字游戏

2024-06-19 02:25| 来源: 网络整理| 查看: 265

一、效果图和源码 

1.先看运行效果图

 2.给出源码。

#include #include #include #include #include #define NUM 16 //字串总数(页面能存在的最大字串数) struct Block{ char strings[20]; //用于存储字串,20是最大长度 int x; //记录字串的横坐标 int y; //记录字串的纵坐标 int Color[20]; //记录每个字符的颜色 }block[NUM]; enum Difficulty_Level{ Difficulty = 2, Medium = 3, Easy = 4 } speed; //难度等级,字串移动速度,单位秒,由玩家给出 int n = 0; //通过的字串个数 int k = 0; //一个字串输入正确的字符数 double t1, t2; //t用来计时 ,用时间计时方式进行字串下移 void window(int w, int h); //设置窗口大小 void HideCursor(void); //隐藏光标 void color(int c); void gotoxy(int x, int y); void StartInterface(void); void InitInterface(void); void InitBlock(void); void Startgame(void); void JudgeString(int i); void UpdateBlock(int i); void MoveBlock(void); void OtherChoice(int choice); //暂停,重开,结束游戏的选择 void Gameover(void); int UpdateScore(void); void window(int w,int h) //设置窗口大小 { HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出的句柄,命令行的程序会把字符输出到屏幕上。 COORD size = {w, h};//设置窗口的大小。 SetConsoleScreenBufferSize(hOut, size);//重新设置缓冲区大小。 SMALL_RECT rc = {1,1, w, h};//重置窗口位置和大小。 SetConsoleWindowInfo(hOut ,true ,&rc);//重置窗口大小 system("cls");//清理屏幕 return; } void HideCursor(void) //隐藏光标 { CONSOLE_CURSOR_INFO curInfo; //定义光标信息的结构体变量 curInfo.dwSize = 1; //如果没赋值的话,隐藏光标无效 curInfo.bVisible = FALSE; //将光标设置为不可见 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); //获取控制台句柄 SetConsoleCursorInfo(handle, &curInfo); //设置光标信息 } void color(int c) // 改变字体颜色 { SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); /* 0=黑色 8=灰色    1=蓝色 9=淡蓝色      2=绿色 10=淡绿色      3=湖蓝色 11=淡浅绿色     4=红色 12=淡红色      5=紫色 13=淡紫色      6=黄色 14=淡黄色      7=白色 15=亮白色 */ } void gotoxy(int x, int y) //设置光标位置 { COORD xy; xy.X=x; xy.Y=y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),xy); } void StartInterface(void) //提供难度选择 { system("cls"); system("color 07"); n = 0; //重置n值,为使再玩一次时n为0 color(7); gotoxy(30, 12); printf("欢迎来到 “打 字 游 戏 ”!"); gotoxy(30, 15); printf("请选择游戏难度:"); gotoxy(30, 18); printf("1.简单 2.中等 3.困难"); gotoxy(47, 15); char ch = getchar(); while(ch != '1' && ch != '2' && ch != '3') { fflush(stdin); gotoxy(47, 15); for(int i = 0; i < 30; i++) putchar(' '); gotoxy(47, 15); color(12); printf("输入不合法,请重新输入!"); color(7); Sleep(1000); gotoxy(47, 15); for(int i = 0; i < 30; i++) putchar(' '); gotoxy(47, 15); ch = getchar(); } fflush(stdin); if(ch == '1') speed = Easy; if(ch == '2') speed = Medium; if(ch == '3') speed = Difficulty; InitInterface(); //初始化游戏界面 } void InitInterface(void) { system("cls"); const int x = 80, y = 30; for(int i = 0; i < x-1; i++) { for(int j = 0; j < y; j++) { if(i == 0 || i == x-2 || j == 0 || j == y-1 || i == x-30) { gotoxy(i, j); printf("■"); } } } for(int i = 50; i < 80; i++) { gotoxy(i, 13); printf("■"); } color(14); gotoxy(55, 2); printf("通过个数: %d 个", n); gotoxy(55, 4); printf("暂停: 空格"); gotoxy(55, 6); printf("暂停后任意键继续"); gotoxy(55, 8); printf("重新开始: Tab"); gotoxy(55, 10); printf("结束游戏: ESC"); gotoxy(55, 16); printf("游戏说明:"); gotoxy(59, 18); printf("在字串下落之前,正"); gotoxy(59, 20); printf("确输入字串所有字符"); gotoxy(59, 22); printf("可得一分"); gotoxy(55, 25); color(4); if(speed == Easy) printf("当前难度: 简单"); else if(speed == Medium) printf("当前难度: 中等"); else printf("当前难度: 困难"); InitBlock(); //初始化字串 } void InitBlock(void) { srand(unsigned(time(NULL))); const int size = 5; //初始长度为5 for(int i = 0; i < NUM; i++) { for(int j = 0; j < size; j++) { block[i].strings[j] = 97 + rand() % (122 - 97 + 1); // a ——z 的ASSCI序列是 97 ——122 block[i].x = 2 + rand() % 43; //x表示字串的初始横坐标 block[i].y = -2*i - 3; //y表示纵坐标 block[i].Color[j] = 7; //将所有字符颜色置为 7(白色) } block[i].strings[size] = '\0'; //构成字符串,才能使用strlen()函数 } Startgame(); //游戏主体函数 } void Startgame(void) //主体函数 (包含主要算法) { t1 = clock(); //开始计时 while(1) { int t = 25000 * speed; //经测试25000下运行时间大约为1秒 while(--t) { if(kbhit() != 0) //敲击了键盘 break; } //未敲击键盘时,出循环,t 为 0 if(t != 0) //敲击了键盘,找到要输入的字串,通过首字符确定要输入的字串 { char ch = getch(); if(ch == 32 || ch == 9 || ch == 27) //暂停,退出,重开 { OtherChoice(ch); continue; } /*遍历所有的字串,寻找距离底线最近的首字符相符的字串*/ int index[NUM], ans, y_max = 0, j = 0; //前两变量用于记录下标 for(int i = 0; i < NUM; i++) { if(0 < block[i].y && block[i].y < 30 && block[i].strings[0] == ch) { index[j] = i; //记录字串下标 j++; } } int next = 0; while(j) //存在符合条件的首字符时,j不为0 { j--; next = 1; //运行了该while()则必然找到了符合要求的字串,才能进行下一步操作 if(y_max < block[index[j]].y) { ans = index[j]; //记录最优下标 y_max = block[index[j]].y; } } if(next == 1) { k = 1; //正确输入了一个字符 /*先输出第一个字符,再对该字串验证后续输入的正确性*/ block[ans].Color[0] = 10; color(block[ans].Color[0]); gotoxy(block[ans].x, block[ans].y); putchar(block[ans].strings[0]); JudgeString(ans); //判断后续字串输入的正确性 } fflush(stdin); // 敲错后刷新缓冲区,防止乱敲键盘,导致程序一直运行上述代码 } t2 = clock(); if((t2 - t1) / CLOCKS_PER_SEC > speed) //时间间隔超过 SPEED 秒,字串下移 MoveBlock(); } } void JudgeString(int i) //主体函数 (包含主要算法) { while(1) { t2 = clock(); if((t2 - t1) / CLOCKS_PER_SEC > speed) //超时,字串下移 MoveBlock(); int t = 25000 * speed; while(--t) { if(kbhit() != 0) //敲击了键盘 break; } //未敲击键盘时,出循环后,t 为 0 if(t != 0) //以下为敲击键盘的情况,未敲击时直接继续死循环 { char ch = getch(); if(ch == 32 || ch == 9 || ch == 27) //暂停,退出,重开 { OtherChoice(ch); continue; } if(0 < block[i].y && block[i].y < 30 && block[i].strings[k] == ch) //下一个字符输入正确 { block[i].Color[k] = 10; color(block[i].Color[k]); gotoxy(block[i].x + k, block[i].y); putchar(block[i].strings[k]); k++; } else //输入错误,则该字串重置, 即将整个字串的颜色改为白色 { for(int j = 0; j < k; j++) { block[i].Color[j] = 7; color(block[i].Color[j]); gotoxy(block[i].x + j, block[i].y); putchar(block[i].strings[j]); } k = 0; //k也重置, 即正确的字符为0个 break; } int size = strlen(block[i].strings); if(k == size) //完全正确,用空格消除字串 { putchar('\a'); //蜂鸣 gotoxy(block[i].x, block[i].y); while(k > 0) { putchar(' '); k--; //退出循环后,k恢复到 0 } n++; //正确数加一 color(15); gotoxy(65, 2); printf("%d", n); UpdateBlock(i); //更新该字串 break; } } } } void MoveBlock(void) //字串下移 { /*先删除原位置,再进行下移*/ for(int i = 0; i < NUM; i++) { int size = strlen(block[i].strings); if(block[i].y > 0) /* 用空格替代原字串,以实现下次循环时字串的下移 */ { gotoxy(block[i].x, block[i].y); while(size > 0) { putchar(' '); size--; } } block[i].y += 2; //下移 } for(int i = 0; i < NUM; i++) { if(block[i].y > 30) //字串超过底线,游戏结束 Gameover(); if(block[i].y > 0) //字串可以输出 { int size = strlen(block[i].strings); for(int j = 0; j < size; j++) { gotoxy(block[i].x + j, block[i].y); color(block[i].Color[j]); putchar(block[i].strings[j]); } } } t1 = clock(); //重新计时 } void UpdateBlock(int i) //更新字串 { int size = 5 + n / 7; //难度系数,每对7个,单个字串的字符数加一 int last_y = 0; //寻找排在最后的字串 for(int order = 0; order < NUM; order++) last_y = last_y < block[order].y ? last_y : block[order].y; for(int j = 0; j < size; j++) { block[i].Color[j] = 7; //初始颜色为白色 block[i].strings[j] = 97 + rand() % (122 - 97 + 1); // a ——z 的ASSCI序列是 97 ——122 block[i].x = 2 + rand() % (48 - size); //x表示字串的初始横坐标 block[i].y = last_y - 2; //将更新后的字串排在最后 } block[i].strings[size] = '\0'; //构成字符串,才能使用strlen()函数 } void OtherChoice(int choice) { switch(choice) { case 32: //暂停 system("pause>nul"); //暂停 t1 = clock(); //暂停结束后重新计时 break; case 27: //退出 Gameover(); break; default: //重新开始 StartInterface(); } } void Gameover(void) { if(kbhit()) fflush(stdin); system("cls"); gotoxy(28, 14); color(3); printf("游 戏 结 束 !"); Sleep(1200); int max = UpdateScore(); //记录最高分,写到文件中,并返回最终的最高分 system("cls"); system("color 7C"); int i = 0; /* 绘制爱心 */ for (float y = 1.3f; y > -1.3f; y -= 0.1f, i++) { gotoxy(7, i); for (float x = -1.5f; x < 1.5f; x += 0.05f) { float a = x * x + y * y - 1; putchar(a * a * a - x * x * y * y * y 1.8) //频闪1.8秒后 { gotoxy(29, 28); printf("按任意键继续"); } Sleep(100); system("color 7E"); Sleep(100); system("color 7B"); Sleep(100); system("color 79"); Sleep(100); system("color 7D"); Sleep(100); system("color 74"); Sleep(100); system("color 76"); Sleep(100); system("color 71"); Sleep(100); system("color 72"); Sleep(100); system("color 74"); if(kbhit()) { char ch = getch(); break; } } gotoxy(29, 28); printf("再来一次? Y / N : "); char ch = getchar(); ch = tolower(ch); while(ch != 'y' && ch != 'n') { fflush(stdin); gotoxy(49, 28); for(int i = 0; i < 30; i++) putchar(' '); gotoxy(49,28); printf("输入不合法,请重新输入!"); Sleep(1000); gotoxy(49, 28); for(int i = 0; i < 30; i++) putchar(' '); gotoxy(49, 28); ch = getchar(); ch = tolower(ch); } fflush(stdin); if(ch == 'y') StartInterface(); if(ch == 'n') exit(1); } int UpdateScore(void) //记录最高分,写到文件中,并返回最终的最高分 { int score[3]; FILE *fp = fopen("打字游戏最高分记录.txt", "r"); //只读 if(fp == NULL) //创建新文件并初始化成绩 { fp = fopen("打字游戏最高分记录.txt", "w+"); //创建文件,可读写,但会清除原文件 for(int i = 0; i < 3; i++) score[i] = 0; } else for(int i = 0; i < 3; i++) fscanf(fp, "%d", &score[i]); fclose(fp); fp = fopen("打字游戏最高分记录.txt", "r+"); //读写 if(speed == Easy) //简单 { score[0] = score[0] > n ? score[0] : n; for(int i = 0; i < 3; i++) fprintf(fp, "%d ", score[i]); fputs("\n上面分别为三种难度系数的最高分,不要乱改!!!,若修改后导致程序运行错误\n\ 或者最高分为乱码数字,将此.txt文件永久删除即可。", fp); fclose(fp); return score[0]; } if(speed == Medium) //中等 { score[1] = score[1] > n ? score[1] : n; for(int i = 0; i < 3; i++) fprintf(fp, "%d ", score[i]); fputs("\n上面分别为三个难度系数的最高分,不要乱改!!!", fp); fclose(fp); return score[1]; } if(speed == Difficulty) //困难 { score[2] = score[2] > n ? score[2] : n; for(int i = 0; i < 3; i++) fprintf(fp, "%d ", score[i]); fputs("\n上面分别为三个难度系数的最高分,不要乱改!!!", fp); fclose(fp); return score[2]; } } int main(void) { window(80, 30); //设置窗口尺寸,意思是设置一个x = 80, y = 30尺寸的cmd窗口 HideCursor(); //隐藏光标 StartInterface(); //询问游戏难度环节 return 0; } 二、核心算法

由运行效果图可以看出,算法核心在于字串的下落、玩家输入正确性和字串之间的交互,以及两者之间的结合。

        1.字串的下落可以用过计时控制,字串下落前,使用t1 = clock()开始计时,完成一些操作后,使用t2 = clock(), if( (t2-t1) / CLOCKS_PER_SEC  > t), 字串下落。意思是如果运行这一些操作后,时间间隔大于t秒,就让字串下落。

        2.玩家输入的正确性判断时,读取玩家输入的第一个字符,寻找在游戏窗口中第一个字符符合且距离底线最近的字串,然后单独把这个字串拿出来,判断玩家后续输入的正确性。

        3.字串下落和玩家输入的结合则可以用kbhit()函数和getch()函数配合使用,前者判断是否敲击了键盘,后者直接读取敲击的字符而无需按回车键。算法实现:如果玩家敲击了键盘,就读取输入然后寻找匹配的字串,并验证输入的正确性,期间不断计时,根据时间间隔下移字串。

三、代码结构讲解

1.头文件,宏,全局变量

#include #include #include #include #include #define NUM 16 //字串总数(页面能存在的最大字串数) struct Block{ char strings[20]; //用于存储字串,20是最大长度 int x; //记录字串的横坐标 int y; //记录字串的纵坐标 int Color[20]; //记录每个字符的颜色 }block[NUM]; enum Difficulty_Level{ Difficulty = 2, Medium = 3, Easy = 4 } speed; //难度等级,字串移动速度,单位秒,由玩家给出 int n = 0; //通过的字串个数 int k = 0; //一个字串输入正确的字符数 double t1, t2; //t用来计时 ,用时间计时方式进行字串下移

(1)头文件

1. 中使用了time()来获取随机数,clock()用于计时;

2. 中使用了tolower(), 将大写字母变成小写;

3. 中使用了控制台句柄来实现改变光标位置和改变颜色,即color()和gotoxy()函数,同时还使用了system()函数中的清屏、改变颜色(前景加背景)、屏幕冻结等功能,使用Sleep()来实现睡眠;

4. 主要用到了getch(),该函数的作用是不按回车直接读取键盘输入,kbhit()用于判断是否敲击键盘。

(2)宏

全局一个宏NUM,表示字串的数量。给定数值16的原因是游戏窗口高度为30,每个字串的间隔为1,为了让字串占满窗口,设置为16。

(3)全局变量

结构体block代表一个字串,总共16个; 

枚举speed表示三种难度;

int n表示输入正确的字串数;

int k表示单个字串中,输入正确的字符数;所以 n 和 k 需要一开始就置位0;

double t1, t2 用于计时,此处不能用int类型,因为返回的时间是带小数点的。

2.辅助功能函数:

        这四个函数只起辅助作用,会贯穿整个代码,但是其本身没有什么算法。所以后续不会做详细介绍

void window(int w, int h); //设置窗口大小 void HideCursor(void); //隐藏光标 void color(int c); //改变字体颜色 void gotoxy(int x, int y); //设置光标位置

3.main()函数:

        main()函数很简单,在整个代码的最下方。

        功能:  设置一个窗口,隐藏光标,和打开整个游戏的入口函数,即StartInterface()函数。

int main(void) { window(80, 30); //设置窗口尺寸,意思是设置一个x = 80, y = 30尺寸的cmd窗口 HideCursor(); //隐藏光标 StartInterface(); //询问游戏难度环节 return 0; }

4.void StartInterface(void)  询问游戏难度

        使用fflush()(清除缓冲区)优化输入,防止输入错误,和缓冲区残留字符干扰游戏,最后通过InitInitface(),进行游戏界面初始化。初始化比较简单就不单独介绍,直接跳过了。

void StartInterface(void) //提供难度选择 { system("cls"); //清屏 system("color 07"); //黑底白字 n = 0; //重置n值,为使再玩一次时n为0 color(7); gotoxy(30, 12); printf("欢迎来到 “打 字 游 戏 ”!"); gotoxy(30, 15); printf("请选择游戏难度:"); gotoxy(30, 18); printf("1.简单 2.中等 3.困难"); gotoxy(47, 15); char ch = getchar(); while(ch != '1' && ch != '2' && ch != '3') { fflush(stdin); gotoxy(47, 15); for(int i = 0; i < 30; i++) putchar(' '); gotoxy(47, 15); color(12); printf("输入不合法,请重新输入!"); color(7); Sleep(1000); gotoxy(47, 15); for(int i = 0; i < 30; i++) putchar(' '); gotoxy(47, 15); ch = getchar(); } fflush(stdin); if(ch == '1') speed = Easy; if(ch == '2') speed = Medium; if(ch == '3') speed = Difficulty; InitInterface(); //初始化游戏界面 }

5.void InitBlock(void)初始化字串

        使用srand()用时间作为种子,再通过rand()获取随机数,字串的横坐标为随机数,纵坐标出初始为负数,是因为窗口的纵坐标范围是0——30,并让字串的纵坐标依次排列,最后再初始化字串每个字符的颜色。

        注意字串必须构成字符串,因为后续需要使用到strlen()函数。

void InitBlock(void) { srand(unsigned(time(NULL))); const int size = 5; //初始长度为5 for(int i = 0; i < NUM; i++) { for(int j = 0; j < size; j++) { block[i].strings[j] = 97 + rand() % (122 - 97 + 1); // a ——z 的ASSCI序列是 97 ——122 block[i].x = 2 + rand() % 43; //x表示字串的初始横坐标 block[i].y = -2*i - 3; //y表示纵坐标 block[i].Color[j] = 7; //将所有字符颜色置为 7(白色) } block[i].strings[size] = '\0'; //构成字符串,才能使用strlen()函数 } Startgame(); //游戏主体函数 }

6. void Startgame(void) 游戏主体函数

        1.总体思想:若玩家开始输入,捕获输入内容的第一个字符,然后去寻找第一个字符匹配的字串,若找到了,将这个字串单独拿出来,进行后续输入的判断,没有找到,则什么也不做,并不断重复这些操作直到游戏结束。     

        2.需要克服的问题: (1)玩家输入不需要按回车结束输入; (2)字串必须定时下落;        (3) 玩家输入不能影响字串的下落。

        3.算法实现:clock()函数返回时间; kbhit()函数当敲击键盘时返回非零值; getch()函数直接读取输入不需要回车键; 

        4.细节优化: 寻找字串时,需优先寻找距离下限最近的,因为当窗口中有两个首字符一样的字串时,玩家更期望先消除更下面的那个。

int t = 25000 * speed; //经测试25000下运行时间大约为1秒 while(--t) { if(kbhit() != 0) //敲击了键盘 break; }

         使用while(--t)判断 t 遍是否有键盘输入,原因:假设只判断一遍,会立即返回0值(没有敲击键盘)。令t = 25000 * speed, 可以使当没有任何输入时,while(--t)大约运行 speed 秒, 就可以保证没有输入时,每经过 speed 秒字串下移。

void Startgame(void) //主体函数 (包含主要算法) { t1 = clock(); //开始计时 while(1) { int t = 25000 * speed; //经测试25000下运行时间大约为1秒 while(--t) { if(kbhit() != 0) //敲击了键盘 break; } //未敲击键盘时,出循环,t 为 0 if(t != 0) //敲击了键盘,找到要输入的字串,通过首字符确定要输入的字串 { char ch = getch(); if(ch == 32 || ch == 9 || ch == 27) //暂停,退出,重开 { OtherChoice(ch); continue; } /*遍历所有的字串,寻找距离底线最近的首字符相符的字串*/ int index[NUM], ans, y_max = 0, j = 0; //前两变量用于记录下标 for(int i = 0; i < NUM; i++) { if(0 < block[i].y && block[i].y < 30 && block[i].strings[0] == ch) { index[j] = i; //记录字串下标 j++; } } int next = 0; while(j) //存在符合条件的首字符时,j不为0 { j--; next = 1; //运行了该while()则必然找到了符合要求的字串,才能进行下一步操作 if(y_max < block[index[j]].y) { ans = index[j]; //记录最优下标 y_max = block[index[j]].y; } } if(next == 1) { k = 1; //正确输入了一个字符 /*先输出第一个字符,再对该字串验证后续输入的正确性*/ block[ans].Color[0] = 10; color(block[ans].Color[0]); gotoxy(block[ans].x, block[ans].y); putchar(block[ans].strings[0]); JudgeString(ans); //判断后续字串输入的正确性 } fflush(stdin); // 敲错后刷新缓冲区,防止乱敲键盘,导致程序一直运行上述代码 } t2 = clock(); if((t2 - t1) / CLOCKS_PER_SEC > speed) //时间间隔超过 SPEED 秒,字串下移 MoveBlock(); } }

7. void JudgeString(int i)  第二个主体函数

        1.总体思想:在上一个函数中找到了第一个首字符匹配的字串,这个函数则将这个字串单独拿出来,继续判断后续输入的正确性。若后续输入完全正确,就消除该字串(空格覆盖),若出现错误,需要从第一个字符重新输入(从头重新输入),或者选择消除其他的字串。

        2.算法实现:给出死循环,获取玩家输入并做出判断,全对或者出现错误,将字串颜色恢复为白色并退出死循环返回上一层函数。函数声明中的 int i 表示第 i 个字串。

void JudgeString(int i) //主体函数 (包含主要算法) { while(1) { t2 = clock(); if((t2 - t1) / CLOCKS_PER_SEC > speed) //超时,字串下移 MoveBlock(); int t = 25000 * speed; while(--t) { if(kbhit() != 0) //敲击了键盘 break; } //未敲击键盘时,出循环后,t 为 0 if(t != 0) //以下为敲击键盘的情况,未敲击时直接继续死循环 { char ch = getch(); if(ch == 32 || ch == 9 || ch == 27) //暂停,退出,重开 { OtherChoice(ch); continue; } if(0 < block[i].y && block[i].y < 30 && block[i].strings[k] == ch) //下一个字符输入正确 { block[i].Color[k] = 10; color(block[i].Color[k]); gotoxy(block[i].x + k, block[i].y); putchar(block[i].strings[k]); k++; } else //输入错误,则该字串重置, 即将整个字串的颜色改为白色 { for(int j = 0; j < k; j++) { block[i].Color[j] = 7; color(block[i].Color[j]); gotoxy(block[i].x + j, block[i].y); putchar(block[i].strings[j]); } k = 0; //k也重置, 即正确的字符为0个 break; } int size = strlen(block[i].strings); if(k == size) //完全正确,用空格消除字串 { putchar('\a'); //蜂鸣 gotoxy(block[i].x, block[i].y); while(k > 0) { putchar(' '); k--; //退出循环后,k恢复到 0 } n++; //正确数加一 color(15); gotoxy(65, 2); printf("%d", n); UpdateBlock(i); //更新该字串 break; } } } }

8.void MoveBlock(void) 字串下移 和 void UpdateBlock(int i)更新字串 

        1.字串下移采用先删除原字串,再在新位置输出字串。删除使用空格覆盖,新位置则在空格覆盖完后,所有字串y轴 + 2的方式。每次移动完一次字串重新计时。

        2.更新字串时先遍历一边所有字串,找到排在最末尾的那个字串,然后更新的字串就放在最末尾的后面,即last_y - 2,其他跟初始化字串一样。

void MoveBlock(void) //字串下移 { /*先删除原位置,再进行下移*/ for(int i = 0; i < NUM; i++) { int size = strlen(block[i].strings); if(block[i].y > 0) /* 用空格替代原字串,以实现下次循环时字串的下移 */ { gotoxy(block[i].x, block[i].y); while(size > 0) { putchar(' '); size--; } } block[i].y += 2; //下移 } for(int i = 0; i < NUM; i++) { if(block[i].y > 30) //字串超过底线,游戏结束 Gameover(); if(block[i].y > 0) //字串可以输出 { int size = strlen(block[i].strings); for(int j = 0; j < size; j++) { gotoxy(block[i].x + j, block[i].y); color(block[i].Color[j]); putchar(block[i].strings[j]); } } } t1 = clock(); //重新计时 } void UpdateBlock(int i) { int size = 5 + n / 7; //难度系数,每对7个,单个字串的字符数加一 int last_y = 0; //寻找排在最后的字串 for(int order = 0; order < NUM; order++) last_y = last_y < block[order].y ? last_y : block[order].y; for(int j = 0; j < size; j++) { block[i].Color[j] = 7; //初始颜色为白色 block[i].strings[j] = 97 + rand() % (122 - 97 + 1); // a ——z 的ASSCI序列是 97 ——122 block[i].x = 2 + rand() % (48 - size); //x表示字串的初始横坐标 block[i].y = last_y - 2; //将更新后的字串排在最后 } block[i].strings[size] = '\0'; //构成字符串,才能使用strlen()函数 }

9. void OtherChoice(int choice) 其他选择(暂停、结束游戏、重新开始)

      代码中 sysytem("pause") ;的效果如下:

        而 system("pause>nul") 可以消除 “请按任意键继续.  .  .” 这几个字。

void OtherChoice(int choice) { switch(choice) { case 32: //暂停 system("pause>nul"); //暂停 t1 = clock(); //暂停结束后重新计时 break; case 27: //退出 Gameover(); break; default: //重新开始 StartInterface(); } }

 10. void Gameover(void) 游戏结束

            游戏结束后需要更新一下最高分记录,然后可以整一些花里胡哨的东西来美化一下界面。在下面代码中使用了绘制爱心并使爱心频闪的方式。

        右边是爱心的数学函数公式,其算法实现是构造一个矩形,从上至下,从左至右,在该数学函数公式范围内的输出 ‘ * ’, 否则输出空格。

        让爱心频闪的算法是,使用 Sleep(100), 每睡眠100 ms,更换一次字体颜色。

void Gameover(void) { if(kbhit()) fflush(stdin); system("cls"); gotoxy(28, 14); color(3); printf("游 戏 结 束 !"); Sleep(1200); int max = UpdateScore(); //记录最高分,写到文件中,并返回最终的最高分 system("cls"); system("color 7C"); int i = 0; /* 绘制爱心 */ for (float y = 1.3f; y > -1.3f; y -= 0.1f, i++) { gotoxy(7, i); for (float x = -1.5f; x < 1.5f; x += 0.05f) { float a = x * x + y * y - 1; putchar(a * a * a - x * x * y * y * y 1.8) //频闪1.8秒后 { gotoxy(29, 28); printf("按任意键继续"); } Sleep(100); system("color 7E"); Sleep(100); system("color 7B"); Sleep(100); system("color 79"); Sleep(100); system("color 7D"); Sleep(100); system("color 74"); Sleep(100); system("color 76"); Sleep(100); system("color 71"); Sleep(100); system("color 72"); Sleep(100); system("color 74"); if(kbhit()) { char ch = getch(); break; } } gotoxy(29, 28); printf("再来一次? Y / N : "); char ch = getchar(); ch = tolower(ch); while(ch != 'y' && ch != 'n') { fflush(stdin); gotoxy(49, 28); for(int i = 0; i < 30; i++) putchar(' '); gotoxy(49,28); printf("输入不合法,请重新输入!"); Sleep(1000); gotoxy(49, 28); for(int i = 0; i < 30; i++) putchar(' '); gotoxy(49, 28); ch = getchar(); ch = tolower(ch); } fflush(stdin); if(ch == 'y') StartInterface(); if(ch == 'n') exit(1); }

11. int UpdateScore(void)  记录最高分,写到文件中,并返回最终的最高分 

        此函数主要用到了打开文件的一些方法,下面罗列了打开文件的各种方式,就不多加赘述了

int UpdateScore(void) //记录最高分,写到文件中,并返回最终的最高分 { int score[3]; FILE *fp = fopen("打字游戏最高分记录.txt", "r"); //只读 if(fp == NULL) //创建新文件并初始化成绩 { fp = fopen("打字游戏最高分记录.txt", "w+"); //创建文件,可读写,但会清除原文件 for(int i = 0; i < 3; i++) score[i] = 0; } else for(int i = 0; i < 3; i++) fscanf(fp, "%d", &score[i]); fclose(fp); fp = fopen("打字游戏最高分记录.txt", "r+"); //读写 if(speed == Easy) //简单 { score[0] = score[0] > n ? score[0] : n; for(int i = 0; i < 3; i++) fprintf(fp, "%d ", score[i]); fputs("\n上面分别为三种难度系数的最高分,不要乱改!!!,若修改后导致程序运行错误\n\ 或者最高分为乱码数字,将此.txt文件永久删除即可。", fp); fclose(fp); return score[0]; } if(speed == Medium) //中等 { score[1] = score[1] > n ? score[1] : n; for(int i = 0; i < 3; i++) fprintf(fp, "%d ", score[i]); fputs("\n上面分别为三个难度系数的最高分,不要乱改!!!", fp); fclose(fp); return score[1]; } if(speed == Difficulty) //困难 { score[2] = score[2] > n ? score[2] : n; for(int i = 0; i < 3; i++) fprintf(fp, "%d ", score[i]); fputs("\n上面分别为三个难度系数的最高分,不要乱改!!!", fp); fclose(fp); return score[2]; } }



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3