欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C语言实现控制台版贪吃蛇游戏

程序员文章站 2022-07-30 12:14:14
用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] = '#';
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

相关标签: C语言 贪吃蛇