C语言实现控制台版贪吃蛇游戏
程序员文章站
2022-04-29 13:03:59
用c语言写的期末作业:c语言实现控制台版贪吃蛇游戏的具体代码,供大家参考,具体内容如下/*{ conio.h 阻塞式: getch(): 从无回显的控制台获取字符。无缓冲区,只有当按下一个键才会执...
用c语言写的期末作业:c语言实现控制台版贪吃蛇游戏的具体代码,供大家参考,具体内容如下
/* { conio.h 阻塞式: getch(): 从无回显的控制台获取字符。无缓冲区,只有当按下一个键才会执行后面的程序。 非阻塞式: kbhit() 检测缓冲区中是否有字符;执行该函数后程序不会停下,而是继续执行下面的代码 由于getch()和kbhit()已弃用, 在编译时会产生警告, 可以用_getch()和_kbhit()替换它们, 或者在包含头文件前加上#pragma warning(disable : 4996)关闭警告 } */ #pragma warning(disable : 4996) //用来关闭警告 #include<stdio.h> #include <stdlib.h> #include <conio.h> //_kbhit()函数获取键盘事件 #include <time.h> #include<windows.h> #define win_heigh 30 //窗口高度 #define win_width 105 //窗口宽度 #define g_height 30 //游戏界面高度 #define g_width 80 //游戏界面宽度 #define status int //函数返回状态属性 #define success 1 //执行成功 #define fail 0 //执行失败 typedef struct snake_node{ //蛇的某个点的信息 char direct; //即将前进的方向 udlr分别对应上下左右,刚吃掉的身体部分方向为o coord postion; //该点所在位置 struct snake_node* next_node; //下个节点的指针 }*ps_node,s_node; typedef struct snake { char head_type; //蛇头的样子 char body_type; //蛇身的样子 word color; //颜色 int level; //等级 int speed; //速度 int score; //成绩 int control; //控制器 即按wasd进行移动,或者按上下左右进行移动 s_node head; //蛇头 }*psnake,snake; //蛇结构 // 0输出空格 -1输出# char canvas[g_height][g_width] ; //画布 int bean_count; //已创建食物的数量 point reward_position; //奖励的位置 int reward_time = -1000; //奖励剩余时间 int run_snake_threads; //正在运行的蛇的数量 char keyboard_out[2]; //键盘的输出控制器 keyboard_out[0],代表控制器1,keyboard_out[1],代表控制器2, int init_snake_speed = 400; //蛇的初始速度 ,例=400时,蛇0.4s前进一步 //关于颜色取值,请查看help.txt void gotoxy(int x, int y); //设置光标到指定位置 void setcolor(word wattributes); //设置输出颜色 void prc_toxy(char c, int x, int y); //指定位置输出字符 void prs_toxy(char* str, int x, int y); //指定位置输出字符串 void prc_colortoxy(char str, int x, int y, word wattributes); //在指定位置,以wattributes颜色输出字符 void prs_colortoxy(char* str, int x, int y, word wattributes); //在指定位置,以wattributes颜色输出字符字符串 void one_play_mod(); //进入单人模式 void two_play_mod(); //进入双人模式 /*********************** 函数名:init_system 功能: 获取窗口句柄 设置控制台颜色和大小 隐藏光标显示 ************************/ void init_system(); /*********************** 函数名:init_snode 功能:初始化新的身体节点 输入参数: direct:这个节点的下一个运动方向; snake_x,snake_y:这个节点的位置(x,y) next_node:下一个节点的指针 返回值: ps_node:返回已初始化的节点的指针 ************************/ ps_node init_snode(ps_node n_snode,char drect,int x,int y,ps_node next_node); /************************ 函数名:init_snake 功能:初始化蛇的相关参数,并为其创建身体,长度为三 输入参数: she: 要初始化的蛇指针 color: 蛇的颜色 head_type: 用该字符显示蛇的身体 x,y: 蛇最开始的位置 direct: 默认前进方向 control: 移动蛇的方式:默认1为wasd键,2为方向键盘上下左右键 返回值:初始化后的蛇指针 **************************/ psnake init_snake(psnake she ,word color,char head_type,char body_type,int x,int y, char direct, int control); //初始化小蛇 dword winapi run_snake_thread(lpvoid lpparam); //线程:运行一条蛇 dword winapi del_reward_thread(lpvoid lpparam); //线程:生成奖励后,一段时间内不迟到奖励会消失 dword winapi render_thread(lpvoid lpparam); //线程:用来渲染,游戏运行时,所有的打印显示由该进程完成 dword winapi keyboard_thread(lpvoid lpparam); //线程:游戏运行时,监听按键输入,并设置keyboard_out /************************ 函数名:get_canvas_toxy 功能: 获取画布上该点的值 输入参数:postion 返回值:char类型,画布上该点的值 ************************/ char get_canvas_toxy(coord postion); /*********************** 函数名:snode_gonext 功能: 蛇身体上的点移动到下个位置 输入参数: snode:要移动的点 direct:要移动的方向 返回值:char ,未移动前,该点要前进的方向 ************************/ char snode_gonext(ps_node snode, char direct); /*********************** 函数名:snake_gonext 功能: 蛇移动到下个位置 输入参数: she:要移动的蛇 direct:蛇头移动的方向 返回值:无 ************************/ void snake_gonext(psnake she, char direct); /******************** 函数名:init_canvas 功能: 初始化画布,并为画布设置边框 输入参数: 无 返回值: 无 ********************/ void init_canvas(); void draw_wall(); //在canvas上设置边框位置 /*********************** 函数名:snaketocanvas 功能:将蛇的坐标信息拷贝到画布canvas上,在canvas上删除原来的位置信息, 输入参数:she :要拷贝的蛇的指针 ***********************/ void snaketocanvas(psnake she); /************************** 函数名:eat_node 功能:蛇吃食物,并把它加入蛇身,并增加成绩,触发升级加速 (注:加入到蛇身后该点的位置还在原来的地方,需要身体都经过那里后长度才会增加) 输入参数: she:吃食物的那条蛇 position:食物的位置 **************************/ void eat_node(psnake she, coord postion); /********************** 函数名:create_bean 功能:在画布的一个随机位置创建豆 返回值: status:返回是否创建成功 **********************/ status createrand_bean(); /********************** 函数名:free_snake 功能:释放小蛇的内存 输入参数: she:要释放内存的小蛇 ************************/ void free_snake(psnake she); void menu(); //开始菜单, 用来选择模式,单人或者双人 void show_menu(int flag); //根据不同的flag显示不同的菜单 handle handle; int main() { init_system(); menu(); return 0; } void init_system() { system("color f0 "); handle = getstdhandle(std_output_handle);//获取窗口句柄 char chcmd[32]; sprintf(chcmd, "mode con cols=%d lines=%d", win_width, win_heigh); //设置控制台大小 system(chcmd); console_cursor_info cursor_info = { 1,0 }; //设置光标不可见,第一个值为光标厚度,第二个值为光标是否显示 setconsolecursorinfo(handle, &cursor_info); // srand((int)time(null)); //初始化随机数种子 } void menu() { int ch1, ch2; int flag = 1; //标志当前选择模式 show_menu(flag); while (1) { ch1 = _getch(); if (ch1 == 13) { printf("此处是进入函数\n"); if (flag == 1) one_play_mod(); else if (flag == 2) two_play_mod(); else { system("cls"); printf("退出\n"); break; } } if (ch1==224) { ch2 = _getch(); if (ch2 == 72) { flag = (flag + 2)% 3; } else if (ch2 == 80) { flag = (flag + 4) % 3; } } show_menu(flag); } } void show_menu(int flag) { char gamename[30] = "贪 吃 蛇"; char mod1[20] = "单人模式"; char mod2[20] = "双人模式"; char modexit[20] = "退出"; int xstr = (win_width - strlen(mod1)) / 2; //要打印选项的位置x列 int ystr; //要打印选项的位置y行 word color[3] = {0xf0,0xf0,0xf0}; //要设置的颜色 system("cls"); setcolor(0xf0); prs_toxy(gamename, (win_width - strlen(gamename) )/ 2, 5); color[flag] = foreground_red | 0xf0; prs_colortoxy(mod1, (win_width - strlen(mod1)) / 2, 11, color[1]); prs_colortoxy(mod2, (win_width - strlen(mod2)) / 2, 13, color[2]); prs_colortoxy(modexit, (win_width - strlen(modexit)) / 2, 15, color[0]); if (flag == 1) ystr = 11; else if (flag == 2) ystr = 13; else ystr = 15; //设置箭头位于哪一行 prs_colortoxy("→", xstr - 4, ystr, color[flag]); gotoxy(0, 0); } void gotoxy(int x, int y) { coord pos; pos.x = x; pos.y = y; setconsolecursorposition(handle, pos); } void setcolor(word wattributes) { setconsoletextattribute(handle, wattributes); } void prc_toxy(char c, int x, int y) { gotoxy(x, y); printf("%c", c); } void prs_toxy(char* str, int x, int y) { gotoxy(x, y); printf("%s", str); } void prc_colortoxy(char c, int x, int y, word wattributes) { gotoxy(x, y); setconsoletextattribute(handle, wattributes); printf("%c", c); } void prs_colortoxy(char* str, int x, int y, word wattributes) { gotoxy(x, y); setconsoletextattribute(handle, wattributes); printf("%s", str); } ps_node init_snode(ps_node n_snode, char drect, int x, int y, ps_node next_node) { n_snode->direct = drect; n_snode->postion.x = x; n_snode->postion.y = y; n_snode->next_node = next_node; return n_snode; } psnake init_snake(psnake she , word color, char head_type, char body_type, int x, int y, char direct,int control) { int ax=x,ay=y,bx=x,by=y; she->head_type = head_type; she->body_type = body_type; she->color = color; she->control = control; she->level = 1; she->speed = init_snake_speed; she->score = 0; ps_node s1 = (ps_node)malloc(sizeof(s_node)); ps_node s2 = (ps_node)malloc(sizeof(s_node)); switch (direct) { case 'l': ax = x + 2; bx = x + 1; break; case 'r': ax = x - 2; bx = x - 1; break; case 'u': ay = y + 2; by = y + 1; break; case 'd': ay = y - 2; by = y - 1; break; default: break; } init_snode(s2, direct, ax, ay, null); //要根据方向设置下一个节点的位置 init_snode(s1, direct, bx , by, s2); init_snode(&she->head, direct, x, y,s1); return she; } void one_play_mod() { handle hthread; handle hthread_render; handle ht_getkey; snake xiaoshe; system("cls"); bean_count = 0; init_canvas(); init_snake(&xiaoshe,0xf2, '@','*', g_width/2, g_height/2, 'r', 2); snaketocanvas(&xiaoshe); createrand_bean(); run_snake_threads = 1; draw_wall(); hthread = createthread(null, 0, run_snake_thread,(lpvoid)&xiaoshe, 0, null); hthread_render = createthread(null, 0, render_thread, (lpvoid)&xiaoshe, 0, null); ht_getkey= createthread(null, 0,keyboard_thread, null, 0, null); waitforsingleobject(hthread, infinite); run_snake_threads = 0; waitforsingleobject(ht_getkey, infinite); waitforsingleobject(hthread_render, infinite); closehandle(hthread); closehandle(ht_getkey); closehandle(hthread_render); gotoxy(g_width / 2-2, g_height / 2); printf("游戏结束\n"); sleep(2000); } void two_play_mod() { handle hthread_a; handle hthread_b; handle hthread_render; handle ht_getkey; snake she[2]; system("cls"); bean_count = 0; init_canvas(); init_snake(&she[0], 0xf2, '@', '*', g_width / 2-4, g_height / 2 -4, 'r', 2); init_snake(&she[1], 0xe5, 'u', 's', g_width / 2, g_height / 2, 'l', 1); snaketocanvas(&she[0]); snaketocanvas(&she[1]); draw_wall(); createrand_bean(); /*createrand_bean(); //创建多个食物 createrand_bean(); createrand_bean();*/ run_snake_threads = 2; hthread_b = createthread(null, 0, run_snake_thread, (lpvoid)&she[0], 0, null); hthread_a = createthread(null, 0, run_snake_thread, (lpvoid)&she[1], 0, null); hthread_render= createthread(null, 0, render_thread, (lpvoid)&she, 0, null); ht_getkey = createthread(null, 0, keyboard_thread, null, 0, null); waitforsingleobject(hthread_a, infinite); waitforsingleobject(hthread_b, infinite); run_snake_threads = 0; waitforsingleobject(ht_getkey, infinite); waitforsingleobject(hthread_render, infinite); closehandle(hthread_a); closehandle(hthread_b); closehandle(ht_getkey); closehandle(hthread_render); gotoxy(g_width / 2, g_height / 2); printf("游戏结束\n"); sleep(1000); } dword winapi keyboard_thread(lpvoid lpparam) { int ch1; int ch2; keyboard_out[0] = 'n'; keyboard_out[1] = 'n'; while (run_snake_threads > 0) { while (_kbhit()) { ch1 = _getch(); switch (ch1) { case 'w': keyboard_out[0] = 'u'; break; case 's': keyboard_out[0] = 'd'; break; case 'd': keyboard_out[0] = 'r'; break; case 'a': keyboard_out[0] = 'l'; break; case 224: ch2 = _getch(); switch (ch2) { case 72: keyboard_out[1] = 'u'; break; case 80: keyboard_out[1] = 'd'; break; case 77: keyboard_out[1] = 'r'; break; case 75: keyboard_out[1] = 'l'; break; default: break; } break; default: break; } } sleep(50); } } char get_canvas_toxy(coord postion) { return canvas[postion.y][postion.x]; } char snode_gonext(ps_node snode, char direct) { char old_direct = snode->direct; snode->direct = direct; switch (direct) { case 'u': snode->postion.y = snode->postion.y - 1; break; case 'd': snode->postion.y = snode->postion.y + 1; break; case 'l': snode->postion.x = snode->postion.x - 1; break; case 'r': snode->postion.x = snode->postion.x + 1; break; default: break; } return old_direct; } void snake_gonext(psnake she, char direct) { ps_node temp=&she->head; ps_node end = temp; char dta=direct; //方向 while (temp!=null) //不处理最后一个节点 { if(temp->next_node!=null && temp->next_node->direct=='n'){ if (temp->postion.x == temp->next_node->postion.x && temp->postion.y == temp->next_node->postion.y) { dta = snode_gonext(temp, dta); temp->next_node->direct = dta; }else dta = snode_gonext(temp, dta); break; } dta=snode_gonext(temp, dta); temp = temp->next_node; } snaketocanvas(she); } void snaketocanvas(psnake she) { ps_node temp=&she->head; int i, j,x,y; char body_type = she->body_type; for (i = 1; i < g_height - 1; i++) for (j = 1; j < g_width - 1; j++) if (canvas[i][j] == she->head_type || canvas[i][j] == she->body_type) canvas[i][j] = '0'; x = temp->postion.x; y = temp->postion.y; while (temp->next_node != null) { canvas[temp->next_node->postion.y][temp->next_node->postion.x] = body_type; temp = temp->next_node; } canvas[y][x] = she->head_type; //单独处理蛇头,放在最后防止被覆盖 } void draw_wall() { int i, j; setcolor(0xf0); gotoxy(0, 0); for (i = 0; i < g_height; i++) { gotoxy(0, i); for (j = 0; j < g_width; j++) { if (canvas[i][j] == '#') printf("#"); else printf(" "); } } } dword winapi render_thread(lpvoid lpparam) { psnake shea = (psnake)lpparam; psnake sheb = (run_snake_threads==2)?((psnake)lpparam+1):(shea); word color; char heada = shea->head_type; char headb = shea->head_type; char pr; char pr_score[50]; char show_time[30]; int snakes_counts = run_snake_threads; int i, j; if (snakes_counts == 1) { //单人模式 prs_colortoxy("player 1", g_width + 3, 6, 0xf0); prs_colortoxy("↑", g_width + 15, 5, 0xf0); prs_colortoxy("←↓→",g_width + 13, 6, 0xf0); } else { prs_colortoxy("player 1", g_width + 3, 6, 0xf0); prs_colortoxy("↑", g_width + 15, 5, 0xf0); prs_colortoxy("←↓→", g_width + 13, 6, 0xf0); prs_colortoxy("player 2", g_width + 3, 19, 0xf0); prs_colortoxy("w", g_width + 14, 18, 0xf0); prs_colortoxy("asd", g_width + 13, 19, 0xf0); } while (run_snake_threads != 0) //根据snake线程数结束循环 { for (i = 1; i < g_height-1; i++) { gotoxy(1, i); for (j = 1; j < g_width-1; j++) { switch (canvas[i][j]) { case '@': //蛇头 color = (heada == '@') ? shea->color : sheb->color; pr = '@'; break; case '*': //蛇身 color = (shea->body_type == '*') ? shea->color : sheb->color; pr = '*'; break; case 'u': //蛇头 color = (shea->head_type == 'u') ? shea->color : sheb->color; pr = 'u'; break; case 's': //蛇身 color = (shea->body_type == 's') ? shea->color : sheb->color; pr = 's'; break; case '$': //豆子 color = 0xf6; pr = '$'; break; case '&': //奖励 color = 0xa4; pr = '&'; break; case '0': color = 0xf0; pr = ' '; break; default: break; } setcolor(color); printf("%c", pr); } } sprintf(pr_score, "分数: %d", shea->score); prs_colortoxy(pr_score, g_width + 3, 8, 0xf0); if (snakes_counts == 2) { sprintf(pr_score, "分数: %d", sheb->score); prs_colortoxy(pr_score, g_width + 3, 21, 0xf0); } if (reward_time >= 0) { sprintf(show_time, "奖励剩余时间:%ds ", reward_time / 1000); prs_colortoxy(show_time, g_width + 5, g_height - 3, 0xf4); } else { prs_colortoxy(" ", g_width + 5, g_height - 3, 0xf4); } sleep(50); //显示频率 } } status createrand_bean() { int ran; //canvas的第n个点为奖励位置 int i,j,count,sum=0; char c = '$'; handle delrewarthread; for (i = 1; i < g_height - 1; i++) for (j = 1; j < g_width - 1; j++) if (canvas[i][j] == '0') sum++; if (sum == 0) return fail; if (bean_count % 5 == 0 && bean_count!=0) { ran = rand() % sum; count = 0; for (i = 1; i < g_height - 1; i++) for (j = 1; j < g_width - 1; j++) if (canvas[i][j] == '0') { if (count == ran) { reward_position.x = j; reward_position.y = i; canvas[i][j] = '&'; delrewarthread= createthread(null, 0, del_reward_thread, null, 0, null); closehandle(delrewarthread); } count++; } } bean_count++; ran = rand() % sum; count = 0; for (i = 1; i < g_height - 1; i++) for (j = 1; j < g_width - 1; j++) if (canvas[i][j] == '0') { if (count == ran) { canvas[i][j] = c; return success; } count++; } return fail; } void eat_node(psnake she, coord postion) { ps_node end = &she->head; ps_node s = (ps_node)malloc(sizeof(s_node)); while (end->next_node != null) end = end->next_node; init_snode(s,'n', postion.x, postion.y, null); end->next_node = s; canvas[postion.y][postion.x]=she->head_type; she->score++; if (she->score / 10 >= she->level) { she->level++; she->speed = (int)(she->speed * 0.75); } } void free_snake(psnake she) { ps_node body = she->head.next_node; ps_node temp; while (body!=null) { temp = body->next_node; free(body); body = temp; } } dword winapi run_snake_thread(lpvoid lpparam) { psnake pshe = (psnake)lpparam; char direct; coord next_node; //下一个蛇头位置 char v_canvas; boolean end = 0; while (!end) { direct = pshe->head.direct; if (keyboard_out[pshe->control - 1] != 'n') { //获取键盘输入的目的是,获取蛇要前往的下一个方向 switch (keyboard_out[pshe->control - 1]) //输入方向与运行方向相反 { case 'u': direct = (direct != 'd') ? 'u' : direct; break; case 'd': direct = (direct != 'u') ? 'd' : direct; break; case 'l': direct = (direct != 'r') ? 'l' : direct; break; case 'r': direct = (direct != 'l') ? 'r' : direct; break; default: break; } keyboard_out[pshe->control - 1] = 'n'; } next_node = pshe->head.postion; switch (direct) { case 'u': next_node.y = next_node.y - 1; break; case 'd': next_node.y = next_node.y + 1; break; case 'l': next_node.x = next_node.x - 1; break; case 'r': next_node.x = next_node.x + 1; break; default: break; } v_canvas = get_canvas_toxy(next_node); switch (v_canvas) { case '0': //表示该点安全,没有东西 snake_gonext(pshe, direct); break; case '$': eat_node(pshe, next_node); snake_gonext(pshe, direct); end = !createrand_bean(); break; case '&': //吃下道具,触发减速 eat_node(pshe, next_node); snake_gonext(pshe, direct); pshe->speed =(int) (pshe->speed * 1.25); break; default: end = 1; break; } sleep(pshe->speed); } free_snake(pshe); //这里只释放了蛇的身体其他信息仍保留 sleep(500); return 0; } dword winapi del_reward_thread(lpvoid lpparam) { reward_time = 10000; while (reward_time >=0) { if (canvas[reward_position.y][reward_position.x] == '&' && run_snake_threads>0) { sleep(1000); reward_time = reward_time - 1000; } else break; } canvas[reward_position.y][reward_position.x] = '0'; reward_time = -1000; return 0; } void init_canvas() { int i, j; for (i = 0; i < g_height; i++) for (j = 0; j < g_width; j++) canvas[i][j] = '0'; for (i = 0; i < g_height ; i++) { canvas[i][0] = '#'; canvas[i][g_width - 1] = '#'; } for (j = 0; j < g_width; j++) { canvas[0][j] = '#'; canvas[g_height - 1][j] = '#'; } }
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: 带壳的熟鸡蛋能放几天
下一篇: 举例详解Go语言中os库的常用函数用法